From 5080b4707ffbcbf20724f633d6a55b62ee46275f Mon Sep 17 00:00:00 2001 From: MananTank Date: Fri, 14 Nov 2025 21:08:47 +0000 Subject: [PATCH] [PRO-98] Update Project FTUX UI (#8418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR primarily focuses on updating the UI components by replacing the `NebulaIcon` with `BotIcon`, enhancing styling, and refactoring code for better readability and functionality across various components. ### Detailed summary - Replaced `NebulaIcon` with `BotIcon` in multiple components. - Improved styles for headings and paragraphs in `ClientIDSection` and `SecretKeySection`. - Updated layout properties in `ProjectWalletSection` and other components. - Added a new `CodeShowcase` component to display code examples. - Enhanced `ProjectFTUX` to accept a `projectWalletSection` prop. - Refactored several components for better structure and readability. - Adjusted margins and paddings for improved UI consistency. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` ## Summary by CodeRabbit * **New Features** * Multi-language code showcase with a language selector for integration examples * Configurable wallet layouts and ability to inject a wallet area into onboarding/FTUX * **UI/UX Improvements** * Refined spacing, typography, and responsive layouts across project pages and sidebar * Added popular framework/product brand icons; replaced several AI/sidebar icons with a unified Bot icon * Simplified sidebar footer links and adjusted paddings and avatar sizes * **Chores** * Updated story examples to include new layout args --- .../blocks/full-width-sidebar-layout.tsx | 2 +- .../project-page/project-page-header.tsx | 5 +- .../blocks/project-page/project-page.tsx | 14 +- apps/dashboard/src/@/icons/NebulaIcon.tsx | 24 -- .../src/@/icons/brand-icons/ExpoIcon.tsx | 21 ++ .../src/@/icons/brand-icons/NextjsIcon.tsx | 59 +++ .../src/@/icons/brand-icons/NodeJSIcon.tsx | 20 + .../src/@/icons/brand-icons/ViteIcon.tsx | 23 ++ .../(chain)/components/server/products.ts | 4 +- .../analytics/chart/AiTokenUsageChartCard.tsx | 4 +- .../(sidebar)/ai/analytics/page.tsx | 4 +- .../(sidebar)/ai/components/ChatSidebar.tsx | 4 +- .../(sidebar)/ai/components/Chats.tsx | 7 +- .../components/EmptyStateChatPageContent.tsx | 5 +- .../ProjectFTUX/ClientIDSection.tsx | 4 +- .../components/ProjectFTUX/CodeSelector.tsx | 45 +++ .../ProjectFTUX/ProjectFTUX.stories.tsx | 1 + .../components/ProjectFTUX/ProjectFTUX.tsx | 349 +++++++++++------- .../ProjectFTUX/SecretKeySection.tsx | 8 +- .../components/ProjectSidebarLayout.tsx | 23 +- .../project-wallet/project-wallet-details.tsx | 4 +- .../project-wallet/project-wallet.stories.tsx | 6 + .../project-wallet/project-wallet.tsx | 41 +- .../[project_slug]/(sidebar)/page.tsx | 54 ++- 24 files changed, 503 insertions(+), 228 deletions(-) delete mode 100644 apps/dashboard/src/@/icons/NebulaIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx create mode 100644 apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx diff --git a/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx b/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx index 892d6ba1671..26ce5518be2 100644 --- a/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx +++ b/apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx @@ -67,7 +67,7 @@ export function FullWidthSidebarLayout(props: { )} > {/* left - sidebar */} - + diff --git a/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx b/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx index 6a027f917f4..f7877cfbca3 100644 --- a/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx +++ b/apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx @@ -66,13 +66,16 @@ export type ProjectPageHeaderProps = { href: string; }; + className?: string; // TODO: add task card component task?: never; }; export function ProjectPageHeader(props: ProjectPageHeaderProps) { return ( -
+
{/* top row */}
{/* left - icon */} diff --git a/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx b/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx index f72bf644ed0..fa2f04083f0 100644 --- a/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx +++ b/apps/dashboard/src/@/components/blocks/project-page/project-page.tsx @@ -13,13 +13,19 @@ type ProjectPageProps = { header: ProjectPageHeaderProps; footer?: ProjectPageFooterProps; tabs?: TabPathLink[]; + containerClassName?: string; }; export function ProjectPage(props: React.PropsWithChildren) { return (
- + 0 ? "pt-8 pb-6" : "py-8", + )} + /> {props.tabs && ( ) { )}
-
{props.children}
+
+ {props.children} +
{props.footer && (
diff --git a/apps/dashboard/src/@/icons/NebulaIcon.tsx b/apps/dashboard/src/@/icons/NebulaIcon.tsx deleted file mode 100644 index 1a59d089f01..00000000000 --- a/apps/dashboard/src/@/icons/NebulaIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -export function NebulaIcon(props: { className?: string }) { - return ( - - - - - ); -} diff --git a/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx new file mode 100644 index 00000000000..3b45bc2cab5 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/ExpoIcon.tsx @@ -0,0 +1,21 @@ +export function ExpoIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx new file mode 100644 index 00000000000..0fd37729730 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/NextjsIcon.tsx @@ -0,0 +1,59 @@ +export function NextjsIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx new file mode 100644 index 00000000000..0f430bee249 --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/NodeJSIcon.tsx @@ -0,0 +1,20 @@ +export function NodeJSIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx b/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx new file mode 100644 index 00000000000..d08367f5d9f --- /dev/null +++ b/apps/dashboard/src/@/icons/brand-icons/ViteIcon.tsx @@ -0,0 +1,23 @@ +export function ViteIcon(props: { className?: string }) { + return ( + + ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts index b425f8219d1..fcdb457611c 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts @@ -1,7 +1,7 @@ +import { BotIcon } from "lucide-react"; import { ConnectSDKIcon } from "@/icons/ConnectSDKIcon"; import { ContractIcon } from "@/icons/ContractIcon"; import { EngineIcon } from "@/icons/EngineIcon"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { PayIcon } from "@/icons/PayIcon"; import { RPCIcon } from "@/icons/RPCIcon"; import { SmartAccountIcon } from "@/icons/SmartAccountIcon"; @@ -52,7 +52,7 @@ export const products = [ }, { description: "The most powerful AI for interacting with the blockchain", - icon: NebulaIcon, + icon: BotIcon, id: "nebula", link: "https://thirdweb.com/ai", name: "thirdweb AI", diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx index b38e0505a6c..c5ca8895970 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/chart/AiTokenUsageChartCard.tsx @@ -1,11 +1,11 @@ "use client"; import { format } from "date-fns"; +import { BotIcon } from "lucide-react"; import { useMemo } from "react"; import { ThirdwebBarChart } from "@/components/blocks/charts/bar-chart"; import { DocLink } from "@/components/blocks/DocLink"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import type { ChartConfig } from "@/components/ui/chart"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import type { AIUsageStats } from "@/types/analytics"; type ChartData = Record & { @@ -106,7 +106,7 @@ function AiTokenUsageEmptyChartState() {
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx index 2f818455eec..661426788dd 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/analytics/page.tsx @@ -1,3 +1,4 @@ +import { BotIcon } from "lucide-react"; import { redirect } from "next/navigation"; import { ResponsiveSearchParamsProvider } from "responsive-rsc"; import { getAuthToken } from "@/api/auth-token"; @@ -6,7 +7,6 @@ import type { DurationId } from "@/components/analytics/date-range-selector"; import { ResponsiveTimeFilters } from "@/components/analytics/responsive-time-filters"; import { ProjectPage } from "@/components/blocks/project-page/project-page"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { getFiltersFromSearchParams } from "@/lib/time"; import { loginRedirect } from "@/utils/redirects"; import { AiAnalytics } from "./chart"; @@ -58,7 +58,7 @@ export default async function Page(props: {
- + thirdweb AI
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx index f5c41ed3440..7dc23ca4b67 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/Chats.tsx @@ -1,10 +1,9 @@ import { MarkdownRenderer } from "@workspace/ui/components/markdown-renderer"; import { ScrollShadow } from "@workspace/ui/components/scroll-shadow"; -import { AlertCircleIcon } from "lucide-react"; +import { AlertCircleIcon, BotIcon } from "lucide-react"; import { useEffect, useRef } from "react"; import type { ThirdwebClient } from "thirdweb"; import type { Project } from "@/api/project/projects"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { cn } from "@/lib/utils"; import type { NebulaSwapData, @@ -238,11 +237,11 @@ function RenderMessage(props: { )} > {message.type === "presence" && ( - + )} {message.type === "assistant" && ( - + )} {message.type === "error" && ( diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx index b2614f74ee9..ad0c25a9578 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/components/EmptyStateChatPageContent.tsx @@ -1,9 +1,8 @@ "use client"; -import { ArrowUpRightIcon, InfoIcon } from "lucide-react"; +import { ArrowUpRightIcon, BotIcon, InfoIcon } from "lucide-react"; import type { ThirdwebClient } from "thirdweb"; import { Button } from "@/components/ui/button"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { cn } from "@/lib/utils"; import type { NebulaContext, NebulaUserMessage } from "../api/types"; import { examplePrompts } from "../data/examplePrompts"; @@ -33,7 +32,7 @@ export function EmptyStateChatPageContent(props: {
- +
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx index 0dd8e8119f4..d9f9d0bc1f3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ClientIDSection.tsx @@ -3,8 +3,8 @@ import { CopyTextButton } from "@/components/ui/CopyTextButton"; export function ClientIDSection(props: { clientId: string }) { return (
-

Client ID

-

+

Client ID

+

Identifies your application

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx new file mode 100644 index 00000000000..4c6d4fd6e8d --- /dev/null +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/CodeSelector.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useState } from "react"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +export function CodeShowcase(props: { + title: string; + tabs: Array<{ + label: string; + code: React.ReactNode; + }>; +}) { + const [selectedTab, setSelectedTab] = useState(props.tabs[0]?.label || ""); + + return ( +
+
+

{props.title}

+ +
+ + {props.tabs.find((tab) => tab.label === selectedTab)?.code} +
+ ); +} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx index e48d6d82575..190484c7c55 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.stories.tsx @@ -24,6 +24,7 @@ type Story = StoryObj; export const Default: Story = { args: { + projectWalletSection: undefined, project: { ...projectStub("foo", "bar"), secretKeys: [ diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx index b1f51f3857f..5ddec808e09 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx @@ -1,26 +1,40 @@ +import { Button } from "@workspace/ui/components/button"; +import { CodeServer } from "@workspace/ui/components/code/code.server"; import { - ArrowLeftRightIcon, + ArrowUpRightIcon, + BotIcon, ChevronRightIcon, - ExternalLinkIcon, + CoinsIcon, + DoorOpenIcon, } from "lucide-react"; import Link from "next/link"; import type { Project } from "@/api/project/projects"; -import { CodeServer } from "@/components/ui/code/code.server"; +import { BridgeIcon } from "@/icons/BridgeIcon"; import { DotNetIcon } from "@/icons/brand-icons/DotNetIcon"; -import { GithubIcon } from "@/icons/brand-icons/GithubIcon"; +import { ExpoIcon } from "@/icons/brand-icons/ExpoIcon"; +import { NextjsIcon } from "@/icons/brand-icons/NextjsIcon"; +import { NodeJSIcon } from "@/icons/brand-icons/NodeJSIcon"; import { ReactIcon } from "@/icons/brand-icons/ReactIcon"; import { TypeScriptIcon } from "@/icons/brand-icons/TypeScriptIcon"; import { UnityIcon } from "@/icons/brand-icons/UnityIcon"; import { UnrealIcon } from "@/icons/brand-icons/UnrealIcon"; -import { ContractIcon } from "@/icons/ContractIcon"; +import { ViteIcon } from "@/icons/brand-icons/ViteIcon"; import { PayIcon } from "@/icons/PayIcon"; +import { WalletProductIcon } from "@/icons/WalletProductIcon"; import { ClientIDSection } from "./ClientIDSection"; +import { CodeShowcase } from "./CodeSelector"; import { SecretKeySection } from "./SecretKeySection"; -export function ProjectFTUX(props: { project: Project; teamSlug: string }) { +export function ProjectFTUX(props: { + project: Project; + teamSlug: string; + projectWalletSection: React.ReactNode; +}) { return ( -
+
+ {props.projectWalletSection} + -

- Integrate API key -

+
+
+

API Keys

+

+ Your API key is used to authenticate and integrate your application. +

+ +
-
+
{secretKeyMasked && ( @@ -53,23 +84,74 @@ function IntegrateAPIKeySection({ project }: { project: Project }) { /> )}
+
+
+ ); +} -
-
-

- Run this command in your terminal to send a test transaction using - your Project Wallet. -

- -
+function GetStartedSection({ project }: { project: Project }) { + return ( +
+
+

+ Get Started +

+

+ Send a test transaction using your project wallet +

+ +
+ + + ), + }, + { + label: "JavaScript", + code: ( + + ), + }, + { + label: "Python", + code: ( + + ), + }, + ]} + />
); } + const curlCodeExample = (project: Project): string => `\ curl https://api.thirdweb.com/v1/transactions \\ --request POST \\ @@ -87,6 +169,40 @@ curl https://api.thirdweb.com/v1/transactions \\ }' `; +const fetchJSCodeExample = (project: Project): string => `\ +fetch("https://api.thirdweb.com/v1/transactions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-key": "${project.secretKeys[0]?.masked ?? ""}", + }, + body: JSON.stringify({ + chainId: 421614, + transactions: [ + { data: "0x", to: "vitalik.eth", value: "0" }, + ], + }), +}); +`; + +const pythonCodeExample = (project: Project): string => `\ +import requests + +url = "https://api.thirdweb.com/v1/transactions" +headers = { + "Content-Type": "application/json", + "x-secret-key": "${project.secretKeys[0]?.masked ?? ""}", +} +payload = { + "chainId": 421614, + "transactions": [ + { "data": "0x", "to": "vitalik.eth", "value": "0" }, + ], +} +response = requests.post(url, headers=headers, json=payload) +result = response.json() +`; + // products section ------------------------------------------------------------ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { @@ -97,49 +213,60 @@ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { icon: React.FC<{ className?: string }>; }> = [ { - description: - "Scale your application with a backend server to read, write, and deploy contracts at production-grade.", - href: `/team/${props.teamSlug}/${props.projectSlug}/transactions`, - icon: ArrowLeftRightIcon, - title: "Transactions", + icon: WalletProductIcon, + title: "Wallets", + description: "Wallets to read, write and transact", + href: `/team/${props.teamSlug}/${props.projectSlug}/wallets/user-wallets`, }, { - description: - "Deploy your own contracts or leverage existing solutions for onchain implementation", - href: `/team/${props.teamSlug}/${props.projectSlug}/contracts`, - icon: ContractIcon, - title: "Contracts", + icon: BridgeIcon, + title: "Bridge", + description: "Swap and bridge tokens", + href: `/team/${props.teamSlug}/${props.projectSlug}/bridge`, }, { - description: - "Bridge, swap, and purchase cryptocurrencies with any fiat options or tokens via cross-chain routing", - href: `/team/${props.teamSlug}/${props.projectSlug}/payments`, icon: PayIcon, - title: "Payments", + title: "x402", + description: "Native internet payments", + href: `/team/${props.teamSlug}/${props.projectSlug}/x402`, + }, + { + icon: DoorOpenIcon, + title: "Gateway", + description: "Blockchain connectivity and data access", + href: `/team/${props.teamSlug}/${props.projectSlug}/gateway/rpc`, + }, + { + icon: CoinsIcon, + title: "Tokens", + description: "Launch tokens and markets", + href: `/team/${props.teamSlug}/${props.projectSlug}/tokens`, + }, + { + icon: BotIcon, + title: "AI", + description: "Read and write onchain via AI agents", + href: `/team/${props.teamSlug}/${props.projectSlug}/ai`, }, ]; return (
-

- Complete your full-stack application -

-

- Tools to build frontend, backend, and onchain with built-in - infrastructure and analytics. +

Products

+

+ Everything you need to build full-stack applications, games, and agents.

- {/* Feature Cards */} -
+
{products.map((product) => ( - ))}
@@ -147,72 +274,51 @@ function ProductsSection(props: { teamSlug: string; projectSlug: string }) { ); } -function ProductCard(props: { - title: string; - description: string; - href: string; - icon: React.FC<{ className?: string }>; -}) { - return ( -
-
- -
-

- - {props.title} - -

-

{props.description}

-
- ); -} - // sdk section ------------------------------------------------------------ -type SDKCardProps = { +type IconCardProps = { name: string; + description: string | undefined; href: string; icon: React.FC<{ className?: string }>; - trackingLabel: string; }; -const sdks: SDKCardProps[] = [ +const sdks: IconCardProps[] = [ { href: "https://portal.thirdweb.com/sdk/typescript", icon: TypeScriptIcon, name: "TypeScript", - trackingLabel: "typescript", + description: undefined, }, { href: "https://portal.thirdweb.com/react/v5", icon: ReactIcon, name: "React", - trackingLabel: "react", + description: undefined, }, { href: "https://portal.thirdweb.com/react-native/v5", icon: ReactIcon, name: "React Native", - trackingLabel: "react_native", + description: undefined, }, { href: "https://portal.thirdweb.com/unity/v5", icon: UnityIcon, name: "Unity", - trackingLabel: "unity", + description: undefined, }, { href: "https://portal.thirdweb.com/unreal-engine", icon: UnrealIcon, name: "Unreal Engine", - trackingLabel: "unreal", + description: undefined, }, { href: "https://portal.thirdweb.com/dotnet", icon: DotNetIcon, name: ".NET", - trackingLabel: "dotnet", + description: undefined, }, ]; @@ -220,14 +326,14 @@ function SDKSection() { return (

Client SDKs

-
+
{sdks.map((sdk) => ( - ))}
@@ -235,10 +341,10 @@ function SDKSection() { ); } -function SDKCard(props: SDKCardProps) { +function IconCard(props: IconCardProps) { return ( -
-
+
+
@@ -246,16 +352,14 @@ function SDKCard(props: SDKCardProps) { {props.name}

-

- View Docs - -

+ {props.description && ( +

{props.description}

+ )}
); @@ -263,42 +367,47 @@ function SDKCard(props: SDKCardProps) { // starter kits section ------------------------------------------------------------ -type StartedKitCardProps = { - name: string; - href: string; - trackingLabel: string; -}; - -const startedKits: StartedKitCardProps[] = [ +const startedKits: IconCardProps[] = [ { href: "https://github.com/thirdweb-example/next-starter", name: "Next Starter", - trackingLabel: "next_starter", + icon: NextjsIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/vite-starter", name: "Vite Starter", - trackingLabel: "vite_starter", + icon: ViteIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/expo-starter", name: "Expo Starter", - trackingLabel: "expo_starter", + icon: ExpoIcon, + description: undefined, }, { href: "https://github.com/thirdweb-example/node-starter", name: "Node Starter", - trackingLabel: "node_starter", + icon: NodeJSIcon, + description: undefined, }, ]; function StarterKitsSection() { return (
-
-

Starter Kits

+
+
+

+ Starters +

+

+ Kickstart your development process with ready-to-ship repositories. +

+
-
+
{startedKits.map((kit) => ( - ))}
); } - -function StarterKitCard(props: StartedKitCardProps) { - return ( -
-
- -
- -
- - {props.name} - -

- View Repo - -

-
-
- ); -} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx index 3a6f24c9294..f7b6e4df883 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/SecretKeySection.tsx @@ -13,15 +13,15 @@ export function SecretKeySection(props: { return (
-

Secret Key

-

+

Secret Key

+

Identifies and authenticates your application from a backend.
{" "} This is not the full secret key, Refer to your saved secret key at the time of creation for the full secret key.

-
-
+
+
{secretKeyMasked}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx index 009229c4ac2..bd40487cb3e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx @@ -1,11 +1,10 @@ "use client"; import { Badge } from "@workspace/ui/components/badge"; import { - BookTextIcon, - BoxIcon, + BotIcon, DatabaseIcon, + DoorOpenIcon, HomeIcon, - RssIcon, Settings2Icon, WebhookIcon, } from "lucide-react"; @@ -15,7 +14,6 @@ import { } from "@/components/blocks/full-width-sidebar-layout"; import { BridgeIcon } from "@/icons/BridgeIcon"; import { ContractIcon } from "@/icons/ContractIcon"; -import { NebulaIcon } from "@/icons/NebulaIcon"; import { PayIcon } from "@/icons/PayIcon"; import { TokenIcon } from "@/icons/TokenIcon"; import { WalletProductIcon } from "@/icons/WalletProductIcon"; @@ -81,12 +79,12 @@ export function ProjectSidebarLayout(props: { }, { href: `${props.layoutPath}/ai`, - icon: NebulaIcon, + icon: BotIcon, label: "AI", }, { subMenu: { - icon: RssIcon, + icon: DoorOpenIcon, label: "Gateway", }, links: [ @@ -129,19 +127,6 @@ export function ProjectSidebarLayout(props: { icon: Settings2Icon, label: "Project Settings", }, - { - separator: true, - }, - { - href: "https://portal.thirdweb.com", - icon: BookTextIcon, - label: "Documentation", - }, - { - href: "https://playground.thirdweb.com/wallets/sign-in/button", - icon: BoxIcon, - label: "Playground", - }, ] satisfies ShadcnSidebarLink[]; return ( diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx index 819d0c652f4..38f5d8da1c1 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx @@ -177,7 +177,7 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) { -
+

Wallet Address

-
+

Balance

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx index 750c51f3328..4d64cb51ca8 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx @@ -49,6 +49,7 @@ const projectWallet2: ProjectWalletSummary = { export const NoProjectWalletSetNoManagedAccessToken: Story = { args: { + layout: "column", project: projectWithoutManagedAccessToken, client: storybookThirdwebClient, teamSlug: "bar", @@ -62,6 +63,7 @@ export const NoProjectWalletSetNoManagedAccessToken: Story = { export const NoProjectWalletSetWithManagedAccessToken: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, client: storybookThirdwebClient, teamSlug: "bar", @@ -75,6 +77,7 @@ export const NoProjectWalletSetWithManagedAccessToken: Story = { export const NoProjectWalletSetWithManagedAccessTokenAndServerWallets: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -88,6 +91,7 @@ export const NoProjectWalletSetWithManagedAccessTokenAndServerWallets: Story = { export const NoProjectWalletSetLoading: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -101,6 +105,7 @@ export const NoProjectWalletSetLoading: Story = { export const ProjectWalletSetMultipleServerWallets: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", client: storybookThirdwebClient, @@ -114,6 +119,7 @@ export const ProjectWalletSetMultipleServerWallets: Story = { export const ProjectWalletSetSingleServerWallet: Story = { args: { + layout: "column", project: projectWithManagedAccessToken, teamSlug: "bar", projectWallet: projectWallet1, diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx index e2a44ce2208..8175644e889 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx @@ -2,7 +2,8 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { UnderlineLink } from "@workspace/ui/components/UnderlineLink"; -import { ChevronDownIcon, XIcon } from "lucide-react"; +import { ArrowUpRightIcon, ChevronDownIcon, XIcon } from "lucide-react"; +import Link from "next/link"; import { useMemo, useState } from "react"; import { toast } from "sonner"; import type { ThirdwebClient } from "thirdweb"; @@ -29,6 +30,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { useDashboardRouter } from "@/lib/DashboardRouter"; import type { ProjectWalletSummary } from "@/lib/server/project-wallet"; +import { cn } from "@/lib/utils"; import { updateDefaultProjectWallet } from "../../transactions/lib/vault.client"; import { CreateServerWallet } from "../../transactions/server-wallets/components/create-server-wallet.client"; import { ProjectWalletDetailsSection } from "./project-wallet-details"; @@ -131,11 +133,11 @@ function CreateProjectWalletSection(props: { Boolean(managementAccessToken) && serverWallets.length > 0; return ( -
+
- +
-

+

No Project Wallet set

@@ -276,10 +278,17 @@ export function ProjectWalletSectionUI(props: { projectWallet: ProjectWalletSummary | undefined; getProjectServerWallets: GetProjectServerWallets; client: ThirdwebClient; + layout: "row" | "column"; }) { return ( -

-
+
+

Project Wallet

@@ -292,6 +301,24 @@ export function ProjectWalletSectionUI(props: { thirdweb API

+ {props.layout === "row" && ( +
+ +
+ )}
{props.projectWallet ? ( @@ -318,6 +345,7 @@ export function ProjectWalletSection(props: { teamSlug: string; projectWallet: ProjectWalletSummary | undefined; client: ThirdwebClient; + layout: "row" | "column"; }) { return ( ); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx index 3226572d485..ff2b14933a3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx @@ -119,7 +119,7 @@ export default async function ProjectOverviewPage(props: PageProps) { isProjectIcon: true, icon: () => ( @@ -130,30 +130,44 @@ export default async function ProjectOverviewPage(props: PageProps) { actions: null, }} > - - -
- {isActive ? ( -
- - + +
+ + +
) : ( - +
+ + } + /> +
)}