design: add dynamic design-style layout selector for saas, marketplace, and websites

This commit is contained in:
2026-06-08 11:23:01 -07:00
parent fa2e08ea42
commit 32124555ab

View File

@@ -18,7 +18,7 @@ import {
// Entrepreneur path — 4 steps. Each step is a focused question. // Entrepreneur path — 4 steps. Each step is a focused question.
const ENTREP_TOTAL = 4; const ENTREP_TOTAL = 4;
const ENTREP_STEP_NAMES = ["Type", "Idea", "Goal", "Look"]; const ENTREP_STEP_NAMES = ["Type", "Idea", "Style", "Look"];
const IDEA_PROMPTS = [ const IDEA_PROMPTS = [
"A community for indie game devs to swap playtesters, with weekly demo nights", "A community for indie game devs to swap playtesters, with weekly demo nights",
@@ -172,62 +172,88 @@ function EntrepType({ value, onChange }) {
); );
} }
const GOALS = [ const SAAS_STYLES = [
{ {
id: "first_customer", id: "sidebar",
icon: "🎯", label: "Vertical Sidebar",
label: "First real customer", desc: "Left-side collapsible menu, data-dense. Ideal for CRM/dashboards.",
desc: "Someone I don't know pays me. Even once.",
}, },
{ {
id: "ten_users", id: "topbar",
icon: "👥", label: "Top Horizontal + ⌘K",
label: "Ten weekly users", desc: "Spacious top navigation with global command search bar.",
desc: "A signal the thing actually does something useful.",
}, },
{ {
id: "mrr_1k", id: "rail",
icon: "📈", label: "Slim Icon Rail",
label: "$1k MRR", desc: "Minimalist vertical narrow icon bar, maximizes workspace area.",
desc: "Enough to take it seriously.",
},
{
id: "side_quit",
icon: "🚪",
label: "Replace my day job",
desc: "The long road. Make this the main thing.",
},
{
id: "audience",
icon: "📣",
label: "Build a tiny audience",
desc: "200 emails, a community, something I can talk to.",
},
{
id: "ship_it",
icon: "🚀",
label: "Just ship it",
desc: "I want the thing to exist.",
}, },
]; ];
function EntrepGoal({ value, onChange }) { const MARKETPLACE_STYLES = [
{
id: "flux",
label: "Dark Glass / Flux",
desc: "Modern dark-glass panels with glowing fuchsia aurora backdrops.",
},
{
id: "minimal",
label: "Classic Minimal",
desc: "Warm parchment neutrals, high-contrast typography and clean grids.",
},
];
const GENERAL_STYLES = [
{
id: "bento",
label: "Dark Bento",
desc: "Modern dark UI, bento-box card clusters.",
},
{
id: "swiss",
label: "Editorial Swiss",
desc: "Type-led, gridded, lots of white space — clean and academic.",
},
{
id: "brutalist",
label: "Neo-Brutalist",
desc: "Bold offsets, thick hand-drawn borders, highly tactile and organic.",
},
];
function EntrepStyle({ productType, value, onChange }) {
// Dynamically tailor the styles array based on what they picked on Page 2
const isSaas = productType === "saas";
const isMarketplace = productType === "marketplace";
const styles = isSaas
? SAAS_STYLES
: isMarketplace
? MARKETPLACE_STYLES
: GENERAL_STYLES;
return ( return (
<> <>
<WizardQ <WizardQ
title="What does “working” look like?" title="Choose a starting design style"
sub="Helps Vibn decide what to build first — a landing page that converts, or a tool that retains." sub={
isSaas
? "Select the navigation layout that fits your app's density."
: isMarketplace
? "Select the design aesthetic for your marketplace templates."
: "Select the design layout for your custom pages."
}
/> />
<PresetGroup <PresetGroup
options={GOALS.map((g) => ({ options={styles.map((s) => ({
id: g.id, id: s.id,
label: g.label, label: s.label,
desc: g.desc, desc: s.desc,
icon: <span style={{ fontSize: 14 }}>{g.icon}</span>, icon: undefined,
}))} }))}
value={value} value={value}
onChange={onChange} onChange={onChange}
columns={2} columns={styles.length === 3 ? 1 : 2}
/> />
</> </>
); );
@@ -387,9 +413,13 @@ export function EntrepreneurPath({
canNext = (data.idea || "").trim().length >= 8; canNext = (data.idea || "").trim().length >= 8;
} else if (step === 2) { } else if (step === 2) {
body = ( body = (
<EntrepGoal value={data.goal} onChange={(v) => onUpdate({ goal: v })} /> <EntrepStyle
productType={data.productType}
value={data.designStyle || ""}
onChange={(v) => onUpdate({ designStyle: v })}
/>
); );
canNext = !!data.goal; canNext = !!data.designStyle;
} else { } else {
body = ( body = (
<EntrepVibe value={data.vibe} onChange={(v) => onUpdate({ vibe: v })} /> <EntrepVibe value={data.vibe} onChange={(v) => onUpdate({ vibe: v })} />