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,403 @@
"use client";
import { useState } from "react";
import { ThemeColor, TABLE_ROWS, SHADCN_THEMES, MANTINE_THEMES, HEROUI_THEMES, TREMOR_THEMES } from "./types";
// Web App surface — shows a logged-in SaaS product: Dashboard, Users, Settings
// This is what the user's customers see after signing in.
type Page = "Dashboard" | "Users" | "Settings";
// ---------------------------------------------------------------------------
// Shared layout shell — nav + header are reused across libraries
// ---------------------------------------------------------------------------
function AppShell({
brand, navBg, navText, navItems, activePage, onNav, headerBg, header, children,
}: {
brand: string; navBg: string; navText: string;
navItems: { label: Page; icon: string }[];
activePage: Page; onNav: (p: Page) => void;
headerBg: string; header: React.ReactNode; children: React.ReactNode;
}) {
return (
<div style={{ display: "flex", height: "100%", fontFamily: "system-ui, sans-serif", fontSize: 14 }}>
<div style={{ width: 168, flexShrink: 0, background: navBg, borderRight: "1px solid rgba(0,0,0,0.07)", display: "flex", flexDirection: "column", padding: "14px 10px" }}>
<div style={{ display: "flex", alignItems: "center", gap: 8, padding: "0 6px", marginBottom: 18 }}>
<div style={{ width: 22, height: 22, borderRadius: 5, background: brand, flexShrink: 0 }} />
<span style={{ fontWeight: 700, fontSize: 11, color: navText }}>Acme Inc</span>
</div>
{navItems.map(({ label, icon }) => (
<button key={label} onClick={() => onNav(label)} style={{
display: "flex", alignItems: "center", gap: 7,
width: "100%", padding: "7px 8px", borderRadius: 6, border: "none",
background: "none", cursor: "pointer", textAlign: "left",
fontSize: 11, fontWeight: activePage === label ? 600 : 400,
color: activePage === label ? navText : `${navText}80`,
marginBottom: 2,
}}>
<span style={{ fontSize: 10, opacity: 0.6 }}>{icon}</span>{label}
</button>
))}
</div>
<div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
<div style={{ height: 44, background: headerBg, borderBottom: "1px solid rgba(0,0,0,0.07)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 18px", flexShrink: 0 }}>
{header}
</div>
<div style={{ flex: 1, overflow: "auto" }}>
{children}
</div>
</div>
</div>
);
}
// ---------------------------------------------------------------------------
// shadcn/ui
// ---------------------------------------------------------------------------
export function WebAppShadcn({ themeColor }: { themeColor?: ThemeColor }) {
const [page, setPage] = useState<Page>("Dashboard");
const t = themeColor ?? SHADCN_THEMES[0];
const NAV = [{ label: "Dashboard" as Page, icon: "▦" }, { label: "Users" as Page, icon: "◎" }, { label: "Settings" as Page, icon: "⚙" }];
return (
<AppShell brand={t.primary} navBg="#fff" navText="#18181b"
navItems={NAV} activePage={page} onNav={setPage}
headerBg="#fff" header={<>
<span style={{ fontWeight: 600, fontSize: 13, color: "#18181b" }}>{page}</span>
<div style={{ display: "flex", gap: 6 }}>
<div style={{ height: 28, padding: "0 12px", borderRadius: 6, border: "1px solid #e4e4e7", display: "flex", alignItems: "center", fontSize: 11, color: "#71717a" }}>Export</div>
<div style={{ height: 28, padding: "0 12px", borderRadius: 6, background: t.primary, color: t.primaryFg, display: "flex", alignItems: "center", fontSize: 11, fontWeight: 600 }}>+ New</div>
</div>
</>}
>
{page === "Dashboard" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 14 }}>
{[["Total Revenue", "$12,400", "+12%"], ["Active Users", "2,841", "+8%"], ["Conversions", "18.2%", "+3%"]].map(([l, v, d]) => (
<div key={l} style={{ background: "#fff", border: "1px solid #e4e4e7", borderRadius: 8, padding: "12px 14px" }}>
<p style={{ fontSize: 10, color: "#71717a", marginBottom: 4 }}>{l}</p>
<p style={{ fontSize: 18, fontWeight: 700, color: "#09090b", marginBottom: 2 }}>{v}</p>
<p style={{ fontSize: 10, color: t.activeFg }}>{d} from last month</p>
</div>
))}
</div>
<div style={{ background: "#fff", border: "1px solid #e4e4e7", borderRadius: 8, marginBottom: 10 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f4f4f5", fontSize: 11, fontWeight: 600, color: "#09090b" }}>Revenue</div>
<div style={{ padding: "14px 14px", display: "flex", alignItems: "flex-end", gap: 4, height: 80 }}>
{[40,60,45,75,65,85,70,90,55,80,75,95].map((h, i) => (
<div key={i} style={{ flex: 1, borderRadius: 3, background: i === 11 ? t.primary : t.ring, height: `${h}%` }} />
))}
</div>
</div>
<div style={{ background: "#fff", border: "1px solid #e4e4e7", borderRadius: 8 }}>
{TABLE_ROWS.slice(0, 3).map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", borderBottom: "1px solid #f9f9f9" }}>
<div style={{ width: 24, height: 24, borderRadius: "50%", background: t.ring, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<p style={{ fontSize: 11, fontWeight: 500, color: "#09090b" }}>{r.name}</p>
<p style={{ fontSize: 10, color: "#a1a1aa" }}>{r.email}</p>
</div>
<span style={{ fontSize: 10, fontWeight: 600, padding: "2px 7px", borderRadius: 4, background: r.status === "Active" ? t.activeBg : "#f4f4f5", color: r.status === "Active" ? t.activeFg : "#a1a1aa" }}>{r.status}</span>
</div>
))}
</div>
</div>
)}
{page === "Users" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ background: "#fff", border: "1px solid #e4e4e7", borderRadius: 8 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f4f4f5", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontSize: 11, fontWeight: 600, color: "#09090b" }}>Team members</span>
<div style={{ display: "flex", gap: 6 }}>
<input style={{ height: 28, padding: "0 10px", border: "1px solid #e4e4e7", borderRadius: 6, fontSize: 11, width: 120, outline: "none" }} placeholder="Search..." />
<div style={{ height: 28, padding: "0 12px", borderRadius: 6, background: t.primary, color: t.primaryFg, display: "flex", alignItems: "center", fontSize: 11, fontWeight: 600 }}>Invite</div>
</div>
</div>
{TABLE_ROWS.map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", padding: "10px 14px", borderBottom: "1px solid #f9f9f9", gap: 10 }}>
<div style={{ width: 24, height: 24, borderRadius: "50%", background: t.ring, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<p style={{ fontSize: 11, fontWeight: 500, color: "#09090b" }}>{r.name}</p>
<p style={{ fontSize: 10, color: "#a1a1aa" }}>{r.email}</p>
</div>
<span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 4, border: "1px solid #e4e4e7", color: "#71717a" }}>{r.role}</span>
<span style={{ fontSize: 10, fontWeight: 600, padding: "2px 7px", borderRadius: 4, background: r.status === "Active" ? t.activeBg : "#f4f4f5", color: r.status === "Active" ? t.activeFg : "#a1a1aa" }}>{r.status}</span>
<span style={{ fontSize: 10, color: "#d4d4d8" }}>{r.date}</span>
</div>
))}
</div>
</div>
)}
{page === "Settings" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ background: "#fff", border: "1px solid #e4e4e7", borderRadius: 8, marginBottom: 10 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f4f4f5", fontSize: 11, fontWeight: 600, color: "#09090b" }}>General</div>
<div style={{ padding: 14, display: "flex", flexDirection: "column", gap: 10 }}>
{[["Workspace name", "Acme Inc"], ["Slug", "acme-inc"], ["Email", "admin@acme.com"]].map(([l, v]) => (
<div key={l}>
<label style={{ fontSize: 10, fontWeight: 500, color: "#71717a", display: "block", marginBottom: 4 }}>{l}</label>
<input defaultValue={v} style={{ width: "100%", height: 32, padding: "0 10px", border: "1px solid #e4e4e7", borderRadius: 6, fontSize: 11, outline: "none" }} />
</div>
))}
<div style={{ height: 30, padding: "0 14px", borderRadius: 6, background: t.primary, color: t.primaryFg, display: "inline-flex", alignItems: "center", fontSize: 11, fontWeight: 600, alignSelf: "flex-start" }}>Save changes</div>
</div>
</div>
</div>
)}
</AppShell>
);
}
// ---------------------------------------------------------------------------
// Mantine
// ---------------------------------------------------------------------------
export function WebAppMantine({ themeColor }: { themeColor?: ThemeColor }) {
const [page, setPage] = useState<Page>("Dashboard");
const t = themeColor ?? MANTINE_THEMES[0];
const NAV = [{ label: "Dashboard" as Page, icon: "▦" }, { label: "Users" as Page, icon: "◎" }, { label: "Settings" as Page, icon: "⚙" }];
return (
<AppShell brand={t.primary} navBg="#fff" navText="#212529"
navItems={NAV} activePage={page} onNav={setPage}
headerBg="#fff" header={<>
<span style={{ fontWeight: 700, fontSize: 13, color: "#212529" }}>{page}</span>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 28, padding: "0 12px", border: "1px solid #dee2e6", borderRadius: 5, fontSize: 11, background: "none", color: "#495057" }}>Export</button>
<button style={{ height: 28, padding: "0 12px", borderRadius: 5, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600 }}>+ New</button>
</div>
</>}
>
{page === "Dashboard" && (
<div style={{ padding: 18, background: "#f8f9fa" }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 14 }}>
{[["Total Revenue", "$12,400", "#2f9e44"], ["Active Users", "2,841", "#228be6"], ["Conversions", "18.2%", "#e67700"]].map(([l, v, c]) => (
<div key={l} style={{ background: "#fff", border: "1px solid #e9ecef", borderRadius: 8, padding: "12px 14px" }}>
<p style={{ fontSize: 10, color: "#868e96", marginBottom: 4 }}>{l}</p>
<p style={{ fontSize: 18, fontWeight: 700, color: "#212529", marginBottom: 2 }}>{v}</p>
<p style={{ fontSize: 10, color: c }}> trending up</p>
</div>
))}
</div>
<div style={{ background: "#fff", border: "1px solid #e9ecef", borderRadius: 8, marginBottom: 10 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #e9ecef", fontSize: 11, fontWeight: 600, color: "#212529" }}>Monthly revenue</div>
<div style={{ padding: "14px", display: "flex", alignItems: "flex-end", gap: 4, height: 80 }}>
{[40,60,45,75,65,85,70,90,55,80,75,95].map((h, i) => (
<div key={i} style={{ flex: 1, borderRadius: 2, background: i === 11 ? t.primary : t.ring, height: `${h}%` }} />
))}
</div>
</div>
<div style={{ background: "#fff", border: "1px solid #e9ecef", borderRadius: 8 }}>
{TABLE_ROWS.slice(0, 3).map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", borderBottom: "1px solid #f1f3f5" }}>
<div style={{ width: 26, height: 26, borderRadius: "50%", background: t.ring, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<p style={{ fontSize: 11, fontWeight: 600, color: "#212529" }}>{r.name}</p>
<p style={{ fontSize: 10, color: "#868e96" }}>{r.email}</p>
</div>
<span style={{ fontSize: 10, fontWeight: 600, padding: "2px 7px", borderRadius: 4, background: r.status === "Active" ? "#d3f9d8" : "#f1f3f5", color: r.status === "Active" ? "#2f9e44" : "#868e96" }}>{r.status}</span>
</div>
))}
</div>
</div>
)}
{page === "Users" && (
<div style={{ padding: 18, background: "#f8f9fa" }}>
<div style={{ background: "#fff", border: "1px solid #e9ecef", borderRadius: 8 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #e9ecef", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style={{ fontSize: 11, fontWeight: 600, color: "#212529" }}>Team members</span>
<button style={{ height: 28, padding: "0 12px", borderRadius: 5, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600 }}>+ Invite</button>
</div>
{TABLE_ROWS.map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", padding: "10px 14px", borderBottom: "1px solid #f1f3f5", gap: 10 }}>
<div style={{ width: 26, height: 26, borderRadius: "50%", background: t.ring, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<p style={{ fontSize: 11, fontWeight: 600, color: "#212529" }}>{r.name}</p>
<p style={{ fontSize: 10, color: "#868e96" }}>{r.email}</p>
</div>
<span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 4, background: t.activeBg, color: t.activeFg }}>{r.role}</span>
<span style={{ fontSize: 10, fontWeight: 600, padding: "2px 7px", borderRadius: 4, background: r.status === "Active" ? "#d3f9d8" : r.status === "Pending" ? "#fff3bf" : "#f1f3f5", color: r.status === "Active" ? "#2f9e44" : r.status === "Pending" ? "#e67700" : "#868e96" }}>{r.status}</span>
</div>
))}
</div>
</div>
)}
{page === "Settings" && (
<div style={{ padding: 18, background: "#f8f9fa" }}>
<div style={{ background: "#fff", border: "1px solid #e9ecef", borderRadius: 8 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #e9ecef", fontSize: 11, fontWeight: 600, color: "#212529" }}>Workspace</div>
<div style={{ padding: 14, display: "flex", flexDirection: "column", gap: 10 }}>
{[["Name", "Acme Inc"], ["Slug", "acme-inc"], ["Email", "admin@acme.com"]].map(([l, v]) => (
<div key={l}>
<label style={{ fontSize: 10, fontWeight: 600, color: "#495057", display: "block", marginBottom: 4 }}>{l}</label>
<input defaultValue={v} style={{ width: "100%", height: 32, padding: "0 10px", border: "1px solid #dee2e6", borderRadius: 5, fontSize: 11, outline: "none" }} />
</div>
))}
<button style={{ height: 30, padding: "0 14px", borderRadius: 5, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600, alignSelf: "flex-start" }}>Save</button>
</div>
</div>
</div>
)}
</AppShell>
);
}
// ---------------------------------------------------------------------------
// HeroUI
// ---------------------------------------------------------------------------
export function WebAppHeroUI({ themeColor }: { themeColor?: ThemeColor }) {
const [page, setPage] = useState<Page>("Dashboard");
const t = themeColor ?? HEROUI_THEMES[0];
const NAV = [{ label: "Dashboard" as Page, icon: "▦" }, { label: "Users" as Page, icon: "◎" }, { label: "Settings" as Page, icon: "⚙" }];
return (
<AppShell brand={t.primary} navBg="linear-gradient(180deg,#1a1a2e,#16213e)" navText="#fff"
navItems={NAV} activePage={page} onNav={setPage}
headerBg="#fff" header={<>
<span style={{ fontWeight: 700, fontSize: 13, color: t.primary }}>{page}</span>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 28, padding: "0 12px", borderRadius: 20, border: "1px solid #e4e4e7", fontSize: 11, background: "none", color: "#71717a" }}>Export</button>
<button style={{ height: 28, padding: "0 12px", borderRadius: 20, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600 }}>+ New</button>
</div>
</>}
>
{page === "Dashboard" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 14 }}>
{[["Revenue", "$12,400"], ["Users", "2,841"], ["Conversion", "18.2%"]].map(([l, v]) => (
<div key={l} style={{ background: "#fff", border: "1px solid #f4f4f5", borderRadius: 14, padding: "12px 14px", boxShadow: "0 2px 8px rgba(0,0,0,0.05)" }}>
<p style={{ fontSize: 10, color: "#a1a1aa", marginBottom: 4 }}>{l}</p>
<p style={{ fontSize: 18, fontWeight: 700, color: "#18181b" }}>{v}</p>
<p style={{ fontSize: 10, color: t.primary }}> this month</p>
</div>
))}
</div>
<div style={{ background: "#fff", border: "1px solid #f4f4f5", borderRadius: 14, padding: 14, boxShadow: "0 2px 8px rgba(0,0,0,0.05)" }}>
<div style={{ display: "flex", alignItems: "flex-end", gap: 4, height: 72 }}>
{[40,60,45,75,65,85,70,90,55,80,75,95].map((h, i) => (
<div key={i} style={{ flex: 1, borderRadius: 5, background: i === 11 ? `linear-gradient(180deg,${t.primary},${t.ring})` : t.activeBg, height: `${h}%` }} />
))}
</div>
</div>
</div>
)}
{page === "Users" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ background: "#fff", border: "1px solid #f4f4f5", borderRadius: 14, boxShadow: "0 2px 8px rgba(0,0,0,0.05)" }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f4f4f5", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style={{ fontSize: 11, fontWeight: 700, color: "#18181b" }}>Team</span>
<button style={{ height: 28, padding: "0 14px", borderRadius: 20, background: `linear-gradient(135deg,${t.primary},${t.ring})`, color: "#fff", border: "none", fontSize: 11, fontWeight: 600 }}>+ Invite</button>
</div>
{TABLE_ROWS.map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", padding: "10px 14px", borderBottom: "1px solid #fafafa", gap: 10 }}>
<div style={{ width: 28, height: 28, borderRadius: "50%", background: t.activeBg, flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<p style={{ fontSize: 11, fontWeight: 600, color: "#18181b" }}>{r.name}</p>
<p style={{ fontSize: 10, color: "#a1a1aa" }}>{r.email}</p>
</div>
<span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 20, background: t.activeBg, color: t.activeFg }}>{r.role}</span>
<span style={{ fontSize: 10, fontWeight: 600, padding: "2px 8px", borderRadius: 20, background: r.status === "Active" ? "rgba(34,197,94,0.1)" : "#f4f4f5", color: r.status === "Active" ? "#16a34a" : "#a1a1aa" }}>{r.status}</span>
</div>
))}
</div>
</div>
)}
{page === "Settings" && (
<div style={{ padding: 18, background: "#fafafa" }}>
<div style={{ background: "#fff", border: "1px solid #f4f4f5", borderRadius: 14, boxShadow: "0 2px 8px rgba(0,0,0,0.05)" }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f4f4f5", fontSize: 11, fontWeight: 700, color: "#18181b" }}>Profile</div>
<div style={{ padding: 14, display: "flex", flexDirection: "column", gap: 10 }}>
{[["Workspace", "Acme Inc"], ["Slug", "acme-inc"], ["Email", "admin@acme.com"]].map(([l, v]) => (
<div key={l}>
<label style={{ fontSize: 10, fontWeight: 600, color: "#71717a", display: "block", marginBottom: 4 }}>{l}</label>
<input defaultValue={v} style={{ width: "100%", height: 32, padding: "0 12px", border: "1px solid #e4e4e7", borderRadius: 10, fontSize: 11, outline: "none" }} />
</div>
))}
<button style={{ height: 30, padding: "0 16px", borderRadius: 20, background: `linear-gradient(135deg,${t.primary},${t.ring})`, color: "#fff", border: "none", fontSize: 11, fontWeight: 700, alignSelf: "flex-start" }}>Save changes</button>
</div>
</div>
</div>
)}
</AppShell>
);
}
// ---------------------------------------------------------------------------
// Tremor (analytics/data-heavy)
// ---------------------------------------------------------------------------
export function WebAppTremor({ themeColor }: { themeColor?: ThemeColor }) {
const [page, setPage] = useState<Page>("Dashboard");
const t = themeColor ?? TREMOR_THEMES[0];
const NAV = [{ label: "Dashboard" as Page, icon: "▦" }, { label: "Users" as Page, icon: "◎" }, { label: "Settings" as Page, icon: "⚙" }];
return (
<AppShell brand={t.primary} navBg="#fff" navText="#374151"
navItems={NAV} activePage={page} onNav={setPage}
headerBg="#fff" header={<>
<span style={{ fontWeight: 700, fontSize: 13, color: "#111827" }}>{page}</span>
<button style={{ height: 28, padding: "0 12px", borderRadius: 7, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600 }}>+ New</button>
</>}
>
{page === "Dashboard" && (
<div style={{ padding: 18, background: "#f9fafb" }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 14 }}>
{[{ l: "Revenue", v: "$12,400", c: t.primary, pct: 65 }, { l: "Users", v: "2,841", c: "#7c3aed", pct: 48 }, { l: "Conversion", v: "18.2%", c: "#059669", pct: 72 }].map(item => (
<div key={item.l} style={{ background: "#fff", border: "1px solid #e5e7eb", borderRadius: 10, padding: "12px 14px" }}>
<p style={{ fontSize: 10, color: "#6b7280", marginBottom: 6 }}>{item.l}</p>
<p style={{ fontSize: 18, fontWeight: 700, color: "#111827", marginBottom: 6 }}>{item.v}</p>
<div style={{ height: 5, borderRadius: 9, background: "#f3f4f6" }}>
<div style={{ height: "100%", borderRadius: 9, width: `${item.pct}%`, background: item.c }} />
</div>
</div>
))}
</div>
<div style={{ background: "#fff", border: "1px solid #e5e7eb", borderRadius: 10, padding: 14 }}>
<p style={{ fontSize: 11, fontWeight: 600, color: "#111827", marginBottom: 10 }}>Revenue over time</p>
<div style={{ display: "flex", alignItems: "flex-end", gap: 4, height: 70 }}>
{[40,65,55,80,70,90,75,85,60,95,80,100].map((h, i) => (
<div key={i} style={{ flex: 1, borderRadius: 3, background: i === 11 ? t.primary : t.activeBg, height: `${h}%` }} />
))}
</div>
</div>
</div>
)}
{page === "Users" && (
<div style={{ padding: 18, background: "#f9fafb" }}>
<div style={{ background: "#fff", border: "1px solid #e5e7eb", borderRadius: 10 }}>
<div style={{ padding: "10px 14px", borderBottom: "1px solid #f3f4f6", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style={{ fontSize: 11, fontWeight: 600, color: "#111827" }}>All users</span>
<input style={{ height: 28, padding: "0 10px", border: "1px solid #e5e7eb", borderRadius: 7, fontSize: 11, width: 120, outline: "none" }} placeholder="Filter..." />
</div>
{TABLE_ROWS.map(r => (
<div key={r.name} style={{ display: "flex", alignItems: "center", padding: "10px 14px", borderBottom: "1px solid #f9fafb", gap: 10 }}>
<span style={{ flex: 1, fontSize: 11, fontWeight: 500, color: "#111827" }}>{r.name}</span>
<span style={{ fontSize: 10, color: "#6b7280" }}>{r.role}</span>
<div style={{ display: "flex", alignItems: "center", gap: 4 }}>
<div style={{ width: 6, height: 6, borderRadius: "50%", background: r.status === "Active" ? "#059669" : r.status === "Pending" ? "#d97706" : "#d1d5db" }} />
<span style={{ fontSize: 10, color: "#374151" }}>{r.status}</span>
</div>
</div>
))}
</div>
</div>
)}
{page === "Settings" && (
<div style={{ padding: 18, background: "#f9fafb" }}>
<div style={{ background: "#fff", border: "1px solid #e5e7eb", borderRadius: 10, padding: 14 }}>
<p style={{ fontSize: 11, fontWeight: 600, color: "#111827", marginBottom: 12 }}>Workspace</p>
<div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
{[["Name", "Acme Inc"], ["Domain", "acme.com"], ["Timezone", "UTC-8"]].map(([l, v]) => (
<div key={l}>
<label style={{ fontSize: 10, fontWeight: 500, color: "#6b7280", display: "block", marginBottom: 4 }}>{l}</label>
<input defaultValue={v} style={{ width: "100%", height: 32, padding: "0 10px", border: "1px solid #e5e7eb", borderRadius: 7, fontSize: 11, outline: "none" }} />
</div>
))}
<button style={{ height: 30, padding: "0 14px", borderRadius: 7, background: t.primary, color: t.primaryFg, border: "none", fontSize: 11, fontWeight: 600, alignSelf: "flex-start" }}>Save</button>
</div>
</div>
</div>
)}
</AppShell>
);
}
export { SHADCN_THEMES, MANTINE_THEMES, HEROUI_THEMES, TREMOR_THEMES };