refactor(design): modularize scaffolds into per-surface files + unique admin

- Deleted monolithic design-scaffolds.tsx (1154 lines, 72KB)
- New folder: components/design-scaffolds/
  - types.ts       — ThemeColor interface + all theme palettes
  - web-app.tsx    — SaaS app: Dashboard / Users / Settings with AppShell
  - marketing.tsx  — Landing page: hero, features, pricing, CTA
  - admin.tsx      — NEW unique admin: System health (servers/CPU/mem/errors),
                     Moderation (user table + audit log + ban/impersonate),
                     Config (API keys, feature flags, webhooks)
  - mobile.tsx     — Phone frame previews: NativeWind / Gluestack
  - email.tsx      — React Email welcome template preview
  - docs.tsx       — Nextra + shadcn docs previews
  - index.ts       — SCAFFOLD_REGISTRY + THEME_REGISTRY (only import needed)
- Adding a new surface = create one file + add 2 lines to index.ts

Made-with: Cursor
This commit is contained in:
2026-03-05 19:54:38 -08:00
parent d30af447da
commit 57c283796f
9 changed files with 1315 additions and 1153 deletions

View File

@@ -0,0 +1,93 @@
"use client";
import { ThemeColor } from "./types";
function MobileFrame({ children }: { children: React.ReactNode }) {
return (
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", background: "#f4f4f5" }}>
<div style={{ position: "relative", width: 200, height: 380 }}>
<div style={{ position: "absolute", inset: 0, borderRadius: 36, background: "#1a1a1a", boxShadow: "0 20px 60px rgba(0,0,0,0.3)" }} />
<div style={{ position: "absolute", top: 10, left: "50%", transform: "translateX(-50%)", width: 60, height: 14, borderRadius: 20, background: "#000", zIndex: 10 }} />
<div style={{ position: "absolute", inset: 8, borderRadius: 30, overflow: "hidden", background: "#fff" }}>
{children}
</div>
</div>
</div>
);
}
export function MobileNativewind({ themeColor }: { themeColor?: ThemeColor }) {
return (
<MobileFrame>
<div style={{ height: "100%", display: "flex", flexDirection: "column", background: "#fff", fontFamily: "system-ui, sans-serif", fontSize: 11 }}>
<div style={{ paddingTop: 22, paddingBottom: 10, paddingLeft: 12, paddingRight: 12, background: "#18181b" }}>
<p style={{ fontSize: 8, color: "#71717a", marginBottom: 2 }}>Good morning</p>
<p style={{ fontSize: 13, fontWeight: 700, color: "#fff" }}>Dashboard</p>
</div>
<div style={{ flex: 1, overflow: "auto", padding: 10, background: "#fafafa", display: "flex", flexDirection: "column", gap: 8 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
{[["Revenue", "$4.2k"], ["Users", "184"]].map(([l, v]) => (
<div key={l} style={{ background: "#fff", borderRadius: 10, padding: "8px 10px", border: "1px solid #e4e4e7" }}>
<p style={{ fontSize: 7, color: "#a1a1aa", marginBottom: 2 }}>{l}</p>
<p style={{ fontSize: 12, fontWeight: 700, color: "#09090b" }}>{v}</p>
</div>
))}
</div>
{["Fix login bug", "Update pricing", "Review PR #42"].map((t, i) => (
<div key={t} style={{ background: "#fff", borderRadius: 10, padding: "8px 10px", display: "flex", alignItems: "center", gap: 8, border: "1px solid #e4e4e7" }}>
<div style={{ width: 14, height: 14, borderRadius: 3, border: "1px solid #d4d4d8", flexShrink: 0, background: i === 0 ? "#18181b" : "none", borderColor: i === 0 ? "#18181b" : "#d4d4d8", display: "flex", alignItems: "center", justifyContent: "center" }}>
{i === 0 && <span style={{ color: "#fff", fontSize: 8 }}></span>}
</div>
<p style={{ fontSize: 9, color: i === 0 ? "#a1a1aa" : "#09090b", textDecoration: i === 0 ? "line-through" : "none" }}>{t}</p>
</div>
))}
</div>
<div style={{ display: "flex", borderTop: "1px solid #f4f4f5", padding: "6px 0 10px", background: "#fff" }}>
{["Home", "Projects", "Chat", "Profile"].map((l, i) => (
<div key={l} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 2 }}>
<div style={{ width: 14, height: 14, borderRadius: 3, background: i === 0 ? "#18181b" : "#e4e4e7" }} />
<span style={{ fontSize: 7, color: i === 0 ? "#18181b" : "#a1a1aa" }}>{l}</span>
</div>
))}
</div>
</div>
</MobileFrame>
);
}
export function MobileGluestack({ themeColor }: { themeColor?: ThemeColor }) {
return (
<MobileFrame>
<div style={{ height: "100%", display: "flex", flexDirection: "column", fontFamily: "system-ui, sans-serif", fontSize: 11 }}>
<div style={{ paddingTop: 22, paddingBottom: 10, paddingLeft: 12, paddingRight: 12, background: "#1976d2", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<p style={{ fontSize: 13, fontWeight: 700, color: "#fff" }}>Dashboard</p>
<div style={{ width: 20, height: 20, borderRadius: "50%", background: "rgba(255,255,255,0.2)" }} />
</div>
<div style={{ flex: 1, overflow: "auto", padding: 10, background: "#f5f5f5", display: "flex", flexDirection: "column", gap: 7 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
{[["Revenue", "$4.2k", "#1976d2"], ["Users", "184", "#7b1fa2"]].map(([l, v, c]) => (
<div key={l} style={{ borderRadius: 8, padding: "8px 10px", background: c }}>
<p style={{ fontSize: 7, color: "rgba(255,255,255,0.7)", marginBottom: 2 }}>{l}</p>
<p style={{ fontSize: 12, fontWeight: 700, color: "#fff" }}>{v}</p>
</div>
))}
</div>
{["Fix login bug", "Update pricing", "Review PR #42"].map((t, i) => (
<div key={t} style={{ background: "#fff", borderRadius: 8, padding: "8px 10px", display: "flex", alignItems: "center", gap: 8, boxShadow: "0 1px 3px rgba(0,0,0,0.08)" }}>
<div style={{ width: 14, height: 14, borderRadius: "50%", border: `2px solid ${i === 0 ? "#1976d2" : "#bdbdbd"}`, flexShrink: 0, background: i === 0 ? "#1976d2" : "none" }} />
<p style={{ fontSize: 9, color: i === 0 ? "#9e9e9e" : "#212121", textDecoration: i === 0 ? "line-through" : "none" }}>{t}</p>
</div>
))}
</div>
<div style={{ display: "flex", borderTop: "1px solid #e0e0e0", padding: "6px 0 10px", background: "#fff" }}>
{["Home", "Tasks", "Chat", "Profile"].map((l, i) => (
<div key={l} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 2 }}>
<div style={{ width: 14, height: 14, borderRadius: 3, background: i === 0 ? "#1976d2" : "#e0e0e0" }} />
<span style={{ fontSize: 7, color: i === 0 ? "#1976d2" : "#9e9e9e" }}>{l}</span>
</div>
))}
</div>
</div>
</MobileFrame>
);
}