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:
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
Reference in New Issue
Block a user