diff --git a/app/[workspace]/project/[projectId]/design/page.tsx b/app/[workspace]/project/[projectId]/design/page.tsx
index e452f44..d2e4184 100644
--- a/app/[workspace]/project/[projectId]/design/page.tsx
+++ b/app/[workspace]/project/[projectId]/design/page.tsx
@@ -1,14 +1,7 @@
"use client";
import { use, useState, useEffect } from "react";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
import { toast } from "sonner";
-import { cn } from "@/lib/utils";
-import {
- Monitor, Globe, Settings, Smartphone, Mail, BookOpen,
- Lock, CheckCircle2, Loader2, ChevronRight, Pencil,
-} from "lucide-react";
import { SCAFFOLD_REGISTRY, THEME_REGISTRY, type ThemeColor } from "@/components/design-scaffolds";
// ---------------------------------------------------------------------------
@@ -19,7 +12,7 @@ interface Surface {
id: string;
name: string;
description: string;
- icon: React.ElementType;
+ icon: string;
themes: Theme[];
}
@@ -29,269 +22,77 @@ interface Theme {
description: string;
tags: string[];
url: string;
- preview: React.ReactNode;
}
-// Mini UI mockups — each styled to feel like the library
-const ShadcnPreview = () => (
-
-
-
-
-
- Save
- Cancel
-
-
-);
-
-const MantiinePreview = () => (
-
-
-
-
- {[1,2].map(i => (
-
- ))}
-
-
- Apply
-
-
-);
-
-const HeroUIPreview = () => (
-
-
-
-
- Get started →
-
-
-);
-
-const DaisyPreview = () => (
-
-
-
-
- Primary
- Success
-
-
-);
-
-const AcernityPreview = () => (
-
-);
-
-const TailwindPreview = () => (
-
-
className="flex…"
-
-
- Custom →
-
-
-);
-
-const TremorPreview = () => (
-
-
-
- {[60, 80, 45, 90, 70, 55].map((h, i) => (
-
- ))}
-
-
-);
-
-const NativewindPreview = () => (
-
-);
-
-const GluestackPreview = () => (
-
-);
-
-const ReactEmailPreview = () => (
-
-
-
-
-
-
- Open App →
-
-
-);
-
-const NextraPreview = () => (
-
-
- {['Getting started', 'Installation', 'API', 'Examples'].map(l => (
-
- ))}
-
-
-
-);
-
const ALL_SURFACES: Surface[] = [
{
id: "web-app",
name: "Web App",
- description: "The core product your users log into — dashboards, features, settings",
- icon: Monitor,
+ icon: "⬡",
+ description: "The core product users log into — dashboards, features, settings",
themes: [
- { id: "shadcn", name: "shadcn/ui", description: "Copy-paste components on Radix primitives. You own the code, fully customisable.", tags: ["Tailwind", "Radix", "Copy-paste"], url: "https://ui.shadcn.com", preview: },
- { id: "mantine", name: "Mantine", description: "100+ components with hooks, forms, charts. Best for data-heavy apps.", tags: ["React", "Charts", "Forms"], url: "https://mantine.dev", preview: },
- { id: "hero-ui", name: "HeroUI", description: "Beautiful, accessible components with smooth animations and dark mode.", tags: ["Tailwind", "Animations", "Accessible"], url: "https://heroui.com", preview: },
- { id: "tremor", name: "Tremor", description: "Dashboard components — charts, KPIs, tables — designed for analytics UIs.", tags: ["Charts", "Dashboard", "Analytics"], url: "https://tremor.so", preview: },
+ { id: "shadcn", name: "shadcn/ui", description: "Copy-paste components on Radix primitives. You own the code, fully customisable.", tags: ["Tailwind", "Radix", "Copy-paste"], url: "https://ui.shadcn.com" },
+ { id: "mantine", name: "Mantine", description: "100+ components with hooks, forms, charts. Best for data-heavy apps.", tags: ["React", "Charts", "Forms"], url: "https://mantine.dev" },
+ { id: "hero-ui", name: "HeroUI", description: "Beautiful, accessible components with smooth animations and dark mode.", tags: ["Tailwind", "Animations", "Accessible"], url: "https://heroui.com" },
+ { id: "tremor", name: "Tremor", description: "Dashboard components — charts, KPIs, tables — designed for analytics UIs.", tags: ["Charts", "Dashboard", "Analytics"], url: "https://tremor.so" },
],
},
{
id: "marketing",
name: "Marketing Site",
+ icon: "◎",
description: "Public-facing landing page, blog, pricing — brand expression and conversion",
- icon: Globe,
themes: [
- { id: "daisy-ui", name: "DaisyUI", description: "Tailwind plugin with 48 built-in themes. Fastest path to a beautiful site.", tags: ["Tailwind", "Themes", "Plugin"], url: "https://daisyui.com", preview: },
- { id: "hero-ui", name: "HeroUI", description: "Beautiful components with gradients and smooth animations.", tags: ["Tailwind", "Animations", "Modern"], url: "https://heroui.com", preview: },
- { id: "aceternity", name: "Aceternity UI", description: "Animated, visually striking components for premium landing pages.", tags: ["Animations", "Dark", "Premium"], url: "https://ui.aceternity.com", preview: },
- { id: "tailwind-only", name: "Tailwind only", description: "No component library — full creative control with pure Tailwind CSS.", tags: ["Custom", "Flexible", "Minimal"], url: "https://tailwindcss.com", preview: },
+ { id: "daisy-ui", name: "DaisyUI", description: "Tailwind plugin with 48 built-in themes. Fastest path to a beautiful site.", tags: ["Tailwind", "Themes", "Plugin"], url: "https://daisyui.com" },
+ { id: "hero-ui", name: "HeroUI", description: "Beautiful components with gradients and smooth animations.", tags: ["Tailwind", "Animations", "Modern"], url: "https://heroui.com" },
+ { id: "aceternity", name: "Aceternity UI", description: "Animated, visually striking components for premium landing pages.", tags: ["Animations", "Dark", "Premium"], url: "https://ui.aceternity.com" },
+ { id: "tailwind-only", name: "Tailwind only", description: "No component library — full creative control with pure Tailwind CSS.", tags: ["Custom", "Flexible", "Minimal"], url: "https://tailwindcss.com" },
],
},
{
id: "admin",
name: "Admin Panel",
+ icon: "◫",
description: "Internal tool for managing your business — users, support, billing, analytics",
- icon: Settings,
themes: [
- { id: "mantine", name: "Mantine", description: "The best choice for admin — comprehensive tables, forms, and data components.", tags: ["Tables", "Forms", "Charts"], url: "https://mantine.dev", preview: },
- { id: "shadcn", name: "shadcn/ui", description: "Clean, neutral components. Great if you want the admin to match the main app.", tags: ["Tailwind", "Consistent", "Clean"], url: "https://ui.shadcn.com", preview: },
- { id: "tremor", name: "Tremor", description: "Analytics-first — built for KPI dashboards, charts, and data tables.", tags: ["Analytics", "Charts", "KPIs"], url: "https://tremor.so", preview: },
+ { id: "mantine", name: "Mantine", description: "The best choice for admin — comprehensive tables, forms, and data components.", tags: ["Tables", "Forms", "Charts"], url: "https://mantine.dev" },
+ { id: "shadcn", name: "shadcn/ui", description: "Clean, neutral components. Great if you want the admin to match the main app.", tags: ["Tailwind", "Consistent", "Clean"], url: "https://ui.shadcn.com" },
+ { id: "tremor", name: "Tremor", description: "Analytics-first — built for KPI dashboards, charts, and data tables.", tags: ["Analytics", "Charts", "KPIs"], url: "https://tremor.so" },
],
},
{
id: "mobile",
name: "Mobile App",
+ icon: "▢",
description: "iOS and Android companion app — touch-first, native feel",
- icon: Smartphone,
themes: [
- { id: "nativewind", name: "NativeWind", description: "Use Tailwind CSS in React Native. Consistent style across web and mobile.", tags: ["Tailwind", "React Native", "Expo"], url: "https://nativewind.dev", preview: },
- { id: "gluestack", name: "Gluestack UI", description: "Universal components for React Native — accessible, well-tested, comprehensive.", tags: ["Universal", "Accessible", "Expo"], url: "https://gluestack.io", preview: },
+ { id: "nativewind", name: "NativeWind", description: "Use Tailwind CSS in React Native. Consistent style across web and mobile.", tags: ["Tailwind", "React Native", "Expo"], url: "https://nativewind.dev" },
+ { id: "gluestack", name: "Gluestack UI", description: "Universal components for React Native — accessible, well-tested, comprehensive.", tags: ["Universal", "Accessible", "Expo"], url: "https://gluestack.io" },
],
},
{
id: "email",
name: "Email",
+ icon: "✉",
description: "Transactional and marketing emails — welcome, billing, notifications",
- icon: Mail,
themes: [
- { id: "react-email", name: "React Email", description: "Build emails with React components. Works with any email provider.", tags: ["React", "Resend", "Cross-client"], url: "https://react.email", preview: },
+ { id: "react-email", name: "React Email", description: "Build emails with React components. Works with any email provider.", tags: ["React", "Resend", "Cross-client"], url: "https://react.email" },
],
},
{
id: "docs",
name: "Docs / Content",
+ icon: "☰",
description: "Documentation, knowledge base, or blog for your product",
- icon: BookOpen,
themes: [
- { id: "nextra", name: "Nextra", description: "Next.js-based docs site. Markdown-first, fast, with great search.", tags: ["Next.js", "Markdown", "Search"], url: "https://nextra.site", preview: },
- { id: "shadcn", name: "shadcn/ui + custom", description: "Build a fully custom docs site that matches your product exactly.", tags: ["Custom", "Tailwind", "Flexible"], url: "https://ui.shadcn.com", preview: },
+ { id: "nextra", name: "Nextra", description: "Next.js-based docs site. Markdown-first, fast, with great search.", tags: ["Next.js", "Markdown", "Search"], url: "https://nextra.site" },
+ { id: "shadcn", name: "shadcn/ui + custom", description: "Build a fully custom docs site that matches your product exactly.", tags: ["Custom", "Tailwind", "Flexible"], url: "https://ui.shadcn.com" },
],
},
];
// ---------------------------------------------------------------------------
-// Surface section — tab toggle + scaffold preview + lock in
+// Surface section
// ---------------------------------------------------------------------------
function SurfaceSection({
@@ -311,38 +112,54 @@ function SurfaceSection({
onUnlock: () => void;
saving: boolean;
}) {
- // 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;
- // Theme color variants for the active library (e.g. shadcn has 8 color themes)
const availableColorThemes: ThemeColor[] = previewId
? (THEME_REGISTRY[surface.id]?.[previewId] ?? [])
: [];
const [selectedColorTheme, setSelectedColorTheme] = useState(null);
const activeColorTheme = selectedColorTheme ?? availableColorThemes[0] ?? null;
- return (
-
+ const isLocked = !!lockedThemeId;
- {/* Scaffold preview — browser chrome frame */}
-
-
-
-
-
-
-
- {activeTheme ? `/${surface.id} — ${activeTheme.name}${activeColorTheme ? ` / ${activeColorTheme.label}` : ""}` : ""}
+ return (
+
+
+ {/* Browser chrome + scaffold */}
+
+ {/* Chrome bar */}
+
+ {["#d0ccc4", "#d0ccc4", "#d0ccc4"].map((c, i) => (
+
+ ))}
+
+
+ {activeTheme ? `/${surface.id} · ${activeTheme.name}${activeColorTheme ? ` · ${activeColorTheme.label}` : ""}` : ""}
-
+
+ {/* Scaffold */}
+
{ScaffoldComponent
?
: (
-
+
Select a library below to preview
)
@@ -350,89 +167,123 @@ function SurfaceSection({
- {/* Controls bar — all below the render */}
-
+ {/* Controls below render */}
+
- {/* Row 1: library tabs */}
-
+ {/* Library tabs */}
+
{surface.themes.map(theme => {
const isActive = theme.id === previewId;
- const isLocked = theme.id === lockedThemeId;
+ const isThisLocked = theme.id === lockedThemeId;
return (
);
})}
- {/* Row 2: color theme swatches (only if this library has color variants) */}
+ {/* Color swatches */}
{availableColorThemes.length > 0 && (
-
-
Theme
-
+
+
Theme
+
{availableColorThemes.map(ct => (
)}
- {/* Row 3: description + tags + docs + lock in */}
-
+ {/* Description + tags + docs + lock-in */}
+
{activeTheme && (
<>
-
{activeTheme.description}
-
+
+ {activeTheme.description}
+
+
{activeTheme.tags.map(t => (
- {t}
+
+ {t}
+
))}
-
+ (e.currentTarget.style.color = "#1a1a1a")}
+ onMouseLeave={e => (e.currentTarget.style.color = "#a09a90")}
+ >
Docs ↗
>
)}
- {lockedThemeId ? (
-
+ {isLocked ? (
+
) : (
-
+
)}
@@ -444,13 +295,7 @@ function SurfaceSection({
// Phase 1 — Surface picker
// ---------------------------------------------------------------------------
-function SurfacePicker({
- onConfirm,
- saving,
-}: {
- onConfirm: (ids: string[]) => void;
- saving: boolean;
-}) {
+function SurfacePicker({ onConfirm, saving }: { onConfirm: (ids: string[]) => void; saving: boolean }) {
const [selected, setSelected] = useState
>(new Set());
const toggle = (id: string) => {
@@ -462,60 +307,73 @@ function SurfacePicker({
};
return (
-
-
-
Design surfaces
-
- Which surfaces does your product need? Select all that apply — you can always add more later.
-
-
+
+
+ Design surfaces
+
+
+ Which surfaces does your product need? Select all that apply.
+
-
+
{ALL_SURFACES.map(surface => {
- const Icon = surface.icon;
const isSelected = selected.has(surface.id);
return (