Add live design configurator for marketing surface

Users can now compose their marketing site by selecting:
- Mode (dark/light), Background style (gradient/beams/meteors/etc.),
  Nav style, Hero header layout, which Sections appear, and Font.

All 4 marketing scaffolds (DaisyUI, HeroUI, Aceternity, Tailwind)
respond live to config changes. Library capability cards + style
options data defined per library. Aceternity shows actual
background effects (beams, meteors, sparkles, wavy, dot-grid).

Made-with: Cursor
This commit is contained in:
2026-03-05 20:15:59 -08:00
parent a980354da6
commit 9c8e1a5f34
4 changed files with 1167 additions and 186 deletions

View File

@@ -2,7 +2,10 @@
import { use, useState, useEffect } from "react";
import { toast } from "sonner";
import { SCAFFOLD_REGISTRY, THEME_REGISTRY, type ThemeColor } from "@/components/design-scaffolds";
import {
SCAFFOLD_REGISTRY, THEME_REGISTRY,
type ThemeColor, type DesignConfig, type LibraryStyleOptions,
} from "@/components/design-scaffolds";
// ---------------------------------------------------------------------------
// Surface definitions
@@ -201,6 +204,310 @@ const ALL_SURFACES: Surface[] = [
},
];
// ---------------------------------------------------------------------------
// Library style configurator options — per library, for the Marketing surface
// (other surfaces can adopt this pattern as needed)
// ---------------------------------------------------------------------------
const LIBRARY_STYLE_OPTIONS: Record<string, LibraryStyleOptions> = {
"daisy-ui": {
modes: [{ id: "light", label: "Light" }, { id: "dark", label: "Dark" }],
backgrounds: [
{ id: "solid", label: "Solid", description: "Clean theme background" },
{ id: "gradient", label: "Gradient", description: "Radial glow from primary color" },
{ id: "pattern", label: "Dot grid", description: "Subtle repeating dot pattern" },
{ id: "noise", label: "Noise", description: "Fine grain texture" },
],
navStyles: [
{ id: "standard", label: "Standard", description: "Bordered top bar" },
{ id: "transparent", label: "Transparent", description: "Overlaps the hero section" },
{ id: "pill", label: "Pill", description: "Floating centered nav" },
],
headerStyles: [
{ id: "centered", label: "Centered", description: "Title and CTAs centred" },
{ id: "split", label: "Split", description: "Left text, right mockup" },
{ id: "stats", label: "With stats", description: "Metrics row below CTAs" },
],
components: [
{ id: "logos", label: "Logo strip" },
{ id: "features", label: "Feature cards" },
{ id: "steps", label: "How it works" },
{ id: "testimonials", label: "Testimonials" },
{ id: "pricing", label: "Pricing table" },
{ id: "faq", label: "FAQ" },
{ id: "cta", label: "CTA banner" },
],
fonts: [
{ id: "system", label: "System UI" },
{ id: "plus-jakarta", label: "Plus Jakarta" },
{ id: "dm-sans", label: "DM Sans" },
{ id: "geist", label: "Geist" },
],
defaultConfig: { mode: "dark", background: "solid", nav: "standard", header: "centered", components: ["features", "pricing"], font: "system" },
},
"hero-ui": {
modes: [{ id: "light", label: "Light" }, { id: "dark", label: "Dark" }],
backgrounds: [
{ id: "clean", label: "Clean", description: "Solid background" },
{ id: "gradient-mesh", label: "Gradient mesh", description: "Soft multi-colour mesh" },
{ id: "glass", label: "Glassmorphism", description: "Frosted glass feel" },
{ id: "aurora", label: "Aurora", description: "Animated colour glow" },
],
navStyles: [
{ id: "blur", label: "Blur backdrop", description: "Frosted glass sticky navbar" },
{ id: "standard", label: "Standard", description: "Solid bordered bar" },
{ id: "minimal", label: "Minimal", description: "No border, clean" },
],
headerStyles: [
{ id: "animated-badge", label: "Animated", description: "Chip badge + gradient headline" },
{ id: "split", label: "Split", description: "Text + dashboard preview" },
{ id: "gradient", label: "Gradient", description: "Full gradient headline" },
],
components: [
{ id: "features", label: "Feature cards" },
{ id: "metrics", label: "Metrics grid" },
{ id: "avatars", label: "Social proof" },
{ id: "pricing", label: "Pricing" },
{ id: "testimonials", label: "Testimonials" },
{ id: "cta", label: "CTA section" },
],
fonts: [
{ id: "system", label: "System UI" },
{ id: "inter", label: "Inter" },
{ id: "geist", label: "Geist" },
{ id: "nunito", label: "Nunito" },
],
defaultConfig: { mode: "light", background: "clean", nav: "blur", header: "animated-badge", components: ["features", "metrics"], font: "system" },
},
"aceternity": {
modes: [{ id: "dark", label: "Dark" }, { id: "light", label: "Light (limited)" }],
backgrounds: [
{ id: "beams", label: "Beams", description: "Signature vertical beam lines" },
{ id: "meteors", label: "Meteors", description: "Shooting particle streaks" },
{ id: "sparkles", label: "Sparkles", description: "Scattered star particles" },
{ id: "wavy", label: "Wavy", description: "Smooth wave shapes" },
{ id: "dot-grid", label: "Dot grid", description: "Perspective dot matrix" },
{ id: "gradient", label: "Glow only", description: "Pure radial glow" },
],
navStyles: [
{ id: "minimal", label: "Minimal", description: "Barely-there top bar" },
{ id: "floating", label: "Floating", description: "Centred floating pill" },
],
headerStyles: [
{ id: "gradient-text", label: "Gradient text", description: "Fade-to-transparent heading" },
{ id: "lamp", label: "Lamp effect", description: "Spotlight cone from above" },
{ id: "typewriter", label: "Typewriter", description: "Animated text reveal" },
],
components: [
{ id: "badge", label: "Glow badge" },
{ id: "features", label: "Feature cards" },
{ id: "moving-cards", label: "Moving cards" },
{ id: "bento", label: "Bento grid" },
{ id: "pricing", label: "Pricing" },
{ id: "cta", label: "CTA section" },
],
fonts: [
{ id: "system", label: "System UI" },
{ id: "geist", label: "Geist" },
{ id: "plus-jakarta", label: "Plus Jakarta" },
],
defaultConfig: { mode: "dark", background: "beams", nav: "minimal", header: "gradient-text", components: ["features", "moving-cards"], font: "system" },
},
"tailwind-only": {
modes: [{ id: "light", label: "Light" }, { id: "dark", label: "Dark" }],
backgrounds: [
{ id: "clean", label: "Clean", description: "Pure white or dark" },
{ id: "dot-grid", label: "Dot grid", description: "Subtle dot pattern" },
{ id: "lines", label: "Grid lines", description: "Faint gridlines" },
{ id: "noise", label: "Noise", description: "Fine grain texture" },
],
navStyles: [
{ id: "minimal", label: "Minimal", description: "Logo + links, no decoration" },
{ id: "bordered", label: "Bordered", description: "With bottom border" },
{ id: "spaced", label: "Spread", description: "Logo left, CTA right" },
],
headerStyles: [
{ id: "editorial", label: "Editorial", description: "Big bold display typography" },
{ id: "split", label: "Split", description: "Text left + terminal preview" },
{ id: "centered", label: "Centered", description: "Minimal centred layout" },
],
components: [
{ id: "badge", label: "Release badge" },
{ id: "logos", label: "Logo strip" },
{ id: "features", label: "Features grid" },
{ id: "stats", label: "Stats row" },
{ id: "testimonials", label: "Testimonials" },
{ id: "pricing", label: "Pricing" },
{ id: "faq", label: "FAQ" },
{ id: "cta", label: "CTA" },
],
fonts: [
{ id: "system", label: "System UI" },
{ id: "inter", label: "Inter" },
{ id: "plus-jakarta", label: "Plus Jakarta" },
{ id: "dm-sans", label: "DM Sans" },
],
defaultConfig: { mode: "light", background: "clean", nav: "minimal", header: "editorial", components: ["features", "stats", "pricing"], font: "system" },
},
};
// ---------------------------------------------------------------------------
// DesignConfigurator — shows mode/bg/nav/header/components/font pickers
// ---------------------------------------------------------------------------
function ConfigRow({ label, children }: { label: string; children: React.ReactNode }) {
return (
<div style={{ display: "flex", alignItems: "flex-start", gap: 10, paddingBottom: 10, borderBottom: "1px solid #f0ece4" }}>
<span style={{ width: 88, flexShrink: 0, fontSize: "0.65rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.08em", fontFamily: "Outfit", paddingTop: 5 }}>{label}</span>
<div style={{ flex: 1, display: "flex", gap: 6, flexWrap: "wrap" }}>
{children}
</div>
</div>
);
}
function OptionChip({
label, description, active, onClick, multi, checked,
}: {
label: string; description?: string; active: boolean; onClick: () => void;
multi?: boolean; checked?: boolean;
}) {
return (
<button
onClick={onClick}
title={description}
style={{
display: "flex", alignItems: "center", gap: 5,
padding: multi ? "4px 9px" : "4px 11px",
borderRadius: 5, border: "1px solid",
fontSize: "0.72rem", fontFamily: "Outfit", cursor: "pointer",
transition: "all 0.1s",
borderColor: active ? "#1a1a1a" : "#e0dcd4",
background: active ? "#1a1a1a" : "#fff",
color: active ? "#fff" : "#4a4640",
}}
onMouseEnter={e => { if (!active) (e.currentTarget as HTMLElement).style.borderColor = "#c5c0b8"; }}
onMouseLeave={e => { if (!active) (e.currentTarget as HTMLElement).style.borderColor = "#e0dcd4"; }}
>
{multi && (
<span style={{ width: 11, height: 11, borderRadius: 2, border: `1.5px solid ${active ? "#fff" : "#c5c0b8"}`, background: checked ? (active ? "#fff" : "#1a1a1a") : "transparent", flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 7, color: checked ? (active ? "#1a1a1a" : "#fff") : "transparent" }}></span>
)}
{label}
</button>
);
}
function ModeToggle({ value, onChange }: { value: string; onChange: (v: "dark" | "light") => void }) {
return (
<div style={{ display: "inline-flex", borderRadius: 6, overflow: "hidden", border: "1px solid #e0dcd4", background: "#f8f5f0" }}>
{(["Light", "Dark"] as const).map(m => {
const id = m.toLowerCase() as "light" | "dark";
const active = value === id;
return (
<button
key={m}
onClick={() => onChange(id)}
style={{
padding: "4px 14px", border: "none", fontSize: "0.72rem", fontFamily: "Outfit",
cursor: "pointer", fontWeight: active ? 600 : 400,
background: active ? "#1a1a1a" : "transparent",
color: active ? "#fff" : "#8a8478",
transition: "all 0.1s",
}}
>
{m === "Light" ? "☀ Light" : "◗ Dark"}
</button>
);
})}
</div>
);
}
function DesignConfigurator({
libraryId,
config,
onChange,
}: {
libraryId: string;
config: DesignConfig;
onChange: (patch: Partial<DesignConfig>) => void;
}) {
const opts = LIBRARY_STYLE_OPTIONS[libraryId];
if (!opts) return null;
const toggleComponent = (id: string) => {
const next = config.components.includes(id)
? config.components.filter(c => c !== id)
: [...config.components, id];
onChange({ components: next });
};
return (
<div style={{ display: "flex", flexDirection: "column", gap: 10, padding: "14px 0 4px" }}>
{/* Mode */}
<ConfigRow label="Mode">
<ModeToggle value={config.mode} onChange={v => onChange({ mode: v })} />
</ConfigRow>
{/* Background */}
<ConfigRow label="Background">
{opts.backgrounds.map(bg => (
<OptionChip
key={bg.id} label={bg.label} description={bg.description}
active={config.background === bg.id}
onClick={() => onChange({ background: bg.id })}
/>
))}
</ConfigRow>
{/* Nav */}
<ConfigRow label="Nav style">
{opts.navStyles.map(n => (
<OptionChip
key={n.id} label={n.label} description={n.description}
active={config.nav === n.id}
onClick={() => onChange({ nav: n.id })}
/>
))}
</ConfigRow>
{/* Header */}
<ConfigRow label="Hero header">
{opts.headerStyles.map(h => (
<OptionChip
key={h.id} label={h.label} description={h.description}
active={config.header === h.id}
onClick={() => onChange({ header: h.id })}
/>
))}
</ConfigRow>
{/* Sections */}
<ConfigRow label="Sections">
{opts.components.map(c => (
<OptionChip
key={c.id} label={c.label} multi
active={config.components.includes(c.id)}
checked={config.components.includes(c.id)}
onClick={() => toggleComponent(c.id)}
/>
))}
</ConfigRow>
{/* Font */}
<ConfigRow label="Font">
{opts.fonts.map(f => (
<OptionChip
key={f.id} label={f.label}
active={config.font === f.id}
onClick={() => onChange({ font: f.id })}
/>
))}
</ConfigRow>
</div>
);
}
// ---------------------------------------------------------------------------
// Surface section
// ---------------------------------------------------------------------------
@@ -232,6 +539,22 @@ function SurfaceSection({
const [selectedColorTheme, setSelectedColorTheme] = useState<ThemeColor | null>(null);
const activeColorTheme = selectedColorTheme ?? availableColorThemes[0] ?? null;
// Design config — per-library style choices (mode, background, nav, header, sections, font)
const defaultForLibrary = previewId ? LIBRARY_STYLE_OPTIONS[previewId]?.defaultConfig : undefined;
const [designConfig, setDesignConfig] = useState<DesignConfig>(
defaultForLibrary ?? { mode: "light", background: "solid", nav: "standard", header: "centered", components: ["features", "pricing"], font: "system" }
);
// Reset config when library changes
const [lastPreviewId, setLastPreviewId] = useState<string | null>(previewId);
if (previewId !== lastPreviewId) {
setLastPreviewId(previewId);
const def = previewId ? LIBRARY_STYLE_OPTIONS[previewId]?.defaultConfig : undefined;
if (def) setDesignConfig(def);
}
const patchConfig = (patch: Partial<DesignConfig>) => setDesignConfig(prev => ({ ...prev, ...patch }));
const hasConfigurator = !!previewId && !!LIBRARY_STYLE_OPTIONS[previewId];
const isLocked = !!lockedThemeId;
return (
@@ -267,7 +590,7 @@ function SurfaceSection({
{/* Scaffold */}
<div style={{ flex: 1, overflow: "hidden" }}>
{ScaffoldComponent
? <ScaffoldComponent themeColor={activeColorTheme ?? undefined} />
? <ScaffoldComponent themeColor={activeColorTheme ?? undefined} config={designConfig} />
: (
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "#b5b0a6", fontSize: "0.82rem", fontFamily: "Outfit" }}>
Select a library below to preview
@@ -369,7 +692,16 @@ function SurfaceSection({
})}
</div>
{/* Color swatches — shown below the cards when available */}
{/* Design configurator — mode, background, nav, header, sections, font */}
{hasConfigurator && !isLocked && (
<DesignConfigurator
libraryId={previewId!}
config={designConfig}
onChange={patchConfig}
/>
)}
{/* Palette (colour) — shown after configurator */}
{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" }}>Colour</span>

View File

@@ -8,7 +8,7 @@
* 4. Add it to ALL_SURFACES in the design page
*/
export type { ThemeColor } from "./types";
export type { ThemeColor, DesignConfig, StyleOption, LibraryStyleOptions } from "./types";
export {
SHADCN_THEMES, MANTINE_THEMES, HEROUI_THEMES, TREMOR_THEMES,
DAISY_THEMES, HEROUI_MARKETING_THEMES,
@@ -21,7 +21,7 @@ import { MobileNativewind, MobileGluestack } from "./mobile";
import { EmailReactEmail } from "./email";
import { DocsNextra, DocsShadcnCustom } from "./docs";
import type { ThemeColor } from "./types";
import type { ThemeColor, DesignConfig } from "./types";
import {
SHADCN_THEMES, MANTINE_THEMES, HEROUI_THEMES, TREMOR_THEMES,
DAISY_THEMES, HEROUI_MARKETING_THEMES,
@@ -31,7 +31,7 @@ import {
// SCAFFOLD_REGISTRY — surface → library → preview component
// ---------------------------------------------------------------------------
export const SCAFFOLD_REGISTRY: Record<string, Record<string, React.ComponentType<{ themeColor?: ThemeColor }>>> = {
export const SCAFFOLD_REGISTRY: Record<string, Record<string, React.ComponentType<{ themeColor?: ThemeColor; config?: DesignConfig }>>> = {
"web-app": {
shadcn: WebAppShadcn,
mantine: WebAppMantine,

View File

@@ -1,209 +1,829 @@
"use client";
import { ThemeColor, DAISY_THEMES, HEROUI_MARKETING_THEMES } from "./types";
import { ThemeColor, DesignConfig, DAISY_THEMES, HEROUI_MARKETING_THEMES } from "./types";
// Marketing Site surface — public-facing pages: hero, features, pricing, CTA
// Context: prospective users discovering the product, not signed-in users.
// All components accept a DesignConfig to drive live preview changes.
export function MarketingDaisy({ themeColor }: { themeColor?: ThemeColor }) {
function fontStack(font?: string) {
if (font === "plus-jakarta") return '"Plus Jakarta Sans", system-ui, sans-serif';
if (font === "dm-sans") return '"DM Sans", system-ui, sans-serif';
if (font === "geist") return '"Geist", system-ui, sans-serif';
if (font === "inter") return '"Inter", system-ui, sans-serif';
if (font === "nunito") return '"Nunito", system-ui, sans-serif';
return "system-ui, sans-serif";
}
// ---------------------------------------------------------------------------
// DaisyUI
// ---------------------------------------------------------------------------
export function MarketingDaisy({ themeColor, config }: { themeColor?: ThemeColor; config?: DesignConfig }) {
const theme = themeColor ?? DAISY_THEMES[0];
const text = theme.textColor ?? "#f8f8f2";
const muted = theme.mutedText ?? "rgba(255,255,255,0.5)";
const card = theme.cardBg ?? "rgba(255,255,255,0.05)";
const border = theme.borderColor ?? "rgba(255,255,255,0.1)";
const bg = theme.bg ?? "#1d232a";
const isDark = config ? config.mode === "dark" : (theme.bg ?? "#fff").match(/^#[012]/i) !== null;
return (
<div style={{ height: "100%", fontFamily: "system-ui, sans-serif", background: bg, color: text, overflow: "auto" }}>
{/* Nav */}
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", borderBottom: `1px solid ${border}` }}>
const bg = isDark ? (theme.bg ?? "#1d232a") : (theme.bg?.match(/^#[012]/) ? "#fff" : (theme.bg ?? "#fff"));
const text = isDark ? (theme.textColor ?? "#a6adba") : (theme.textColor ?? "#1f2937");
const muted = isDark ? (theme.mutedText ?? "rgba(255,255,255,0.4)") : (theme.mutedText ?? "#6b7280");
const card = isDark ? (theme.cardBg ?? "rgba(255,255,255,0.04)") : (theme.cardBg ?? "#f9fafb");
const border = isDark ? (theme.borderColor ?? "rgba(255,255,255,0.08)") : (theme.borderColor ?? "#e5e7eb");
const bgStyle = config?.background ?? "solid";
const navStyle = config?.nav ?? "standard";
const hdrStyle = config?.header ?? "centered";
const comps = config?.components ?? ["features", "pricing"];
const ff = fontStack(config?.font);
// Background overlay applied to the hero area
const heroBgLayer =
bgStyle === "gradient" ? `radial-gradient(ellipse 80% 55% at 50% -5%, ${theme.primary}40, transparent)` :
bgStyle === "pattern" ? undefined : // handled as a full-page layer
bgStyle === "noise" ? undefined :
undefined;
const navBg = navStyle === "transparent" ? "transparent" : bg;
const navBorderB = navStyle === "transparent" ? "none" : `1px solid ${border}`;
const pillNav = navStyle === "pill";
const NavContent = () => (
<>
<div style={{ display: "flex", alignItems: "center", gap: 7 }}>
<div style={{ width: 20, height: 20, borderRadius: 4, background: theme.primary }} />
<span style={{ fontWeight: 800, fontSize: 12, color: text }}>Acme</span>
<div style={{ width: 18, height: 18, borderRadius: 4, background: theme.primary }} />
<span style={{ fontWeight: 800, fontSize: 11, color: text }}>Acme</span>
</div>
<div style={{ display: "flex", gap: 16, fontSize: 10, color: muted }}>
<div style={{ display: "flex", gap: 14, fontSize: 9.5, color: muted }}>
{["Features", "Pricing", "Docs", "Blog"].map(i => <span key={i}>{i}</span>)}
</div>
<div style={{ display: "flex", gap: 7 }}>
<button style={{ height: 26, padding: "0 12px", borderRadius: 20, fontSize: 10, fontWeight: 700, background: `${border}`, color: text, border: "none", cursor: "pointer" }}>Login</button>
<button style={{ height: 26, padding: "0 12px", borderRadius: 20, fontSize: 10, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Get started</button>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 24, padding: "0 10px", borderRadius: 16, fontSize: 9.5, fontWeight: 600, background: `${border}`, color: text, border: "none", cursor: "pointer" }}>Login</button>
<button style={{ height: 24, padding: "0 10px", borderRadius: 16, fontSize: 9.5, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Get started</button>
</div>
</nav>
</>
);
{/* Hero */}
<div style={{ padding: "28px 22px 18px", textAlign: "center" }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "3px 10px", borderRadius: 20, fontSize: 9, fontWeight: 700, marginBottom: 14, background: `${theme.primary}22`, color: theme.primary, border: `1px solid ${theme.primary}44` }}>
{theme.label} theme v2.0
return (
<div style={{ height: "100%", fontFamily: ff, background: bg, color: text, overflow: "auto", position: "relative" }}>
{/* Dot-pattern full-page overlay */}
{bgStyle === "pattern" && (
<div style={{ position: "absolute", inset: 0, backgroundImage: `radial-gradient(${theme.primary}22 1px, transparent 1px)`, backgroundSize: "18px 18px", pointerEvents: "none", zIndex: 0 }} />
)}
{/* Nav */}
{pillNav ? (
<div style={{ display: "flex", justifyContent: "center", padding: "10px 22px", position: "relative", zIndex: 2 }}>
<nav style={{ display: "flex", alignItems: "center", gap: 20, padding: "7px 18px", borderRadius: 30, background: isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)", border: `1px solid ${border}` }}>
<NavContent />
</nav>
</div>
) : (
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "9px 22px", background: navBg, borderBottom: navBorderB, position: "relative", zIndex: 2 }}>
<NavContent />
</nav>
)}
{/* Hero — centered */}
{hdrStyle === "centered" && (
<div style={{ padding: "26px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
{heroBgLayer && <div style={{ position: "absolute", inset: 0, background: heroBgLayer, pointerEvents: "none" }} />}
<div style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "3px 10px", borderRadius: 20, fontSize: 9, fontWeight: 700, marginBottom: 12, background: `${theme.primary}22`, color: theme.primary, border: `1px solid ${theme.primary}44` }}>
{theme.label} theme · v2.0
</div>
<h1 style={{ fontSize: 22, fontWeight: 900, marginBottom: 8, color: text, lineHeight: 1.15 }}>Build faster,<br />ship smarter</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 260, margin: "0 auto 18px", lineHeight: 1.6 }}>The all-in-one platform that helps teams build, launch, and scale their products.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginBottom: 22 }}>
<button style={{ height: 32, padding: "0 18px", borderRadius: 20, fontSize: 10, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Start for free</button>
<button style={{ height: 32, padding: "0 18px", borderRadius: 20, fontSize: 10, fontWeight: 700, border: `1px solid ${border}`, color: text, background: "none", cursor: "pointer" }}>See demo </button>
<p style={{ fontSize: 10, color: muted, maxWidth: 240, margin: "0 auto 16px", lineHeight: 1.6 }}>The all-in-one platform that helps teams build, launch, and scale.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
<button style={{ height: 30, padding: "0 16px", borderRadius: 20, fontSize: 9.5, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Start for free</button>
<button style={{ height: 30, padding: "0 16px", borderRadius: 20, fontSize: 9.5, border: `1px solid ${border}`, color: text, background: "none", cursor: "pointer" }}>See demo </button>
</div>
</div>
)}
{/* Feature cards */}
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, padding: "0 22px 18px" }}>
{[{ icon: "⚡", title: "Lightning fast", desc: "Deploy in seconds" }, { icon: "🔒", title: "Secure by default", desc: "Enterprise-grade security" }, { icon: "📈", title: "Scales with you", desc: "From zero to millions" }].map(f => (
<div key={f.title} style={{ padding: "12px 14px", borderRadius: 12, textAlign: "center", background: card, border: `1px solid ${border}` }}>
<div style={{ fontSize: 18, marginBottom: 5 }}>{f.icon}</div>
<p style={{ fontSize: 10, fontWeight: 700, color: text, marginBottom: 3 }}>{f.title}</p>
<p style={{ fontSize: 9, color: muted }}>{f.desc}</p>
{/* Hero — split layout */}
{hdrStyle === "split" && (
<div style={{ display: "flex", gap: 14, padding: "22px 22px 14px", alignItems: "center", position: "relative", zIndex: 1 }}>
{heroBgLayer && <div style={{ position: "absolute", inset: 0, background: heroBgLayer, pointerEvents: "none" }} />}
<div style={{ flex: 1 }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "2px 8px", borderRadius: 16, fontSize: 8.5, fontWeight: 700, marginBottom: 10, background: `${theme.primary}22`, color: theme.primary, border: `1px solid ${theme.primary}44` }}> New · v2.0</div>
<h1 style={{ fontSize: 19, fontWeight: 900, marginBottom: 8, color: text, lineHeight: 1.2 }}>Build faster,<br />ship smarter</h1>
<p style={{ fontSize: 9.5, color: muted, marginBottom: 14, lineHeight: 1.6 }}>The platform teams trust to ship faster.</p>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 28, padding: "0 14px", borderRadius: 18, fontSize: 9, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Start free</button>
<button style={{ height: 28, padding: "0 12px", borderRadius: 18, fontSize: 9, border: `1px solid ${border}`, color: text, background: "none", cursor: "pointer" }}>Demo </button>
</div>
</div>
<div style={{ width: 130, flexShrink: 0, borderRadius: 10, overflow: "hidden", border: `1px solid ${border}`, background: card, boxShadow: "0 4px 16px rgba(0,0,0,0.12)" }}>
<div style={{ height: 18, display: "flex", alignItems: "center", gap: 4, padding: "0 8px", background: isDark ? "rgba(255,255,255,0.04)" : "#f5f5f5", borderBottom: `1px solid ${border}` }}>
{["#ff5f56","#ffbd2e","#27c93f"].map(c => <div key={c} style={{ width: 5, height: 5, borderRadius: "50%", background: c }} />)}
</div>
<div style={{ padding: 8 }}>
{["Revenue $12k","Users 2.8k","Growth +24%"].map(m => (
<div key={m} style={{ marginBottom: 6, padding: "5px 7px", borderRadius: 6, background: `${theme.primary}10`, border: `1px solid ${theme.primary}22` }}>
<p style={{ fontSize: 7.5, color: muted }}>{m.split(" ")[0]}</p>
<p style={{ fontSize: 11, fontWeight: 700, color: text }}>{m.split(" ")[1]}</p>
</div>
))}
</div>
</div>
</div>
)}
{/* Pricing strip */}
<div style={{ padding: "0 22px" }}>
<div style={{ borderRadius: 12, padding: "14px 16px", background: card, border: `1px solid ${border}` }}>
{/* Hero — with stats */}
{hdrStyle === "stats" && (
<div style={{ padding: "22px 22px 12px", textAlign: "center", position: "relative", zIndex: 1 }}>
{heroBgLayer && <div style={{ position: "absolute", inset: 0, background: heroBgLayer, pointerEvents: "none" }} />}
<h1 style={{ fontSize: 21, fontWeight: 900, marginBottom: 8, color: text, lineHeight: 1.15 }}>Build faster,<br />ship smarter</h1>
<p style={{ fontSize: 9.5, color: muted, maxWidth: 220, margin: "0 auto 14px", lineHeight: 1.6 }}>Trusted by thousands of teams worldwide.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginBottom: 16 }}>
<button style={{ height: 28, padding: "0 14px", borderRadius: 20, fontSize: 9.5, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Start free</button>
<button style={{ height: 28, padding: "0 12px", borderRadius: 20, fontSize: 9.5, border: `1px solid ${border}`, color: text, background: "none", cursor: "pointer" }}>Demo </button>
</div>
<div style={{ display: "flex", justifyContent: "center", gap: 20 }}>
{[["50k+","Teams"],["99.9%","Uptime"],["10ms","Latency"]].map(([v, l]) => (
<div key={l} style={{ textAlign: "center" }}>
<p style={{ fontSize: 16, fontWeight: 800, color: theme.primary }}>{v}</p>
<p style={{ fontSize: 8.5, color: muted }}>{l}</p>
</div>
))}
</div>
</div>
)}
{/* Conditional sections */}
{comps.includes("logos") && (
<div style={{ padding: "8px 22px", display: "flex", alignItems: "center", gap: 12, overflow: "hidden", position: "relative", zIndex: 1 }}>
<span style={{ fontSize: 8, color: muted, whiteSpace: "nowrap" }}>Trusted by</span>
{["Vercel","Stripe","Linear","Notion","Supabase"].map(b => (
<span key={b} style={{ fontSize: 9, fontWeight: 700, color: muted, opacity: 0.6, whiteSpace: "nowrap" }}>{b}</span>
))}
</div>
)}
{comps.includes("features") && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, padding: "12px 22px", position: "relative", zIndex: 1 }}>
{[{ icon: "⚡", title: "Lightning fast", desc: "Deploy in seconds" }, { icon: "🔒", title: "Secure by default", desc: "Enterprise-grade" }, { icon: "📈", title: "Scales with you", desc: "From 0 to millions" }].map(f => (
<div key={f.title} style={{ padding: "10px 12px", borderRadius: 10, textAlign: "center", background: card, border: `1px solid ${border}` }}>
<div style={{ fontSize: 16, marginBottom: 4 }}>{f.icon}</div>
<p style={{ fontSize: 9.5, fontWeight: 700, color: text, marginBottom: 2 }}>{f.title}</p>
<p style={{ fontSize: 8.5, color: muted }}>{f.desc}</p>
</div>
))}
</div>
)}
{comps.includes("steps") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 10, fontWeight: 700, color: text, marginBottom: 10 }}>How it works</p>
<div style={{ display: "flex", gap: 0 }}>
{["Connect your repo","Configure your stack","Deploy in seconds"].map((s, i) => (
<div key={s} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 6 }}>
<div style={{ width: 22, height: 22, borderRadius: "50%", background: theme.primary, color: theme.primaryFg, fontSize: 10, fontWeight: 800, display: "flex", alignItems: "center", justifyContent: "center" }}>{i + 1}</div>
<p style={{ fontSize: 8.5, color: muted, lineHeight: 1.4 }}>{s}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("testimonials") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
{[{ q: "\"Deployed in 5 minutes. Incredible.\"", name: "Sarah K.", role: "CTO, Startup" }, { q: "\"Cut our infra costs by 40%.\"", name: "James R.", role: "Eng Lead" }].map(t => (
<div key={t.name} style={{ padding: "10px 12px", borderRadius: 10, background: card, border: `1px solid ${border}` }}>
<p style={{ fontSize: 8.5, color: muted, marginBottom: 8, lineHeight: 1.5 }}>{t.q}</p>
<p style={{ fontSize: 8.5, fontWeight: 700, color: text }}>{t.name}</p>
<p style={{ fontSize: 7.5, color: muted }}>{t.role}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("pricing") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 10, fontWeight: 700, color: text, marginBottom: 8 }}>Simple pricing</p>
<div style={{ display: "flex", gap: 8 }}>
{[{ plan: "Starter", price: "Free", highlight: false }, { plan: "Pro", price: "$29/mo", highlight: true }, { plan: "Enterprise", price: "Custom", highlight: false }].map(p => (
<div key={p.plan} style={{ flex: 1, padding: "8px 10px", borderRadius: 8, background: p.highlight ? theme.primary : "transparent", border: `1px solid ${p.highlight ? "transparent" : border}`, textAlign: "center" }}>
<p style={{ fontSize: 9, fontWeight: 600, color: p.highlight ? theme.primaryFg : muted, marginBottom: 2 }}>{p.plan}</p>
<p style={{ fontSize: 8.5, fontWeight: 600, color: p.highlight ? theme.primaryFg : muted, marginBottom: 2 }}>{p.plan}</p>
<p style={{ fontSize: 13, fontWeight: 800, color: p.highlight ? theme.primaryFg : text }}>{p.price}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("faq") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 10, fontWeight: 700, color: text, marginBottom: 8 }}>FAQ</p>
{["What's included in the free plan?","Can I upgrade anytime?","Do you offer team billing?"].map((q, i) => (
<div key={q} style={{ padding: "7px 0", borderBottom: `1px solid ${border}`, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style={{ fontSize: 9, color: i === 0 ? text : muted }}>{q}</span>
<span style={{ fontSize: 9, color: muted }}>{i === 0 ? "" : "+"}</span>
</div>
))}
</div>
)}
{comps.includes("cta") && (
<div style={{ margin: "12px 22px 18px", padding: "14px 18px", borderRadius: 12, background: `${theme.primary}14`, border: `1px solid ${theme.primary}30`, textAlign: "center", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 12, fontWeight: 800, color: text, marginBottom: 4 }}>Ready to ship faster?</p>
<p style={{ fontSize: 9, color: muted, marginBottom: 12 }}>Join 50,000+ teams already on Acme.</p>
<button style={{ height: 28, padding: "0 16px", borderRadius: 20, fontSize: 9.5, fontWeight: 700, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Get started free </button>
</div>
)}
<div style={{ height: 20 }} />
</div>
);
}
export function MarketingHeroUI({ themeColor }: { themeColor?: ThemeColor }) {
// ---------------------------------------------------------------------------
// HeroUI
// ---------------------------------------------------------------------------
export function MarketingHeroUI({ themeColor, config }: { themeColor?: ThemeColor; config?: DesignConfig }) {
const theme = themeColor ?? HEROUI_MARKETING_THEMES[0];
const bg = theme.bg ?? "#fff";
const text = theme.textColor ?? "#18181b";
const muted = theme.mutedText ?? "#71717a";
const card = theme.cardBg ?? "#fff";
const border = theme.borderColor ?? "#f4f4f5";
const isDark = config ? config.mode === "dark" : (theme.bg ?? "#fff") === "#09090b";
const bg = isDark ? (theme.bg ?? "#09090b") : (theme.bg ?? "#fff");
const text = isDark ? (theme.textColor ?? "#f4f4f5") : (theme.textColor ?? "#18181b");
const muted = isDark ? (theme.mutedText ?? "#71717a") : (theme.mutedText ?? "#71717a");
const card = isDark ? (theme.cardBg ?? "#18181b") : (theme.cardBg ?? "#fafafa");
const border = isDark ? (theme.borderColor ?? "#27272a") : (theme.borderColor ?? "#f4f4f5");
const bgStyle = config?.background ?? "clean";
const navStyle = config?.nav ?? "blur";
const hdrStyle = config?.header ?? "animated-badge";
const comps = config?.components ?? ["features", "metrics"];
const ff = fontStack(config?.font);
const navBlur = navStyle === "blur";
const navBg = navBlur
? (isDark ? "rgba(9,9,11,0.7)" : "rgba(255,255,255,0.7)")
: navStyle === "minimal" ? "transparent"
: bg;
const navBorderB = navStyle === "minimal" ? "none" : `1px solid ${border}`;
const heroBgOverlay =
bgStyle === "gradient-mesh" ? `radial-gradient(ellipse 70% 60% at 30% 40%, ${theme.primary}25, transparent 60%), radial-gradient(ellipse 50% 50% at 80% 60%, ${isDark ? "#06b6d422" : "#06b6d418"}, transparent 60%)` :
bgStyle === "glass" ? `linear-gradient(135deg, ${theme.primary}14, ${isDark ? "#18181b" : "#fff"} 60%)` :
bgStyle === "aurora" ? `radial-gradient(ellipse 80% 60% at 50% -10%, ${theme.primary}35, transparent 70%)` :
undefined;
return (
<div style={{ height: "100%", fontFamily: "system-ui, sans-serif", background: bg, overflow: "auto" }}>
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", borderBottom: `1px solid ${border}` }}>
<div style={{ height: "100%", fontFamily: ff, background: bg, overflow: "auto", position: "relative" }}>
{heroBgOverlay && <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 260, background: heroBgOverlay, pointerEvents: "none", zIndex: 0 }} />}
{/* Nav */}
<nav style={{
display: "flex", alignItems: "center", justifyContent: "space-between",
padding: "9px 22px", borderBottom: navBorderB, position: "sticky", top: 0, zIndex: 10,
background: navBg,
backdropFilter: navBlur ? "blur(12px)" : undefined,
WebkitBackdropFilter: navBlur ? "blur(12px)" : undefined,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 7 }}>
<div style={{ width: 20, height: 20, borderRadius: "50%", background: theme.primary }} />
<div style={{ width: 18, height: 18, borderRadius: "50%", background: theme.primary }} />
<span style={{ fontWeight: 800, fontSize: 11, color: text }}>Acme</span>
</div>
<div style={{ display: "flex", gap: 14, fontSize: 10, color: muted }}>
<div style={{ display: "flex", gap: 14, fontSize: 9.5, color: muted }}>
{["Features","Pricing","Docs","Blog"].map(i => <span key={i}>{i}</span>)}
</div>
<div style={{ display: "flex", gap: 7 }}>
<button style={{ height: 26, padding: "0 12px", borderRadius: 20, border: `1px solid ${border}`, fontSize: 10, background: "none", color: muted, cursor: "pointer" }}>Login</button>
<button style={{ height: 26, padding: "0 12px", borderRadius: 20, fontSize: 10, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer" }}>Get started</button>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 24, padding: "0 10px", borderRadius: 16, border: `1px solid ${border}`, fontSize: 9.5, background: "none", color: muted, cursor: "pointer" }}>Login</button>
<button style={{ height: 24, padding: "0 10px", borderRadius: 16, fontSize: 9.5, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer", boxShadow: `0 2px 10px ${theme.ring}` }}>Get started</button>
</div>
</nav>
<div style={{ padding: "26px 22px 16px", textAlign: "center" }}>
{/* Hero — animated badge style */}
{hdrStyle === "animated-badge" && (
<div style={{ padding: "24px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "3px 10px", borderRadius: 20, fontSize: 9, fontWeight: 600, marginBottom: 14, background: theme.activeBg, color: theme.activeFg, border: `1px solid ${theme.ring}` }}>
🚀 {theme.label} theme v2.0
🚀 Now in public beta
</div>
<h1 style={{ fontSize: 22, fontWeight: 900, color: theme.primary, marginBottom: 8, lineHeight: 1.15 }}>Build faster,<br />ship smarter</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 260, margin: "0 auto 16px", lineHeight: 1.6 }}>The all-in-one platform for teams that move fast.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginBottom: 18 }}>
<button style={{ height: 32, padding: "0 18px", borderRadius: 20, fontSize: 10, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer", boxShadow: `0 4px 14px ${theme.ring}` }}>Start for free</button>
<button style={{ height: 32, padding: "0 18px", borderRadius: 20, fontSize: 10, background: "none", border: `1px solid ${border}`, color: muted, cursor: "pointer" }}>Live demo </button>
<p style={{ fontSize: 10, color: muted, maxWidth: 240, margin: "0 auto 16px", lineHeight: 1.6 }}>The all-in-one platform for teams that move fast.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
<button style={{ height: 30, padding: "0 16px", borderRadius: 20, fontSize: 9.5, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer", boxShadow: `0 4px 14px ${theme.ring}` }}>Start for free</button>
<button style={{ height: 30, padding: "0 14px", borderRadius: 20, fontSize: 9.5, background: "none", border: `1px solid ${border}`, color: muted, cursor: "pointer" }}>Live demo </button>
</div>
</div>
)}
{/* Dashboard preview card */}
<div style={{ borderRadius: 16, overflow: "hidden", border: `1px solid ${border}`, maxWidth: 340, margin: "0 auto", background: card, boxShadow: `0 8px 30px rgba(0,0,0,0.08)` }}>
<div style={{ height: 22, display: "flex", alignItems: "center", gap: 5, padding: "0 10px", background: bg === "#09090b" ? "#27272a" : "#fafafa", borderBottom: `1px solid ${border}` }}>
{["#ff5f56", "#ffbd2e", "#27c93f"].map(c => <div key={c} style={{ width: 7, height: 7, borderRadius: "50%", background: c }} />)}
{/* Hero — split layout */}
{hdrStyle === "split" && (
<div style={{ display: "flex", gap: 14, padding: "20px 22px 14px", alignItems: "center", position: "relative", zIndex: 1 }}>
<div style={{ flex: 1 }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "2px 8px", borderRadius: 12, fontSize: 8.5, fontWeight: 600, marginBottom: 10, background: theme.activeBg, color: theme.activeFg }}>🚀 Beta</div>
<h1 style={{ fontSize: 20, fontWeight: 900, color: theme.primary, marginBottom: 8, lineHeight: 1.2 }}>Build faster,<br />ship smarter</h1>
<p style={{ fontSize: 9.5, color: muted, marginBottom: 14, lineHeight: 1.6 }}>The platform for fast-moving teams.</p>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 28, padding: "0 14px", borderRadius: 18, fontSize: 9, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer", boxShadow: `0 2px 10px ${theme.ring}` }}>Start free</button>
<button style={{ height: 28, padding: "0 12px", borderRadius: 18, fontSize: 9, border: `1px solid ${border}`, color: muted, background: "none", cursor: "pointer" }}>Demo </button>
</div>
<div style={{ padding: 12 }}>
</div>
<div style={{ width: 130, flexShrink: 0, borderRadius: 12, overflow: "hidden", border: `1px solid ${border}`, boxShadow: `0 8px 24px rgba(0,0,0,0.12)`, background: card }}>
<div style={{ height: 18, display: "flex", alignItems: "center", gap: 4, padding: "0 8px", background: isDark ? "#27272a" : "#fafafa", borderBottom: `1px solid ${border}` }}>
{["#ff5f56","#ffbd2e","#27c93f"].map(c => <div key={c} style={{ width: 5, height: 5, borderRadius: "50%", background: c }} />)}
</div>
<div style={{ padding: 8 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 5 }}>
{["Revenue $12k","Users 2.8k","Growth +24%","Churn 2.1%"].map(m => (
<div key={m} style={{ padding: "5px 6px", borderRadius: 7, background: theme.activeBg, border: `1px solid ${theme.ring}` }}>
<p style={{ fontSize: 7.5, color: muted }}>{m.split(" ")[0]}</p>
<p style={{ fontSize: 10, fontWeight: 700, color: text }}>{m.split(" ")[1]}</p>
</div>
))}
</div>
</div>
</div>
</div>
)}
{/* Hero — gradient headline */}
{hdrStyle === "gradient" && (
<div style={{ padding: "28px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<h1 style={{ fontSize: 24, fontWeight: 900, lineHeight: 1.1, marginBottom: 10, background: `linear-gradient(135deg, ${theme.primary}, ${isDark ? "#06b6d4" : "#7c3aed"})`, WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
Build faster.<br />Ship smarter.
</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 240, margin: "0 auto 16px", lineHeight: 1.6 }}>Everything your team needs in one platform.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
<button style={{ height: 30, padding: "0 16px", borderRadius: 20, fontSize: 9.5, fontWeight: 600, background: `linear-gradient(135deg, ${theme.primary}, #06b6d4)`, color: "#fff", border: "none", cursor: "pointer" }}>Get started </button>
</div>
</div>
)}
{/* Conditional sections */}
{comps.includes("features") && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, padding: "10px 22px", position: "relative", zIndex: 1 }}>
{[{ icon: "⚡", title: "10x faster deploys" }, { icon: "🔒", title: "Zero-trust security" }, { icon: "📦", title: "Any stack" }, { icon: "🌍", title: "Global CDN" }].map(f => (
<div key={f.title} style={{ padding: "10px 12px", borderRadius: 10, background: card, border: `1px solid ${border}`, display: "flex", alignItems: "center", gap: 8 }}>
<span style={{ fontSize: 16 }}>{f.icon}</span>
<p style={{ fontSize: 9.5, fontWeight: 600, color: text }}>{f.title}</p>
</div>
))}
</div>
)}
{comps.includes("metrics") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ padding: "12px 16px", borderRadius: 12, border: `1px solid ${border}`, background: card, boxShadow: `0 4px 20px rgba(0,0,0,0.06)` }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
{["Revenue $12k","Users 2.8k","Growth +24%","Churn 2.1%"].map((m, i) => (
<div key={m} style={{ padding: "8px 10px", borderRadius: 10, background: theme.activeBg, border: `1px solid ${theme.ring}` }}>
<p style={{ fontSize: 9, color: muted, marginBottom: 2 }}>{m.split(" ")[0]}</p>
<p style={{ fontSize: 13, fontWeight: 700, color: text }}>{m.split(" ")[1]}</p>
<p style={{ fontSize: 14, fontWeight: 700, color: text }}>{m.split(" ")[1]}</p>
</div>
))}
</div>
</div>
</div>
)}
{comps.includes("avatars") && (
<div style={{ padding: "10px 22px", display: "flex", alignItems: "center", gap: 10, position: "relative", zIndex: 1 }}>
<div style={{ display: "flex" }}>
{["#7c3aed","#2563eb","#0d9488","#e11d48"].map((c, i) => (
<div key={c} style={{ width: 22, height: 22, borderRadius: "50%", background: c, border: `2px solid ${bg}`, marginLeft: i > 0 ? -8 : 0 }} />
))}
</div>
<span style={{ fontSize: 9, color: muted }}>Trusted by <strong style={{ color: text }}>50,000+</strong> teams</span>
</div>
)}
{comps.includes("pricing") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "flex", gap: 8 }}>
{[{ plan: "Starter", price: "Free", hi: false }, { plan: "Pro", price: "$29/mo", hi: true }, { plan: "Enterprise", price: "Custom", hi: false }].map(p => (
<div key={p.plan} style={{ flex: 1, padding: "10px", borderRadius: 10, background: p.hi ? theme.primary : card, border: `1px solid ${p.hi ? "transparent" : border}`, textAlign: "center", boxShadow: p.hi ? `0 4px 14px ${theme.ring}` : "none" }}>
<p style={{ fontSize: 8.5, fontWeight: 600, color: p.hi ? theme.primaryFg : muted, marginBottom: 3 }}>{p.plan}</p>
<p style={{ fontSize: 14, fontWeight: 800, color: p.hi ? theme.primaryFg : text }}>{p.price}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("testimonials") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
{[{ q: "\"Shipped 3x faster since switching.\"", name: "Sarah K." }, { q: "\"Cut infra costs by 40%.\"", name: "James R." }].map(t => (
<div key={t.name} style={{ padding: "10px", borderRadius: 10, background: card, border: `1px solid ${border}` }}>
<p style={{ fontSize: 8.5, color: muted, marginBottom: 6, lineHeight: 1.5 }}>{t.q}</p>
<p style={{ fontSize: 8.5, fontWeight: 600, color: text }}>{t.name}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("cta") && (
<div style={{ margin: "12px 22px 18px", padding: "14px 18px", borderRadius: 12, background: `linear-gradient(135deg, ${theme.primary}18, ${theme.ring}22)`, border: `1px solid ${theme.ring}`, textAlign: "center", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 12, fontWeight: 800, color: text, marginBottom: 4 }}>Ready to ship faster?</p>
<p style={{ fontSize: 9, color: muted, marginBottom: 10 }}>Join 50,000+ teams already on Acme.</p>
<button style={{ height: 28, padding: "0 16px", borderRadius: 20, fontSize: 9.5, fontWeight: 600, background: theme.primary, color: theme.primaryFg, border: "none", cursor: "pointer", boxShadow: `0 2px 10px ${theme.ring}` }}>Get started free </button>
</div>
)}
<div style={{ height: 20 }} />
</div>
);
}
export function MarketingAceternity() {
return (
<div style={{ height: "100%", fontFamily: "system-ui, sans-serif", background: "#030303", overflow: "auto" }}>
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", borderBottom: "1px solid rgba(255,255,255,0.06)" }}>
<div style={{ display: "flex", alignItems: "center", gap: 7 }}>
<div style={{ width: 20, height: 20, borderRadius: 4, background: "linear-gradient(135deg,#a855f7,#3b82f6)" }} />
<span style={{ fontWeight: 800, fontSize: 11, color: "#fff" }}>Acme</span>
// ---------------------------------------------------------------------------
// Aceternity UI
// ---------------------------------------------------------------------------
export function MarketingAceternity({ config }: { themeColor?: ThemeColor; config?: DesignConfig }) {
const isDark = config?.mode !== "light";
const bgStyle = config?.background ?? "beams";
const navStyle = config?.nav ?? "minimal";
const hdrStyle = config?.header ?? "gradient-text";
const comps = config?.components ?? ["features", "moving-cards"];
const ff = fontStack(config?.font);
const bg = isDark ? "#030303" : "#f8fafc";
const text = isDark ? "#fff" : "#0f172a";
const muted = isDark ? "rgba(255,255,255,0.38)" : "#64748b";
const card = isDark ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.03)";
const border= isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.08)";
// Background effects rendered as CSS
const BackgroundEffect = () => {
if (bgStyle === "beams") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none", zIndex: 0 }}>
{/* Vertical beam lines */}
{Array.from({ length: 8 }).map((_, i) => (
<div key={i} style={{ position: "absolute", top: 0, bottom: 0, width: 1, left: `${10 + i * 12}%`, background: `linear-gradient(180deg, transparent, ${i % 2 === 0 ? "rgba(168,85,247,0.15)" : "rgba(59,130,246,0.1)"}, transparent)` }} />
))}
<div style={{ position: "absolute", inset: 0, background: "radial-gradient(ellipse 70% 50% at 50% 0%, rgba(168,85,247,0.12), transparent)" }} />
</div>
<div style={{ display: "flex", gap: 14, fontSize: 10, color: "rgba(255,255,255,0.4)" }}>
);
if (bgStyle === "meteors") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none", zIndex: 0 }}>
<div style={{ position: "absolute", inset: 0, background: "radial-gradient(ellipse 60% 40% at 50% 0%, rgba(168,85,247,0.1), transparent)" }} />
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} style={{ position: "absolute", top: `${5 + i * 12}%`, left: `${10 + i * 15}%`, width: 1, height: `${20 + i * 8}px`, background: "linear-gradient(180deg, #a855f7, transparent)", transform: "rotate(-35deg)", opacity: 0.4 + i * 0.08 }} />
))}
</div>
);
if (bgStyle === "sparkles") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none", zIndex: 0 }}>
{Array.from({ length: 20 }).map((_, i) => (
<div key={i} style={{ position: "absolute", width: 3, height: 3, borderRadius: "50%", background: i % 3 === 0 ? "#a855f7" : i % 3 === 1 ? "#3b82f6" : "#22c55e", top: `${(i * 37) % 90}%`, left: `${(i * 53) % 90}%`, opacity: 0.3 + (i % 4) * 0.15 }} />
))}
</div>
);
if (bgStyle === "wavy") return (
<div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 200, overflow: "hidden", pointerEvents: "none", zIndex: 0 }}>
<svg viewBox="0 0 400 100" preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}>
<path d="M0,50 Q50,20 100,50 T200,50 T300,50 T400,50 L400,100 L0,100 Z" fill="rgba(168,85,247,0.06)" />
<path d="M0,60 Q60,30 120,60 T240,60 T360,60 T400,60 L400,100 L0,100 Z" fill="rgba(59,130,246,0.05)" />
</svg>
</div>
);
if (bgStyle === "dot-grid") return (
<div style={{ position: "absolute", inset: 0, backgroundImage: "radial-gradient(rgba(168,85,247,0.2) 1px, transparent 1px)", backgroundSize: "20px 20px", pointerEvents: "none", zIndex: 0 }} />
);
// gradient (default radial glow)
return <div style={{ position: "absolute", inset: 0, background: "radial-gradient(ellipse 70% 50% at 50% 0%, rgba(168,85,247,0.15), transparent)", pointerEvents: "none", zIndex: 0 }} />;
};
const floatingNav = navStyle === "floating";
return (
<div style={{ height: "100%", fontFamily: ff, background: bg, overflow: "auto", position: "relative" }}>
<BackgroundEffect />
{/* Nav */}
{floatingNav ? (
<div style={{ display: "flex", justifyContent: "center", padding: "10px 22px", position: "relative", zIndex: 10 }}>
<nav style={{ display: "flex", alignItems: "center", gap: 18, padding: "7px 18px", borderRadius: 30, background: "rgba(168,85,247,0.1)", border: "1px solid rgba(168,85,247,0.25)" }}>
<span style={{ fontWeight: 800, fontSize: 11, color: text }}>Acme</span>
{["Features","Pricing","Docs"].map(i => <span key={i} style={{ fontSize: 9.5, color: muted }}>{i}</span>)}
<button style={{ height: 22, padding: "0 10px", borderRadius: 12, fontSize: 9, fontWeight: 600, color: "#fff", background: "rgba(168,85,247,0.4)", border: "1px solid rgba(168,85,247,0.4)", cursor: "pointer" }}>Get started</button>
</nav>
</div>
) : (
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", borderBottom: `1px solid ${border}`, position: "relative", zIndex: 10 }}>
<div style={{ display: "flex", alignItems: "center", gap: 7 }}>
<div style={{ width: 18, height: 18, borderRadius: 4, background: "linear-gradient(135deg,#a855f7,#3b82f6)" }} />
<span style={{ fontWeight: 800, fontSize: 11, color: text }}>Acme</span>
</div>
<div style={{ display: "flex", gap: 14, fontSize: 9.5, color: muted }}>
{["Features","Pricing","Docs"].map(i => <span key={i}>{i}</span>)}
</div>
<button style={{ height: 26, padding: "0 12px", borderRadius: 5, fontSize: 10, fontWeight: 600, color: "#fff", background: "rgba(168,85,247,0.2)", border: "1px solid rgba(168,85,247,0.3)", cursor: "pointer" }}>Get started</button>
<button style={{ height: 24, padding: "0 10px", borderRadius: 5, fontSize: 9.5, fontWeight: 600, color: "#fff", background: "rgba(168,85,247,0.2)", border: "1px solid rgba(168,85,247,0.3)", cursor: "pointer" }}>Get started</button>
</nav>
<div style={{ position: "relative", padding: "28px 22px 18px", textAlign: "center", overflow: "hidden" }}>
<div style={{ position: "absolute", inset: 0, background: "radial-gradient(ellipse 60% 40% at 50% 0%,rgba(168,85,247,0.15),transparent)", pointerEvents: "none" }} />
)}
{/* Hero — gradient text */}
{hdrStyle === "gradient-text" && (
<div style={{ padding: "26px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "3px 10px", borderRadius: 20, fontSize: 9, fontWeight: 500, marginBottom: 14, border: "1px solid rgba(168,85,247,0.3)", color: "rgba(168,85,247,0.9)" }}>
Open source · 12k GitHub stars
Open source · 12k stars
</div>
<h1 style={{ fontSize: 22, fontWeight: 900, marginBottom: 8, lineHeight: 1.15, background: "linear-gradient(180deg,#fff 0%,rgba(255,255,255,0.5) 100%)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
<h1 style={{ fontSize: 22, fontWeight: 900, marginBottom: 8, lineHeight: 1.15, background: isDark ? "linear-gradient(180deg,#fff 0%,rgba(255,255,255,0.5) 100%)" : "linear-gradient(180deg,#0f172a 0%,rgba(15,23,42,0.5) 100%)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
Build the future<br />of the web
</h1>
<p style={{ fontSize: 10, color: "rgba(255,255,255,0.35)", maxWidth: 240, margin: "0 auto 18px", lineHeight: 1.6 }}>Beautifully crafted components built with Tailwind CSS and Framer Motion.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginBottom: 22 }}>
<button style={{ height: 32, padding: "0 18px", borderRadius: 6, fontSize: 10, fontWeight: 600, color: "#fff", background: "linear-gradient(135deg,#a855f7,#3b82f6)", border: "none", cursor: "pointer" }}>Get started </button>
<button style={{ height: 32, padding: "0 18px", borderRadius: 6, fontSize: 10, color: "rgba(255,255,255,0.6)", border: "1px solid rgba(255,255,255,0.1)", background: "none", cursor: "pointer" }}>View components</button>
<p style={{ fontSize: 10, color: muted, maxWidth: 230, margin: "0 auto 16px", lineHeight: 1.6 }}>Beautifully crafted components built with Tailwind CSS and Framer Motion.</p>
<div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
<button style={{ height: 30, padding: "0 16px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, color: "#fff", background: "linear-gradient(135deg,#a855f7,#3b82f6)", border: "none", cursor: "pointer" }}>Get started </button>
<button style={{ height: 30, padding: "0 14px", borderRadius: 6, fontSize: 9.5, color: muted, border: `1px solid ${border}`, background: "none", cursor: "pointer" }}>View components</button>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8 }}>
{["Animated", "Accessible", "Open source"].map((f, i) => (
<div key={f} style={{ padding: "10px 12px", borderRadius: 10, textAlign: "left", background: "rgba(255,255,255,0.03)", border: "1px solid rgba(255,255,255,0.06)" }}>
<div style={{ width: 20, height: 20, borderRadius: 5, marginBottom: 6, background: ["rgba(168,85,247,0.15)", "rgba(59,130,246,0.15)", "rgba(34,197,94,0.15)"][i], display: "flex", alignItems: "center", justifyContent: "center" }}>
<div style={{ width: 8, height: 8, borderRadius: "50%", background: ["#a855f7", "#3b82f6", "#22c55e"][i] }} />
</div>
<p style={{ fontSize: 9, fontWeight: 600, color: "#fff", marginBottom: 2 }}>{f}</p>
<p style={{ fontSize: 9, color: "rgba(255,255,255,0.3)" }}>Built for production</p>
)}
{/* Hero — lamp effect */}
{hdrStyle === "lamp" && (
<div style={{ padding: "20px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<div style={{ position: "absolute", top: 0, left: "50%", transform: "translateX(-50%)", width: 200, height: 60, background: "radial-gradient(ellipse at top, rgba(168,85,247,0.4), transparent 70%)", borderRadius: "0 0 100px 100px", pointerEvents: "none" }} />
<div style={{ width: 80, height: 1, background: "linear-gradient(90deg, transparent, #a855f7, transparent)", margin: "0 auto 16px" }} />
<h1 style={{ fontSize: 22, fontWeight: 900, color: text, marginBottom: 8, lineHeight: 1.15 }}>Build the future<br />of the web</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 220, margin: "0 auto 14px", lineHeight: 1.6 }}>Powered by Framer Motion and Tailwind CSS.</p>
<button style={{ height: 30, padding: "0 16px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, color: "#fff", background: "linear-gradient(135deg,#a855f7,#3b82f6)", border: "none", cursor: "pointer" }}>Get started </button>
</div>
)}
{/* Hero — typewriter */}
{hdrStyle === "typewriter" && (
<div style={{ padding: "26px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<div style={{ fontSize: 9, color: "rgba(168,85,247,0.7)", letterSpacing: "0.2em", marginBottom: 12 }}>THE FUTURE IS HERE</div>
<h1 style={{ fontSize: 20, fontWeight: 900, color: text, marginBottom: 8, lineHeight: 1.2 }}>
Build the future<br />
<span style={{ background: "linear-gradient(90deg,#a855f7,#3b82f6)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>of the web_</span>
</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 220, margin: "0 auto 14px", lineHeight: 1.6 }}>Components that bring your ideas to life.</p>
<button style={{ height: 30, padding: "0 16px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, color: "#fff", background: "linear-gradient(135deg,#a855f7,#3b82f6)", border: "none", cursor: "pointer" }}>Get started </button>
</div>
)}
{/* Conditional sections */}
{comps.includes("features") && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, padding: "10px 22px", position: "relative", zIndex: 1 }}>
{[{ label: "Animated", color: "#a855f7" }, { label: "Accessible", color: "#3b82f6" }, { label: "Open source", color: "#22c55e" }].map(f => (
<div key={f.label} style={{ padding: "10px 12px", borderRadius: 10, background: card, border: `1px solid ${border}` }}>
<div style={{ width: 18, height: 18, borderRadius: 5, marginBottom: 6, background: `${f.color}22`, display: "flex", alignItems: "center", justifyContent: "center" }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: f.color }} />
</div>
<p style={{ fontSize: 9.5, fontWeight: 600, color: text, marginBottom: 2 }}>{f.label}</p>
<p style={{ fontSize: 8.5, color: muted }}>Built for production</p>
</div>
))}
</div>
)}
{comps.includes("badge") && (
<div style={{ padding: "8px 22px", textAlign: "center", position: "relative", zIndex: 1 }}>
<span style={{ display: "inline-block", padding: "4px 12px", borderRadius: 20, fontSize: 9, border: "1px solid rgba(168,85,247,0.4)", color: "rgba(168,85,247,0.9)", background: "rgba(168,85,247,0.08)" }}> v2.0 just shipped see what's new →</span>
</div>
)}
{comps.includes("moving-cards") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1, overflow: "hidden" }}>
<p style={{ fontSize: 9, color: muted, marginBottom: 8, textAlign: "center" }}>What our users say</p>
<div style={{ display: "flex", gap: 10, overflow: "hidden" }}>
{[{ text: "\"Game changer for our team.\"", name: "Sarah K." }, { text: "\"Ships 3x faster.\"", name: "James R." }, { text: "\"Zero-config deploys.\"", name: "Mia L." }].map(t => (
<div key={t.name} style={{ minWidth: 140, padding: "10px 12px", borderRadius: 10, background: card, border: `1px solid rgba(168,85,247,0.12)`, flexShrink: 0 }}>
<p style={{ fontSize: 8.5, color: muted, marginBottom: 6, lineHeight: 1.5 }}>{t.text}</p>
<p style={{ fontSize: 8.5, fontWeight: 600, color: text }}>— {t.name}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("bento") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gridTemplateRows: "auto auto", gap: 8 }}>
<div style={{ padding: "14px", borderRadius: 12, background: card, border: `1px solid rgba(168,85,247,0.12)`, gridRow: "1 / 3" }}>
<p style={{ fontSize: 10, fontWeight: 700, color: text, marginBottom: 4 }}>Analytics</p>
<div style={{ height: 40, background: "linear-gradient(to right, rgba(168,85,247,0.2), rgba(59,130,246,0.2))", borderRadius: 6, marginTop: 8 }} />
</div>
<div style={{ padding: "10px", borderRadius: 12, background: card, border: `1px solid ${border}` }}>
<p style={{ fontSize: 9, fontWeight: 600, color: text }}>Deploys</p>
<p style={{ fontSize: 16, fontWeight: 800, color: "#a855f7" }}>∞</p>
</div>
<div style={{ padding: "10px", borderRadius: 12, background: card, border: `1px solid ${border}` }}>
<p style={{ fontSize: 9, fontWeight: 600, color: text }}>Uptime</p>
<p style={{ fontSize: 14, fontWeight: 800, color: "#22c55e" }}>99.9%</p>
</div>
</div>
</div>
)}
{comps.includes("pricing") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "flex", gap: 8 }}>
{[{ plan: "Starter", price: "Free", hi: false }, { plan: "Pro", price: "$29/mo", hi: true }, { plan: "Enterprise", price: "Custom", hi: false }].map(p => (
<div key={p.plan} style={{ flex: 1, padding: "10px", borderRadius: 10, background: p.hi ? "linear-gradient(135deg,rgba(168,85,247,0.25),rgba(59,130,246,0.2))" : card, border: `1px solid ${p.hi ? "rgba(168,85,247,0.4)" : border}`, textAlign: "center" }}>
<p style={{ fontSize: 8.5, fontWeight: 600, color: p.hi ? "#c084fc" : muted, marginBottom: 2 }}>{p.plan}</p>
<p style={{ fontSize: 13, fontWeight: 800, color: text }}>{p.price}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("cta") && (
<div style={{ margin: "12px 22px 18px", padding: "14px 18px", borderRadius: 12, background: "linear-gradient(135deg,rgba(168,85,247,0.12),rgba(59,130,246,0.1))", border: "1px solid rgba(168,85,247,0.2)", textAlign: "center", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 12, fontWeight: 800, color: text, marginBottom: 4 }}>Start building today</p>
<p style={{ fontSize: 9, color: muted, marginBottom: 10 }}>Join thousands of developers worldwide.</p>
<button style={{ height: 28, padding: "0 16px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, color: "#fff", background: "linear-gradient(135deg,#a855f7,#3b82f6)", border: "none", cursor: "pointer" }}>Get started →</button>
</div>
)}
<div style={{ height: 20 }} />
</div>
);
}
export function MarketingTailwind() {
// ---------------------------------------------------------------------------
// Tailwind only
// ---------------------------------------------------------------------------
export function MarketingTailwind({ config }: { themeColor?: ThemeColor; config?: DesignConfig }) {
const isDark = config?.mode === "dark";
const bgStyle = config?.background ?? "clean";
const navStyle = config?.nav ?? "minimal";
const hdrStyle = config?.header ?? "editorial";
const comps = config?.components ?? ["features", "stats", "pricing"];
const ff = fontStack(config?.font);
const bg = isDark ? "#09090b" : "#fff";
const text = isDark ? "#f4f4f5" : "#09090b";
const muted = isDark ? "#71717a" : "#71717a";
const card = isDark ? "#18181b" : "#f9fafb";
const border= isDark ? "#27272a" : "#e5e7eb";
const accent = "#7c3aed";
const navBg = navStyle === "minimal" ? "transparent" : bg;
const navBorderB = navStyle === "minimal" ? "none" : `1px solid ${border}`;
return (
<div style={{ height: "100%", fontFamily: "system-ui, sans-serif", background: "#fff", overflow: "auto" }}>
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", borderBottom: "1px solid #e5e7eb" }}>
<span style={{ fontWeight: 900, fontSize: 12, color: "#09090b" }}>acme</span>
<div style={{ display: "flex", gap: 14, fontSize: 10, color: "#71717a" }}>
<div style={{ height: "100%", fontFamily: ff, background: bg, overflow: "auto", position: "relative" }}>
{/* Background effects */}
{bgStyle === "dot-grid" && (
<div style={{ position: "absolute", inset: 0, backgroundImage: `radial-gradient(${isDark ? "#ffffff18" : "#00000018"} 1px, transparent 1px)`, backgroundSize: "16px 16px", pointerEvents: "none" }} />
)}
{bgStyle === "lines" && (
<div style={{ position: "absolute", inset: 0, backgroundImage: `linear-gradient(${isDark ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.04)"} 1px, transparent 1px), linear-gradient(90deg, ${isDark ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.04)"} 1px, transparent 1px)`, backgroundSize: "24px 24px", pointerEvents: "none" }} />
)}
{bgStyle === "noise" && (
<div style={{ position: "absolute", inset: 0, opacity: 0.03, backgroundImage: "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")", pointerEvents: "none" }} />
)}
{/* Nav */}
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 22px", background: navBg, borderBottom: navBorderB, position: "relative", zIndex: 2 }}>
<span style={{ fontWeight: 900, fontSize: 12, color: text, letterSpacing: navStyle === "minimal" ? "0.05em" : 0 }}>acme</span>
<div style={{ display: "flex", gap: 14, fontSize: 9.5, color: muted }}>
{["Features","Pricing","Blog"].map(i => <span key={i}>{i}</span>)}
</div>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 26, padding: "0 10px", fontSize: 10, color: "#71717a", background: "none", border: "none", cursor: "pointer" }}>Log in</button>
<button style={{ height: 26, padding: "0 12px", borderRadius: 5, fontSize: 10, fontWeight: 500, background: "#09090b", color: "#fff", border: "none", cursor: "pointer" }}>Sign up</button>
<button style={{ height: 24, padding: "0 10px", fontSize: 9.5, color: muted, background: "none", border: "none", cursor: "pointer" }}>Log in</button>
<button style={{ height: 24, padding: "0 10px", borderRadius: 5, fontSize: 9.5, fontWeight: 500, background: text, color: bg, border: "none", cursor: "pointer" }}>Sign up</button>
</div>
</nav>
<div style={{ padding: "28px 22px" }}>
<div style={{ maxWidth: 320 }}>
<span style={{ fontSize: 9, fontWeight: 600, color: "#7c3aed", letterSpacing: "0.12em", textTransform: "uppercase" }}>Now in public beta</span>
<h1 style={{ fontSize: 22, fontWeight: 900, color: "#09090b", marginTop: 4, marginBottom: 8, lineHeight: 1.15 }}>The platform<br />built for scale</h1>
<p style={{ fontSize: 10, color: "#71717a", marginBottom: 18, lineHeight: 1.6 }}>Everything your team needs to build, deploy, and monitor production applications.</p>
<div style={{ display: "flex", gap: 8, marginBottom: 24 }}>
<button style={{ height: 30, padding: "0 14px", borderRadius: 6, fontSize: 10, fontWeight: 500, background: "#09090b", color: "#fff", border: "none", cursor: "pointer" }}>Get started free</button>
<button style={{ height: 30, padding: "0 14px", borderRadius: 6, fontSize: 10, fontWeight: 500, border: "1px solid #e5e7eb", color: "#71717a", background: "none", cursor: "pointer" }}>Documentation </button>
{/* Hero — editorial big type */}
{hdrStyle === "editorial" && (
<div style={{ padding: "28px 22px 16px", position: "relative", zIndex: 1 }}>
<span style={{ fontSize: 8.5, fontWeight: 600, color: accent, letterSpacing: "0.14em", textTransform: "uppercase" }}>Now in public beta</span>
<h1 style={{ fontSize: 26, fontWeight: 900, color: text, marginTop: 6, marginBottom: 10, lineHeight: 1.05, letterSpacing: "-0.02em" }}>The platform<br />built for scale</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 260, marginBottom: 16, lineHeight: 1.6 }}>Everything your team needs to build, deploy, and monitor production applications.</p>
<div style={{ display: "flex", gap: 8 }}>
<button style={{ height: 30, padding: "0 14px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, background: text, color: bg, border: "none", cursor: "pointer" }}>Get started free</button>
<button style={{ height: 30, padding: "0 14px", borderRadius: 6, fontSize: 9.5, border: `1px solid ${border}`, color: muted, background: "none", cursor: "pointer" }}>Documentation </button>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
{["99.9% uptime SLA", "10ms avg latency", "SOC2 compliant", "GDPR ready"].map(f => (
<div key={f} style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 9, color: "#71717a" }}>
<div style={{ width: 14, height: 14, borderRadius: "50%", background: "#09090b", flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ color: "#fff", fontSize: 8, lineHeight: 1 }}></span>
</div>
{f}
)}
{/* Hero — split */}
{hdrStyle === "split" && (
<div style={{ display: "flex", gap: 16, padding: "22px 22px 14px", alignItems: "flex-start", position: "relative", zIndex: 1 }}>
<div style={{ flex: 1 }}>
<span style={{ fontSize: 8.5, fontWeight: 600, color: accent, letterSpacing: "0.12em", textTransform: "uppercase" }}>Public beta</span>
<h1 style={{ fontSize: 20, fontWeight: 900, color: text, marginTop: 5, marginBottom: 8, lineHeight: 1.15, letterSpacing: "-0.01em" }}>The platform<br />built for scale</h1>
<p style={{ fontSize: 9.5, color: muted, marginBottom: 14, lineHeight: 1.6 }}>Deploy anywhere. Monitor everything.</p>
<div style={{ display: "flex", gap: 6 }}>
<button style={{ height: 28, padding: "0 12px", borderRadius: 6, fontSize: 9, fontWeight: 600, background: text, color: bg, border: "none", cursor: "pointer" }}>Get started</button>
<button style={{ height: 28, padding: "0 10px", borderRadius: 6, fontSize: 9, border: `1px solid ${border}`, color: muted, background: "none", cursor: "pointer" }}>Docs </button>
</div>
</div>
<div style={{ width: 120, flexShrink: 0, borderRadius: 8, overflow: "hidden", border: `1px solid ${border}`, background: card }}>
<div style={{ height: 16, display: "flex", alignItems: "center", gap: 3, padding: "0 6px", background: isDark ? "#27272a" : "#f5f5f5", borderBottom: `1px solid ${border}` }}>
{["#ff5f56","#ffbd2e","#27c93f"].map(c => <div key={c} style={{ width: 5, height: 5, borderRadius: "50%", background: c }} />)}
</div>
<div style={{ padding: 7, fontFamily: "monospace", fontSize: 7.5, color: muted, lineHeight: 1.8 }}>
<div style={{ color: "#22c55e" }}> Build complete</div>
<div> Deploying</div>
<div style={{ color: "#3b82f6" }}> Live in 2.1s</div>
</div>
</div>
</div>
)}
{/* Hero — centered minimal */}
{hdrStyle === "centered" && (
<div style={{ padding: "32px 22px 16px", textAlign: "center", position: "relative", zIndex: 1 }}>
<h1 style={{ fontSize: 22, fontWeight: 900, color: text, marginBottom: 8, lineHeight: 1.1, letterSpacing: "-0.02em" }}>The platform<br />built for scale</h1>
<p style={{ fontSize: 10, color: muted, maxWidth: 240, margin: "0 auto 16px", lineHeight: 1.6 }}>Everything your team needs.</p>
<button style={{ height: 30, padding: "0 16px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, background: text, color: bg, border: "none", cursor: "pointer" }}>Get started free </button>
</div>
)}
{/* Conditional sections */}
{comps.includes("badge") && (
<div style={{ padding: "6px 22px", position: "relative", zIndex: 1 }}>
<span style={{ display: "inline-block", padding: "3px 10px", borderRadius: 4, fontSize: 8.5, background: `${accent}14`, color: accent, fontWeight: 500 }}> v2.0 released see what's new</span>
</div>
)}
{comps.includes("logos") && (
<div style={{ padding: "8px 22px", display: "flex", alignItems: "center", gap: 12, overflow: "hidden", position: "relative", zIndex: 1 }}>
<span style={{ fontSize: 8, color: muted, whiteSpace: "nowrap" }}>Trusted by</span>
{["Vercel","Stripe","Linear","Notion","Supabase"].map(b => (
<span key={b} style={{ fontSize: 8.5, fontWeight: 700, color: muted, opacity: 0.5, whiteSpace: "nowrap" }}>{b}</span>
))}
</div>
)}
{comps.includes("features") && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, padding: "12px 22px", position: "relative", zIndex: 1 }}>
{[{ title: "99.9% uptime SLA", desc: "Enterprise reliability" }, { title: "10ms avg latency", desc: "Edge-first network" }, { title: "SOC2 compliant", desc: "Security baked in" }, { title: "GDPR ready", desc: "Privacy by default" }].map(f => (
<div key={f.title} style={{ display: "flex", alignItems: "flex-start", gap: 8, padding: "8px", borderRadius: 8, background: card, border: `1px solid ${border}` }}>
<div style={{ width: 14, height: 14, borderRadius: "50%", background: text, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center", marginTop: 1 }}>
<span style={{ color: bg, fontSize: 7, lineHeight: 1 }}>✓</span>
</div>
<div>
<p style={{ fontSize: 9, fontWeight: 600, color: text, marginBottom: 1 }}>{f.title}</p>
<p style={{ fontSize: 8.5, color: muted }}>{f.desc}</p>
</div>
</div>
))}
</div>
)}
{comps.includes("stats") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "flex", gap: 0, borderRadius: 10, overflow: "hidden", border: `1px solid ${border}` }}>
{[["50k+","Teams"],["99.9%","Uptime"],["10ms","Latency"],["$0","To start"]].map(([v, l], i) => (
<div key={l} style={{ flex: 1, textAlign: "center", padding: "10px 4px", borderRight: i < 3 ? `1px solid ${border}` : "none", background: i % 2 === 0 ? card : bg }}>
<p style={{ fontSize: 15, fontWeight: 800, color: text }}>{v}</p>
<p style={{ fontSize: 7.5, color: muted }}>{l}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("testimonials") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
{[{ q: "\"Shipped 3x faster.\"", name: "Sarah K.", role: "CTO" }, { q: "\"Cut costs by 40%.\"", name: "James R.", role: "Eng Lead" }].map(t => (
<div key={t.name} style={{ padding: "10px", borderRadius: 8, background: card, border: `1px solid ${border}` }}>
<p style={{ fontSize: 9, color: muted, marginBottom: 8, lineHeight: 1.5 }}>{t.q}</p>
<p style={{ fontSize: 8.5, fontWeight: 600, color: text }}>{t.name} · <span style={{ fontWeight: 400, color: muted }}>{t.role}</span></p>
</div>
))}
</div>
</div>
)}
{comps.includes("pricing") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
<div style={{ display: "flex", gap: 8 }}>
{[{ plan: "Starter", price: "Free", hi: false }, { plan: "Pro", price: "$29/mo", hi: true }, { plan: "Enterprise", price: "Custom", hi: false }].map(p => (
<div key={p.plan} style={{ flex: 1, padding: "10px", borderRadius: 8, background: p.hi ? text : card, border: `1px solid ${p.hi ? "transparent" : border}`, textAlign: "center" }}>
<p style={{ fontSize: 8.5, fontWeight: 500, color: p.hi ? bg : muted, marginBottom: 3 }}>{p.plan}</p>
<p style={{ fontSize: 14, fontWeight: 800, color: p.hi ? bg : text }}>{p.price}</p>
</div>
))}
</div>
</div>
)}
{comps.includes("faq") && (
<div style={{ padding: "10px 22px", position: "relative", zIndex: 1 }}>
{["What's included in free?","Can I upgrade anytime?","Do you offer team plans?"].map((q, i) => (
<div key={q} style={{ padding: "7px 0", borderBottom: `1px solid ${border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontSize: 9, color: i === 0 ? text : muted }}>{q}</span>
<span style={{ fontSize: 9, color: muted }}>{i === 0 ? "" : "+"}</span>
</div>
))}
</div>
)}
{comps.includes("cta") && (
<div style={{ margin: "12px 22px 18px", padding: "16px 18px", borderRadius: 10, background: text, textAlign: "center", position: "relative", zIndex: 1 }}>
<p style={{ fontSize: 12, fontWeight: 800, color: bg, marginBottom: 4 }}>Ready to ship faster?</p>
<p style={{ fontSize: 9, color: isDark ? "#71717a" : "#9ca3af", marginBottom: 10 }}>Join 50,000+ teams already on Acme.</p>
<button style={{ height: 28, padding: "0 14px", borderRadius: 6, fontSize: 9.5, fontWeight: 600, background: bg, color: text, border: "none", cursor: "pointer" }}>Get started free </button>
</div>
)}
<div style={{ height: 20 }} />
</div>
);
}

View File

@@ -19,6 +19,35 @@ export interface ThemeColor {
mutedText?: string;
}
// ---------------------------------------------------------------------------
// Design configurator types — used by the surface configurator and scaffolds
// ---------------------------------------------------------------------------
export interface StyleOption {
id: string;
label: string;
description?: string;
}
export interface LibraryStyleOptions {
modes: StyleOption[];
backgrounds: StyleOption[];
navStyles: StyleOption[];
headerStyles: StyleOption[];
components: StyleOption[];
fonts: StyleOption[];
defaultConfig: DesignConfig;
}
export interface DesignConfig {
mode: "dark" | "light";
background: string;
nav: string;
header: string;
components: string[];
font: string;
}
// Shared mock data
export const TABLE_ROWS = [
{ name: "Alice Martin", email: "alice@co.com", role: "Admin", status: "Active", date: "Jan 12" },