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 (
-
- {/* Preview */}
-
- {theme.preview}
- {selected && locked && (
-
-
-
- )}
- {selected && !locked && (
-
-
-
- )}
-
-
- {/* Info */}
-
-
-
{theme.description}
-
- {theme.tags.map(t => (
- {t}
- ))}
-
-
-
- );
-}
-
-// ---------------------------------------------------------------------------
-// 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 (
+ !lockedThemeId && onSelect(theme.id)}
+ disabled={!!lockedThemeId && !isLocked}
+ className={cn(
+ "flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-all border",
+ isActive && isLocked
+ ? "bg-foreground text-background border-foreground"
+ : isActive
+ ? "bg-foreground text-background border-foreground"
+ : lockedThemeId
+ ? "opacity-30 border-transparent text-muted-foreground cursor-not-allowed"
+ : "border-border text-muted-foreground hover:border-foreground/40 hover:text-foreground"
)}
-
-
{surface.description}
-
-
+ >
+ {isLocked &&
}
+ {theme.name}
+
+ );
+ })}
- {/* Lock / Unlock controls */}
-
+ {/* Spacer + actions */}
+
+ {activeTheme && (
+
+ {activeTheme.name} docs ↗
+
+ )}
{lockedThemeId ? (
-
+
Change
@@ -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 */}
+
+
+ {NAV_ITEMS.map((item, i) => (
+
+ ))}
+
+ {/* Main */}
+
+
+
+
+ {["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=>{h} )}
+ {TABLE_ROWS.map(r=>{r.name} {r.email} {r.status} {r.date} )}
+
+
+
+
+
+ );
+}
+
+export function WebAppMantine() {
+ return (
+
+
+
+ {NAV_ITEMS.map((item, i) => (
+
+ ))}
+
+
+
+
Dashboard
+
+ Export
+ + New project
+
+
+
+
+ {["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=>{h} )}
+ {TABLE_ROWS.map(r=>{r.name} {r.email} {r.status} {r.date} )}
+
+
+
+
+
+ );
+}
+
+export function WebAppHeroUI() {
+ return (
+
+
+
+ {NAV_ITEMS.map((item, i) => (
+
+ ))}
+
+
+
+
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
+ View all
+
+
+ {["Name","Email","Status","Date"].map(h=>{h} )}
+ {TABLE_ROWS.map(r=>{r.name} {r.email} {r.status} {r.date} )}
+
+
+
+
+
+ );
+}
+
+export function WebAppTremor() {
+ return (
+
+
+
+ {NAV_ITEMS.map((item, i) => (
+
+ ))}
+
+
+
+ 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=>(
+
+ ))}
+
+
+
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 (
+
+
+
+
+ {["Features","Pricing","Docs","Blog"].map(i=>{i} )}
+
+
+ Login
+ Get started
+
+
+
+
+ ✦ New — v2.0 is here
+
+
Build faster, ship smarter
+
The all-in-one platform that helps teams build, launch, and scale their products.
+
+ Start for free
+ See demo →
+
+
+
+ {[{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 (
+
+
+
+
+ {["Features","Pricing","Docs","Blog"].map(i=>{i} )}
+
+
+ Login
+ Get started
+
+
+
+
+ 🚀 Just launched — v2.0
+
+
+ Build faster, ship smarter
+
+
The all-in-one platform for teams that move fast.
+
+ Start for free
+ Live demo →
+
+
+
+ {["#ff5f56","#ffbd2e","#27c93f"].map(c=>
)}
+
+
+
+ {["Revenue","Users","Growth","Churn"].map((m,i)=>
{m}
{["$12k","2.8k","+24%","2.1%"][i]}
)}
+
+
+
+
+
+ );
+}
+
+export function MarketingAceternity() {
+ return (
+
+
+
+
+ {["Features","Pricing","Docs"].map(i=>{i} )}
+
+ Get started
+
+
+
+
+ ✦ Open source · 12k GitHub stars
+
+
+ Build the future of the web
+
+
Beautifully crafted components built with Tailwind CSS and Framer Motion.
+
+ Get started →
+ View components
+
+
+ {["Animated","Accessible","Open source"].map((f,i)=>(
+
+
+
{f}
+
Built for production
+
+ ))}
+
+
+
+ );
+}
+
+export function MarketingTailwind() {
+ return (
+
+
+ acme
+
+ {["Features","Pricing","Blog"].map(i=>{i} )}
+
+
+ Log in
+ Sign up
+
+
+
+
+
Now in public beta
+
The platform built for scale
+
Everything your team needs to build, deploy, and monitor production applications.
+
+ Get started free
+ Documentation →
+
+
+ {["99.9% uptime SLA","10ms avg latency","SOC2 compliant","GDPR ready"].map(f=>(
+
+ ))}
+
+
+
+
+ );
+}
+
+// ---------------------------------------------------------------------------
+// ADMIN scaffolds
+// ---------------------------------------------------------------------------
+
+export function AdminMantine() { return ; }
+export function AdminShadcn() { return ; }
+export function AdminTremor() { return ; }
+
+// ---------------------------------------------------------------------------
+// MOBILE scaffolds
+// ---------------------------------------------------------------------------
+
+function MobileFrame({ children }: { children: React.ReactNode }) {
+ return (
+
+ );
+}
+
+export function MobileNativewind() {
+ return (
+
+
+
+
Good morning
+
Dashboard
+
+
+
+ {[{l:"Revenue",v:"$4.2k"},{l:"Users",v:"184"}].map(c=>(
+
+ ))}
+
+ {["Fix login bug","Update pricing","Review PR #42"].map((t,i)=>(
+
+ ))}
+
+
+ {["Home","Projects","Chat","Profile"].map((l,i)=>(
+
+ ))}
+
+
+
+ );
+}
+
+export function MobileGluestack() {
+ return (
+
+
+
+
+
+ {[{l:"Revenue",v:"$4.2k",c:"#1976d2"},{l:"Users",v:"184",c:"#7b1fa2"}].map(c=>(
+
+ ))}
+
+ {["Fix login bug","Update pricing","Review PR #42"].map((t,i)=>(
+
+ ))}
+
+
+ {["Home","Tasks","Chat","Profile"].map((l,i)=>(
+
+ ))}
+
+
+
+ );
+}
+
+// ---------------------------------------------------------------------------
+// EMAIL scaffolds
+// ---------------------------------------------------------------------------
+
+export function EmailReactEmail() {
+ return (
+
+
+
+
+
Welcome to Acme! 🎉
+
Hi Alice, thanks for signing up. Your account is ready and you can start building right away.
+
+ Get started →
+
+
+
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=>(
+
+ ))}
+
+
+
+ );
+}
+
+export function DocsShadcnCustom() {
+ return (
+
+
+
+ {[{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,
+ },
+};