// Entrepreneur path β 4 steps. Each step is a focused question.
const ENTREP_TOTAL = 4;
const ENTREP_STEP_NAMES = ["Idea", "Audience", "Goal", "Look"];
const IDEA_PROMPTS = [
"A community for indie game devs to swap playtesters, with weekly demo nights",
"An AI tool that turns my handwritten recipe notes into a clean cookbook for my family",
"A waitlist + scheduler for my pottery studio β small classes, six people max",
"A subscription box service for cold-brew enthusiasts, with monthly tasting cards",
"A simple tool that turns my Strava data into framed art prints I can sell",
];
function EntrepIdea({ value, onChange }) {
const [phIdx, setPhIdx] = React.useState(0);
const [phChars, setPhChars] = React.useState(0);
const [deleting, setDeleting] = React.useState(false);
React.useEffect(() => {
if (value.length > 0) return undefined;
const full = IDEA_PROMPTS[phIdx];
const speed = deleting ? 18 : 38;
const t = setTimeout(() => {
if (!deleting) {
if (phChars < full.length) setPhChars(phChars + 1);
else setTimeout(() => setDeleting(true), 1500);
} else {
if (phChars > 0) setPhChars(phChars - 1);
else { setDeleting(false); setPhIdx((phIdx + 1) % IDEA_PROMPTS.length); }
}
}, speed);
return () => clearTimeout(t);
}, [value, phIdx, phChars, deleting]);
return (
<>
{value.length} chars Β· be specific where it matters
>
);
}
const AUDIENCE_PRESETS = [
"Me and people like me",
"A small community I'm part of",
"Local people in my city",
"Anyone searching for this",
"Other small businesses",
"Hobbyists in a niche I love",
];
function EntrepAudience({ value, onChange }) {
const isPreset = AUDIENCE_PRESETS.includes(value);
return (
<>
onChange(arr[arr.length - 1] || "")}
/>
onChange(e.target.value)}
/>
>
);
}
const GOALS = [
{ id: "first_customer", icon: "π―", label: "First real customer",
desc: "Someone I don't know pays me. Even once." },
{ id: "ten_users", icon: "π₯", label: "Ten weekly users",
desc: "A signal the thing actually does something useful." },
{ id: "mrr_1k", icon: "π", label: "$1k MRR",
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 }) {
return (
<>
({
id: g.id, label: g.label, desc: g.desc,
icon: {g.icon},
}))}
value={value}
onChange={onChange}
columns={2}
/>
>
);
}
const VIBES = [
{ id: "warm", name: "Warm coral", swatch: "linear-gradient(135deg, #E27855, #B33B2A)",
desc: "Confident, hand-built, warm." },
{ id: "ink", name: "Ink & paper", swatch: "linear-gradient(135deg, #1d1d1d, #4a4a4a)",
desc: "Editorial, serif, quiet." },
{ id: "sage", name: "Sage matte", swatch: "linear-gradient(135deg, #7BA890, #3F6B57)",
desc: "Calm, modern, slightly herbal." },
{ id: "neon", name: "Neon arcade", swatch: "linear-gradient(135deg, #5B6CFF, #FF3DDB)",
desc: "Loud, fun, late-night." },
{ id: "cream", name: "Cream linen", swatch: "linear-gradient(135deg, #F2E7D5, #C9A977)",
desc: "Cozy and beige." },
{ id: "later", name: "Decide later", swatch: "repeating-linear-gradient(45deg, oklch(0.30 0.010 60), oklch(0.30 0.010 60) 6px, oklch(0.22 0.010 60) 6px, oklch(0.22 0.010 60) 12px)",
desc: "Vibn picks one that fits." },
];
function EntrepVibe({ value, onChange }) {
return (
<>
{VIBES.map((v) => {
const active = value === v.id;
return (
);
})}
>
);
}
// ββ Path wrapper βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
function EntrepreneurPath({ data, onUpdate, onBack, onClose, onComplete, onJumpToStep, step }) {
const next = () => {
if (step < ENTREP_TOTAL - 1) onJumpToStep(step + 1);
else onComplete();
};
const back = () => {
if (step === 0) onBack();
else onJumpToStep(step - 1);
};
let body, canNext, onSkip = null;
if (step === 0) {
body = onUpdate({ idea: v })} />;
canNext = (data.idea || "").trim().length >= 8;
} else if (step === 1) {
body = onUpdate({ audience: v })} />;
canNext = (data.audience || "").trim().length >= 3;
} else if (step === 2) {
body = onUpdate({ goal: v })} />;
canNext = !!data.goal;
} else {
body = onUpdate({ vibe: v })} />;
canNext = !!data.vibe;
onSkip = () => { onUpdate({ vibe: "later" }); next(); };
}
// 5 total: fork(1) + 4 path steps
return (
<>
{body}
>
);
}
Object.assign(window, { EntrepreneurPath, ENTREP_TOTAL });