Replace flat library buttons with capability cards on design page
Each library option now shows: best-for summary, 3 key highlights, capability tags, Templates badge, and Dark-first badge. All surface themes updated with richer metadata. Marketing surface updated with full highlights for DaisyUI/HeroUI/Aceternity/Tailwind. Made-with: Cursor
This commit is contained in:
@@ -22,6 +22,11 @@ interface Theme {
|
||||
description: string;
|
||||
tags: string[];
|
||||
url: string;
|
||||
// Richer metadata shown in the capability card picker
|
||||
highlights?: string[]; // 3 key things this library does well
|
||||
hasTemplates?: boolean; // pre-built page templates available
|
||||
bestFor?: string; // one-line "best for" summary
|
||||
darkFirst?: boolean; // dark-mode-first aesthetic
|
||||
}
|
||||
|
||||
const ALL_SURFACES: Surface[] = [
|
||||
@@ -31,10 +36,37 @@ const ALL_SURFACES: Surface[] = [
|
||||
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" },
|
||||
{ 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: "shadcn", name: "shadcn/ui", url: "https://ui.shadcn.com",
|
||||
description: "Copy-paste components on Radix primitives. You own the code.",
|
||||
tags: ["Tailwind", "Radix", "Copy-paste"],
|
||||
bestFor: "Most SaaS apps — you control every pixel",
|
||||
highlights: ["Code lives in your repo, not node_modules", "Radix primitives for full accessibility", "New York & Default variants built in"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
{
|
||||
id: "mantine", name: "Mantine", url: "https://mantine.dev",
|
||||
description: "100+ fully featured components including charts, forms, date pickers.",
|
||||
tags: ["React", "Charts", "Forms", "Hooks"],
|
||||
bestFor: "Data-heavy apps that need charts and complex forms",
|
||||
highlights: ["Built-in charts, tables, and data grid", "60+ hooks (useForm, useLocalStorage, etc.)", "Date/time pickers, rich text editor included"],
|
||||
},
|
||||
{
|
||||
id: "hero-ui", name: "HeroUI", url: "https://heroui.com",
|
||||
description: "Smooth animations, blur effects, and dark mode out of the box.",
|
||||
tags: ["Tailwind", "Framer Motion", "Dark mode"],
|
||||
bestFor: "Modern SaaS with polished animations",
|
||||
highlights: ["Blur backdrop navigation built in", "Framer Motion on every interaction", "Dark mode first, light mode included"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
{
|
||||
id: "tremor", name: "Tremor", url: "https://tremor.so",
|
||||
description: "Purpose-built dashboard components — charts, KPIs, tables.",
|
||||
tags: ["Charts", "Dashboard", "Analytics"],
|
||||
bestFor: "Analytics products and internal dashboards",
|
||||
highlights: ["Chart library built in (area, bar, donut)", "KPI cards, progress bars, trackers", "Area chart with tooltip out of the box"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -43,10 +75,37 @@ const ALL_SURFACES: Surface[] = [
|
||||
icon: "◎",
|
||||
description: "Public-facing landing page, blog, pricing — brand expression and conversion",
|
||||
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" },
|
||||
{ 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: "daisy-ui", name: "DaisyUI", url: "https://daisyui.com",
|
||||
description: "Tailwind plugin with 48 built-in themes — swap the entire look with one word.",
|
||||
tags: ["Tailwind", "48 Themes", "Plugin"],
|
||||
bestFor: "Teams that want theme variety without custom CSS",
|
||||
highlights: ["48 built-in themes (dark, cupcake, synthwave, cyberpunk…)", "One-line theme switching: data-theme=\"synthwave\"", "Hero, Features, Pricing, CTA, Footer all included"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
{
|
||||
id: "hero-ui", name: "HeroUI", url: "https://heroui.com",
|
||||
description: "Gradient buttons, animated badges, blur nav — high-end SaaS look.",
|
||||
tags: ["Tailwind", "Framer Motion", "Gradients"],
|
||||
bestFor: "Modern SaaS landing page with a premium feel",
|
||||
highlights: ["Gradient & glassmorphism components", "Animated feature cards with hover depth", "Navbar with blur-backdrop effect"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
{
|
||||
id: "aceternity", name: "Aceternity UI", url: "https://ui.aceternity.com",
|
||||
description: "Signature background effects — beams, meteors, sparkles, wavy gradients.",
|
||||
tags: ["Framer Motion", "Background FX", "Dark-first"],
|
||||
bestFor: "Premium, visually striking launch pages",
|
||||
highlights: ["Background Beams, Meteors, Sparkles effects", "Infinite moving cards, Lamp effect, Wavy BG", "Text generate & typewriter animations"],
|
||||
darkFirst: true,
|
||||
},
|
||||
{
|
||||
id: "tailwind-only", name: "Tailwind only", url: "https://tailwindcss.com",
|
||||
description: "Zero component library. Full creative control — design exactly what you want.",
|
||||
tags: ["Custom", "Zero constraints", "Typography-first"],
|
||||
bestFor: "Strong design opinions, no library overhead",
|
||||
highlights: ["No component library constraints", "Typography-first editorial layouts", "Fastest builds, smallest bundle"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -55,9 +114,28 @@ const ALL_SURFACES: Surface[] = [
|
||||
icon: "◫",
|
||||
description: "Internal tool for managing your business — users, support, billing, analytics",
|
||||
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" },
|
||||
{ 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: "mantine", name: "Mantine", url: "https://mantine.dev",
|
||||
description: "Comprehensive component set built for admin — tables, forms, charts.",
|
||||
tags: ["Tables", "Forms", "Charts", "Date picker"],
|
||||
bestFor: "Feature-rich internal tools",
|
||||
highlights: ["Data grid with sorting, filtering, pagination", "Complex form handling with validation", "Stats, charts, and KPI components"],
|
||||
},
|
||||
{
|
||||
id: "shadcn", name: "shadcn/ui", url: "https://ui.shadcn.com",
|
||||
description: "Clean components that match your main app if it uses shadcn.",
|
||||
tags: ["Tailwind", "Consistent", "Copy-paste"],
|
||||
bestFor: "Keeping admin and app visually consistent",
|
||||
highlights: ["Matches the web app if using shadcn", "Data table with react-table built in", "Command palette, sheets, dialogs"],
|
||||
},
|
||||
{
|
||||
id: "tremor", name: "Tremor", url: "https://tremor.so",
|
||||
description: "Analytics-first admin — built for KPI dashboards and data tables.",
|
||||
tags: ["Analytics", "Charts", "KPIs"],
|
||||
bestFor: "Analytics-heavy operations dashboards",
|
||||
highlights: ["KPI cards, area charts, bar lists built in", "Data table with search + filter", "Progress bars, badges, trackers"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -66,8 +144,20 @@ const ALL_SURFACES: Surface[] = [
|
||||
icon: "▢",
|
||||
description: "iOS and Android companion app — touch-first, native feel",
|
||||
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" },
|
||||
{ id: "gluestack", name: "Gluestack UI", description: "Universal components for React Native — accessible, well-tested, comprehensive.", tags: ["Universal", "Accessible", "Expo"], url: "https://gluestack.io" },
|
||||
{
|
||||
id: "nativewind", name: "NativeWind", url: "https://nativewind.dev",
|
||||
description: "Use Tailwind classes in React Native. Consistent web + mobile styling.",
|
||||
tags: ["Tailwind", "React Native", "Expo"],
|
||||
bestFor: "Teams already using Tailwind on web",
|
||||
highlights: ["Same Tailwind classes on web and mobile", "Expo compatible, dark mode support", "Platform-specific variants built in"],
|
||||
},
|
||||
{
|
||||
id: "gluestack", name: "Gluestack UI", url: "https://gluestack.io",
|
||||
description: "Universal component library for React Native with accessibility baked in.",
|
||||
tags: ["Universal", "Accessible", "Expo"],
|
||||
bestFor: "Comprehensive native component coverage",
|
||||
highlights: ["50+ components (ActionSheet, Toast, FAB…)", "ARIA accessible out of the box", "Works on iOS, Android, and web"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -76,7 +166,14 @@ const ALL_SURFACES: Surface[] = [
|
||||
icon: "✉",
|
||||
description: "Transactional and marketing emails — welcome, billing, notifications",
|
||||
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" },
|
||||
{
|
||||
id: "react-email", name: "React Email", url: "https://react.email",
|
||||
description: "Build beautiful emails with React. Test across 90+ email clients.",
|
||||
tags: ["React", "Resend", "Cross-client", "Preview"],
|
||||
bestFor: "Teams wanting React-based email workflows",
|
||||
highlights: ["Live preview across Gmail, Outlook, Apple Mail", "Works with Resend, SendGrid, Postmark", "50+ pre-built email components"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -85,8 +182,21 @@ const ALL_SURFACES: Surface[] = [
|
||||
icon: "☰",
|
||||
description: "Documentation, knowledge base, or blog for your product",
|
||||
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" },
|
||||
{ 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" },
|
||||
{
|
||||
id: "nextra", name: "Nextra", url: "https://nextra.site",
|
||||
description: "Next.js-based docs with built-in search, MDX, and versioning.",
|
||||
tags: ["Next.js", "MDX", "Search", "Dark mode"],
|
||||
bestFor: "Developer-facing documentation",
|
||||
highlights: ["Full-text search out of the box (Pagefind)", "MDX — React components inside Markdown", "Auto-generated sidebar from file structure"],
|
||||
hasTemplates: true,
|
||||
},
|
||||
{
|
||||
id: "shadcn", name: "shadcn/ui + custom", url: "https://ui.shadcn.com",
|
||||
description: "Fully custom docs site that matches your product exactly.",
|
||||
tags: ["Custom", "Tailwind", "Flexible"],
|
||||
bestFor: "Brand-consistent docs that stand out",
|
||||
highlights: ["Matches your app's exact design language", "Full control over layout and navigation", "Blog, changelog, and API ref in one"],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -170,39 +280,99 @@ function SurfaceSection({
|
||||
{/* Controls below render */}
|
||||
<div style={{ flexShrink: 0, paddingTop: 18, display: "flex", flexDirection: "column", gap: 14 }}>
|
||||
|
||||
{/* Library tabs */}
|
||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
||||
{/* Library capability cards */}
|
||||
<div style={{ display: "grid", gridTemplateColumns: `repeat(${Math.min(surface.themes.length, 4)}, 1fr)`, gap: 8 }}>
|
||||
{surface.themes.map(theme => {
|
||||
const isActive = theme.id === previewId;
|
||||
const isThisLocked = theme.id === lockedThemeId;
|
||||
const dimmed = isLocked && !isThisLocked;
|
||||
return (
|
||||
<button
|
||||
key={theme.id}
|
||||
onClick={() => { if (!isLocked) { onSelect(theme.id); setSelectedColorTheme(null); } }}
|
||||
disabled={isLocked && !isThisLocked}
|
||||
disabled={dimmed}
|
||||
style={{
|
||||
display: "flex", alignItems: "center", gap: 5,
|
||||
padding: "6px 14px", borderRadius: 6, border: "1px solid",
|
||||
fontSize: "0.78rem", fontWeight: isActive ? 600 : 500,
|
||||
fontFamily: "Outfit", cursor: isLocked && !isThisLocked ? "not-allowed" : "pointer",
|
||||
transition: "all 0.12s",
|
||||
borderColor: isActive ? "#1a1a1a" : "#e0dcd4",
|
||||
display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 0,
|
||||
padding: "12px 14px", borderRadius: 9, textAlign: "left",
|
||||
border: `1px solid ${isActive ? "#1a1a1a" : "#e8e4dc"}`,
|
||||
background: isActive ? "#1a1a1a" : "#fff",
|
||||
color: isActive ? "#fff" : isLocked && !isThisLocked ? "#c5c0b8" : "#6b6560",
|
||||
opacity: isLocked && !isThisLocked ? 0.4 : 1,
|
||||
boxShadow: isActive ? "0 0 0 1px #1a1a1a" : "none",
|
||||
cursor: dimmed ? "not-allowed" : "pointer",
|
||||
opacity: dimmed ? 0.35 : 1,
|
||||
transition: "all 0.12s",
|
||||
position: "relative",
|
||||
fontFamily: "Outfit, sans-serif",
|
||||
}}
|
||||
onMouseEnter={e => { if (!isLocked && !isActive) { (e.currentTarget as HTMLElement).style.borderColor = "#c5c0b8"; } }}
|
||||
onMouseLeave={e => { if (!isLocked && !isActive) { (e.currentTarget as HTMLElement).style.borderColor = "#e8e4dc"; } }}
|
||||
>
|
||||
{isThisLocked && <span style={{ fontSize: "0.65rem" }}>🔒</span>}
|
||||
{/* Top row: name + badges */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 6, width: "100%", marginBottom: 8 }}>
|
||||
{isThisLocked && <span style={{ fontSize: "0.6rem" }}>🔒</span>}
|
||||
<span style={{ fontSize: "0.8rem", fontWeight: 700, color: isActive ? "#fff" : "#1a1a1a", flex: 1 }}>
|
||||
{theme.name}
|
||||
</span>
|
||||
{theme.hasTemplates && (
|
||||
<span style={{
|
||||
fontSize: "0.56rem", fontWeight: 700, padding: "1px 5px", borderRadius: 3,
|
||||
background: isActive ? "rgba(255,255,255,0.15)" : "#f0ece4",
|
||||
color: isActive ? "rgba(255,255,255,0.8)" : "#8a8478",
|
||||
letterSpacing: "0.04em", textTransform: "uppercase", flexShrink: 0,
|
||||
}}>Templates</span>
|
||||
)}
|
||||
{theme.darkFirst && (
|
||||
<span style={{
|
||||
fontSize: "0.56rem", fontWeight: 700, padding: "1px 5px", borderRadius: 3,
|
||||
background: isActive ? "rgba(255,255,255,0.15)" : "#1a1a1a",
|
||||
color: isActive ? "rgba(255,255,255,0.8)" : "#fff",
|
||||
letterSpacing: "0.04em", textTransform: "uppercase", flexShrink: 0,
|
||||
}}>Dark</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Best for */}
|
||||
{theme.bestFor && (
|
||||
<p style={{ fontSize: "0.68rem", color: isActive ? "rgba(255,255,255,0.55)" : "#a09a90", marginBottom: 8, lineHeight: 1.4 }}>
|
||||
Best for: {theme.bestFor}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Highlights */}
|
||||
{theme.highlights && theme.highlights.length > 0 && (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 4, marginBottom: 10, width: "100%" }}>
|
||||
{theme.highlights.map((h, i) => (
|
||||
<div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 6 }}>
|
||||
<span style={{ fontSize: "0.6rem", color: isActive ? "rgba(255,255,255,0.4)" : "#c5c0b8", marginTop: 2, flexShrink: 0 }}>→</span>
|
||||
<span style={{ fontSize: "0.7rem", color: isActive ? "rgba(255,255,255,0.7)" : "#4a4640", lineHeight: 1.4 }}>{h}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tags */}
|
||||
<div style={{ display: "flex", gap: 4, flexWrap: "wrap" }}>
|
||||
{theme.tags.map(t => (
|
||||
<span key={t} style={{
|
||||
fontSize: "0.6rem", fontWeight: 600, padding: "2px 6px", borderRadius: 4,
|
||||
background: isActive ? "rgba(255,255,255,0.1)" : "#f6f4f0",
|
||||
color: isActive ? "rgba(255,255,255,0.6)" : "#8a8478",
|
||||
}}>{t}</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Active indicator */}
|
||||
{isActive && !isThisLocked && (
|
||||
<div style={{ position: "absolute", top: 10, right: 12, fontSize: "0.7rem", color: "rgba(255,255,255,0.5)" }}>✓</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Color swatches */}
|
||||
{/* Color swatches — shown below the cards when available */}
|
||||
{availableColorThemes.length > 0 && (
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
||||
<span style={{ fontSize: "0.68rem", fontWeight: 600, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.08em", fontFamily: "Outfit" }}>Theme</span>
|
||||
<span style={{ fontSize: "0.68rem", fontWeight: 600, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.08em", fontFamily: "Outfit" }}>Colour</span>
|
||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center" }}>
|
||||
{availableColorThemes.map(ct => (
|
||||
<button
|
||||
@@ -228,30 +398,21 @@ function SurfaceSection({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Description + tags + docs + lock-in */}
|
||||
{/* Docs link + lock action bar */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 12, paddingTop: 4, borderTop: "1px solid #f0ece4" }}>
|
||||
{activeTheme && (
|
||||
<>
|
||||
<p style={{ flex: 1, fontSize: "0.78rem", color: "#8a8478", lineHeight: 1.5, fontFamily: "Outfit" }}>
|
||||
{activeTheme.description}
|
||||
</p>
|
||||
<div style={{ display: "flex", gap: 4 }}>
|
||||
{activeTheme.tags.map(t => (
|
||||
<span key={t} style={{ padding: "3px 8px", borderRadius: 4, fontSize: "0.65rem", fontWeight: 600, color: "#6b6560", background: "#f0ece4", fontFamily: "Outfit" }}>
|
||||
{t}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<a
|
||||
href={activeTheme.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ fontSize: "0.75rem", color: "#a09a90", textDecoration: "none", fontFamily: "Outfit", flexShrink: 0 }}
|
||||
style={{ fontSize: "0.75rem", color: "#a09a90", textDecoration: "none", fontFamily: "Outfit" }}
|
||||
onMouseEnter={e => (e.currentTarget.style.color = "#1a1a1a")}
|
||||
onMouseLeave={e => (e.currentTarget.style.color = "#a09a90")}
|
||||
>
|
||||
Docs ↗
|
||||
{activeTheme.name} docs ↗
|
||||
</a>
|
||||
<div style={{ flex: 1 }} />
|
||||
</>
|
||||
)}
|
||||
{isLocked ? (
|
||||
|
||||
Reference in New Issue
Block a user