diff --git a/app/[workspace]/project/[projectId]/design/page.tsx b/app/[workspace]/project/[projectId]/design/page.tsx index 72df47c..d984a1e 100644 --- a/app/[workspace]/project/[projectId]/design/page.tsx +++ b/app/[workspace]/project/[projectId]/design/page.tsx @@ -9,6 +9,7 @@ import { Monitor, Globe, Settings, Smartphone, Mail, BookOpen, Lock, CheckCircle2, Loader2, ChevronRight, Pencil, } from "lucide-react"; +import { SCAFFOLD_REGISTRY } from "@/components/design-scaffolds"; // --------------------------------------------------------------------------- // Surface definitions @@ -290,77 +291,7 @@ const ALL_SURFACES: Surface[] = [ ]; // --------------------------------------------------------------------------- -// Theme option card -// --------------------------------------------------------------------------- - -function ThemeCard({ - theme, - selected, - locked, - onSelect, -}: { - theme: Theme; - selected: boolean; - locked: boolean; - onSelect: () => void; -}) { - return ( - - ); -} - -// --------------------------------------------------------------------------- -// Surface section +// Surface section — tab toggle + scaffold preview + lock in // --------------------------------------------------------------------------- function SurfaceSection({ @@ -380,35 +311,56 @@ function SurfaceSection({ onUnlock: () => void; saving: boolean; }) { - const Icon = surface.icon; - const lockedTheme = surface.themes.find(t => t.id === lockedThemeId); + // Active preview tab — if locked show that, otherwise the selected/first + const previewId = lockedThemeId ?? selectedThemeId ?? surface.themes[0]?.id ?? null; + const activeTheme = surface.themes.find(t => t.id === previewId); + const ScaffoldComponent = previewId + ? SCAFFOLD_REGISTRY[surface.id]?.[previewId] + : null; return ( -
- {/* Surface header */} -
-
-
- -
-
-
-

{surface.name}

- {lockedTheme && ( - - - {lockedTheme.name} - +
+ {/* Tab bar */} +
+ {surface.themes.map(theme => { + const isActive = theme.id === previewId; + const isLocked = theme.id === lockedThemeId; + return ( +
-

{surface.description}

-
-
+ > + {isLocked && } + {theme.name} + + ); + })} - {/* Lock / Unlock controls */} -
+ {/* Spacer + actions */} +
+ {activeTheme && ( + + {activeTheme.name} docs ↗ + + )} {lockedThemeId ? ( - @@ -417,7 +369,7 @@ function SurfaceSection({ size="sm" onClick={onLock} disabled={!selectedThemeId || saving} - className="gap-1.5 text-xs" + className="gap-1.5 text-xs h-7" > {saving ? : } Lock in @@ -426,33 +378,41 @@ function SurfaceSection({
- {/* Theme cards — horizontal scroll */} - {!lockedThemeId && ( -
- {surface.themes.map(theme => ( - onSelect(theme.id)} - /> - ))} + {/* Scaffold preview — browser chrome frame */} +
+ {/* Browser chrome */} +
+
+
+
+
+ + {activeTheme ? `/${surface.id} — ${activeTheme.name}` : ""} + +
- )} + {/* Scaffold */} +
+ {ScaffoldComponent + ? + : ( +
+ Select a library above to preview +
+ ) + } +
+
- {/* Locked state — show only selected */} - {lockedThemeId && ( -
- {surface.themes.map(theme => ( - {}} - /> - ))} + {/* Theme description */} + {activeTheme && ( +
+

{activeTheme.description}

+
+ {activeTheme.tags.map(t => ( + {t} + ))} +
)}
diff --git a/components/design-scaffolds.tsx b/components/design-scaffolds.tsx new file mode 100644 index 0000000..7feaede --- /dev/null +++ b/components/design-scaffolds.tsx @@ -0,0 +1,653 @@ +"use client"; + +/** + * Design scaffolds — styled React mockups showing what each UI library + * looks like for a given surface. Used in the Design page preview area. + * + * Each scaffold is rendered at its natural size inside a scaled container, + * giving the user a realistic feel for the library's visual language. + */ + +// --------------------------------------------------------------------------- +// Shared mock data +// --------------------------------------------------------------------------- + +const NAV_ITEMS = ["Dashboard", "Projects", "Analytics", "Settings"]; +const TABLE_ROWS = [ + { name: "Alice Martin", email: "alice@co.com", status: "Active", date: "Jan 12" }, + { name: "Ben Walsh", email: "ben@co.com", status: "Pending", date: "Jan 14" }, + { name: "Clara Kim", email: "clara@co.com", status: "Active", date: "Jan 15" }, + { name: "David Osei", email: "david@co.com", status: "Inactive", date: "Jan 16" }, +]; + +// --------------------------------------------------------------------------- +// WEB APP scaffolds +// --------------------------------------------------------------------------- + +export function WebAppShadcn() { + return ( +
+ {/* Sidebar */} +
+
+
+ Acme Inc +
+ {NAV_ITEMS.map((item, i) => ( +
+
+ {item} +
+ ))} +
+ {/* Main */} +
+
+ Dashboard +
+
Export
+
New project
+
+
+
+
+ {["Total Revenue", "Active Users", "Conversions"].map((label, i) => ( +
+

{label}

+

{["$12,400", "2,841", "18.2%"][i]}

+

+{[12, 8, 3][i]}% from last month

+
+ ))} +
+
+
+ Recent activity +
Filter
+
+ + {["Name","Email","Status","Date"].map(h=>)} + {TABLE_ROWS.map(r=>)} +
{h}
{r.name}{r.email}{r.status}{r.date}
+
+
+
+
+ ); +} + +export function WebAppMantine() { + return ( +
+
+
+
+ Acme Inc +
+ {NAV_ITEMS.map((item, i) => ( +
+
+ {item} +
+ ))} +
+
+
+ Dashboard +
+ + +
+
+
+
+ {["Total Revenue","Active Users","Conversions"].map((label,i)=>( +
+

{label}

+

{["$12,400","2,841","18.2%"][i]}

+

↑ {[12,8,3][i]}% this month

+
+ ))} +
+
+
+ Users + +
+ + {["Name","Email","Status","Date"].map(h=>)} + {TABLE_ROWS.map(r=>)} +
{h}
{r.name}{r.email}{r.status}{r.date}
+
+
+
+
+ ); +} + +export function WebAppHeroUI() { + return ( +
+
+
+
+ Acme Inc +
+ {NAV_ITEMS.map((item, i) => ( +
+
+ {item} +
+ ))} +
+
+
+ Dashboard +
+ + +
+
+
+
+ {["Total Revenue","Active Users","Conversions"].map((label,i)=>( +
+

{label}

+

{["$12,400","2,841","18.2%"][i]}

+

+{[12,8,3][i]}% from last month

+
+ ))} +
+
+
+ Recent activity + +
+ + {["Name","Email","Status","Date"].map(h=>)} + {TABLE_ROWS.map(r=>)} +
{h}
{r.name}{r.email}{r.status}{r.date}
+
+
+
+
+ ); +} + +export function WebAppTremor() { + return ( +
+
+
+
+ Acme Inc +
+ {NAV_ITEMS.map((item, i) => ( +
+
+ {item} +
+ ))} +
+
+
+ Overview +
+
+
+ {[{l:"Revenue",v:"$12,400",c:"#2563eb",bg:"#dbeafe"},{l:"Users",v:"2,841",c:"#7c3aed",bg:"#ede9fe"},{l:"Conversion",v:"18.2%",c:"#059669",bg:"#d1fae5"}].map(item=>( +
+
+

{item.l}

+
+
+

{item.v}

+
+
+ ))} +
+
+

Revenue over time

+
+ {[40,65,55,80,70,90,75,85,60,95,80,100].map((h,i)=>( +
+ ))} +
+
+ {["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"].map(m=>{m})} +
+
+
+
+
+ ); +} + +// --------------------------------------------------------------------------- +// MARKETING scaffolds +// --------------------------------------------------------------------------- + +export function MarketingDaisy() { + return ( +
+ +
+
+ ✦ New — v2.0 is here +
+

Build faster,
ship smarter

+

The all-in-one platform that helps teams build, launch, and scale their products.

+
+ + +
+
+
+ {[{icon:"⚡",title:"Lightning fast",desc:"Deploy in seconds, not hours"},{icon:"🔒",title:"Secure by default",desc:"Enterprise-grade security built in"},{icon:"📈",title:"Scales with you",desc:"From zero to millions of users"}].map(f=>( +
+
{f.icon}
+

{f.title}

+

{f.desc}

+
+ ))} +
+
+ ); +} + +export function MarketingHeroUI() { + return ( +
+ +
+
+ 🚀 Just launched — v2.0 +
+

+ Build faster,
ship smarter +

+

The all-in-one platform for teams that move fast.

+
+ + +
+
+
+ {["#ff5f56","#ffbd2e","#27c93f"].map(c=>
)} +
+
+
+ {["Revenue","Users","Growth","Churn"].map((m,i)=>

{m}

{["$12k","2.8k","+24%","2.1%"][i]}

)} +
+
+
+
+
+ ); +} + +export function MarketingAceternity() { + return ( +
+ +
+
+
+ ✦ Open source · 12k GitHub stars +
+

+ Build the future
of the web +

+

Beautifully crafted components built with Tailwind CSS and Framer Motion.

+
+ + +
+
+ {["Animated","Accessible","Open source"].map((f,i)=>( +
+
+
+
+

{f}

+

Built for production

+
+ ))} +
+
+
+ ); +} + +export function MarketingTailwind() { + return ( +
+ +
+
+ Now in public beta +

The platform
built for scale

+

Everything your team needs to build, deploy, and monitor production applications.

+
+ + +
+
+ {["99.9% uptime SLA","10ms avg latency","SOC2 compliant","GDPR ready"].map(f=>( +
+
+
+
+ {f} +
+ ))} +
+
+
+
+ ); +} + +// --------------------------------------------------------------------------- +// ADMIN scaffolds +// --------------------------------------------------------------------------- + +export function AdminMantine() { return ; } +export function AdminShadcn() { return ; } +export function AdminTremor() { return ; } + +// --------------------------------------------------------------------------- +// MOBILE scaffolds +// --------------------------------------------------------------------------- + +function MobileFrame({ children }: { children: React.ReactNode }) { + return ( +
+
+
+
+
+ {children} +
+
+
+ ); +} + +export function MobileNativewind() { + return ( + +
+
+

Good morning

+

Dashboard

+
+
+
+ {[{l:"Revenue",v:"$4.2k"},{l:"Users",v:"184"}].map(c=>( +
+

{c.l}

+

{c.v}

+
+ ))} +
+ {["Fix login bug","Update pricing","Review PR #42"].map((t,i)=>( +
+
+

{t}

+
+ ))} +
+
+ {["Home","Projects","Chat","Profile"].map((l,i)=>( +
+
+ {l} +
+ ))} +
+
+ + ); +} + +export function MobileGluestack() { + return ( + +
+
+

Dashboard

+
+
+
+
+ {[{l:"Revenue",v:"$4.2k",c:"#1976d2"},{l:"Users",v:"184",c:"#7b1fa2"}].map(c=>( +
+

{c.l}

+

{c.v}

+
+ ))} +
+ {["Fix login bug","Update pricing","Review PR #42"].map((t,i)=>( +
+
+

{t}

+
+ ))} +
+
+ {["Home","Tasks","Chat","Profile"].map((l,i)=>( +
+
+ {l} +
+ ))} +
+
+ + ); +} + +// --------------------------------------------------------------------------- +// EMAIL scaffolds +// --------------------------------------------------------------------------- + +export function EmailReactEmail() { + return ( +
+
+
+
+
+ Acme +
+
+
+

Welcome to Acme! 🎉

+

Hi Alice, thanks for signing up. Your account is ready and you can start building right away.

+
+ +
+
+

Your account details

+ {["Plan: Starter","Workspace: alice-workspace","Status: Active"].map(d=>( +

{d}

+ ))} +
+

If you have any questions, reply to this email or visit our help center. We're here to help.

+
+
+

Acme Inc · 123 Main St · San Francisco CA · Unsubscribe

+
+
+
+ ); +} + +// --------------------------------------------------------------------------- +// DOCS scaffolds +// --------------------------------------------------------------------------- + +export function DocsNextra() { + return ( +
+
+
+

Getting Started

+ {["Introduction","Installation","Quick Start"].map((item,i)=>( +
{item}
+ ))} +
+
+

Components

+ {["Button","Card","Input","Modal","Table"].map(item=>( +
{item}
+ ))} +
+
+

API Reference

+ {["REST API","Webhooks"].map(item=>( +
{item}
+ ))} +
+
+
+
+
+ Docs/Getting Started/Introduction +
+

Introduction

+

Acme UI is a collection of re-usable components that you can copy and paste into your web apps. Built with Radix UI and Tailwind CSS.

+
+

$ npm install acme-ui

+
+

Key features

+ {["Accessible","Customisable","Open source","TypeScript ready"].map(f=>( +
+
{f} +
+ ))} +
+
+
+ ); +} + +export function DocsShadcnCustom() { + return ( +
+
+
+
+
+ Acme Docs +
+
+ {[{section:"Guides",items:["Introduction","Installation","Theming"]},{section:"Components",items:["Button","Input","Select","Dialog"]}].map(g=>( +
+

{g.section}

+ {g.items.map((item,i)=>( +
{item}
+ ))} +
+ ))} +
+
+

Introduction

+

A set of beautifully designed components built with Radix UI and Tailwind CSS.

+
+
+ bash +
+
+

npx shadcn@latest init

+
+
+
+ {["Button","Card","Input","Badge"].map(c=>( +
+

{c}

+

View component →

+
+ ))} +
+
+
+ ); +} + +// --------------------------------------------------------------------------- +// Registry — maps surface+theme to scaffold component +// --------------------------------------------------------------------------- + +export const SCAFFOLD_REGISTRY: Record> = { + "web-app": { + "shadcn": WebAppShadcn, + "mantine": WebAppMantine, + "hero-ui": WebAppHeroUI, + "tremor": WebAppTremor, + }, + "marketing": { + "daisy-ui": MarketingDaisy, + "hero-ui": MarketingHeroUI, + "aceternity": MarketingAceternity, + "tailwind-only": MarketingTailwind, + }, + "admin": { + "mantine": AdminMantine, + "shadcn": AdminShadcn, + "tremor": AdminTremor, + }, + "mobile": { + "nativewind": MobileNativewind, + "gluestack": MobileGluestack, + }, + "email": { + "react-email": EmailReactEmail, + }, + "docs": { + "nextra": DocsNextra, + "shadcn": DocsShadcnCustom, + }, +};