design: integrate Name workspace step into the path, pre-seed name from description, and remove redundant vibe and choice stages

This commit is contained in:
2026-06-08 12:23:14 -07:00
parent 00243cbc73
commit 1756778a54
2 changed files with 58 additions and 118 deletions

View File

@@ -6,10 +6,11 @@ import {
WizardFooter,
LANE_LABELS,
PresetGroup,
Field,
} from "./onboarding-primitives";
const ENTREP_TOTAL = 4;
const ENTREP_STEP_NAMES = ["Type", "Idea", "Status", "Look"];
const ENTREP_STEP_NAMES = ["Type", "Idea", "Status", "Name"];
const IDEA_PROMPTS = [
"A community for indie game devs to swap playtesters, with weekly demo nights",
@@ -197,123 +198,47 @@ function EntrepStatus({ value, onChange }) {
}))}
value={value}
onChange={onChange}
columns={3}
columns={1}
minimal={false}
/>
</>
);
}
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 EntrepName({ value, onChange, ideaDescription }) {
// Pre-fill the workspace name from what they typed, or fall back
const trimmed = String(value || "").trim();
const slug = trimmed
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 32);
function EntrepVibe({ value, onChange }) {
return (
<>
<WizardQ
title="Pick a starting vibe."
sub="Every color and font is a tweak away once the site is live."
title="Name your workspace"
sub="This is your home base. You can rename it later."
/>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gap: 10,
}}
>
{VIBES.map((v) => {
const active = value === v.id;
return (
<button
key={v.id}
type="button"
onClick={() => onChange(v.id)}
style={{
padding: "10px 10px 10px",
borderRadius: 11,
border: `1px solid ${active ? "var(--accent)" : "var(--hairline)"}`,
background: active
? "oklch(0.20 0.04 35 / 0.4)"
: "oklch(0.18 0.009 60 / 0.6)",
boxShadow: active
? "0 0 0 3px oklch(0.74 0.175 35 / 0.1)"
: "none",
textAlign: "left",
color: "var(--fg)",
display: "flex",
flexDirection: "column",
gap: 8,
transition: "border-color .15s, background .15s",
}}
>
<span
style={{
height: 52,
borderRadius: 7,
background: v.swatch,
border: "1px solid oklch(1 0 0 / 0.08)",
boxShadow: "inset 0 1px 0 oklch(1 0 0 / 0.18)",
}}
/>
<span
style={{
fontSize: 13,
fontWeight: 500,
letterSpacing: "-0.005em",
}}
>
{v.name}
</span>
<span
style={{
fontSize: 11.5,
color: "var(--fg-mute)",
lineHeight: 1.4,
}}
>
{v.desc}
</span>
</button>
);
})}
</div>
<Field label="Workspace name">
<input
type="text"
className="wiz-input"
placeholder="My Workspace"
value={value}
autoFocus
maxLength={48}
onChange={(e) => onChange(e.target.value)}
/>
</Field>
{slug && (
<div
className="mono"
style={{ marginTop: 4, fontSize: 12.5, color: "var(--fg-mute)" }}
>
vibnai.com/<span style={{ color: "var(--accent)" }}>{slug}</span>
</div>
)}
</>
);
}
@@ -337,9 +262,8 @@ export function EntrepreneurPath({
else onJumpToStep(step - 1);
};
let body,
canNext,
onSkip = null;
let body, canNext;
const onSkip = null;
if (step === 0) {
body = (
<EntrepType
@@ -352,7 +276,21 @@ export function EntrepreneurPath({
body = (
<EntrepIdea
value={data.idea || ""}
onChange={(v) => onUpdate({ idea: v })}
onChange={(v) => {
const words = v
.trim()
.split(/\s+/)
.slice(0, 4)
.join(" ")
.replace(/[^a-zA-Z0-9\s]/g, "");
const cleanName = words
? words.charAt(0).toUpperCase() + words.slice(1)
: "";
onUpdate({
idea: v,
...(!data.bizName ? { bizName: cleanName } : {}),
});
}}
/>
);
canNext = (data.idea || "").trim().length >= 8;
@@ -366,13 +304,13 @@ export function EntrepreneurPath({
canNext = !!data.projectStatus;
} else {
body = (
<EntrepVibe value={data.vibe} onChange={(v) => onUpdate({ vibe: v })} />
<EntrepName
value={data.bizName || ""}
onChange={(v) => onUpdate({ bizName: v })}
ideaDescription={data.idea || ""}
/>
);
canNext = !!data.vibe;
onSkip = () => {
onUpdate({ vibe: "later" });
next();
};
canNext = (data.bizName || "").trim().length > 0;
}
// 5 total: fork(1) + 4 path steps

View File

@@ -95,7 +95,9 @@ export default function OnboardingApp() {
setStage("fork");
setStep(0);
};
const completePath = () => setStage("choice");
const completePath = () => {
finishNaming(String(data.bizName || ""));
};
const openWorkspace = () => {
if (createdSlug && typeof window !== "undefined") {
window.location.href = "/" + createdSlug; // Route directly to their live chat workspace!