207 lines
5.7 KiB
TypeScript
207 lines
5.7 KiB
TypeScript
import React, {
|
|
useState,
|
|
useEffect,
|
|
useRef,
|
|
useMemo,
|
|
useCallback,
|
|
} from "react";
|
|
import {
|
|
WizardTop,
|
|
WizardBody,
|
|
WizardQ,
|
|
WizardFooter,
|
|
} from "./onboarding-primitives";
|
|
// Step 1: the only branching question — "which describes you?"
|
|
// Quiet radio-style cards. No quotes, no marketing, no glow theatrics.
|
|
|
|
const FORKS = [
|
|
{
|
|
id: "entrepreneur",
|
|
label: "I am building a tool to market to many users",
|
|
hint: "Launch a SaaS, platform, or app with a public audience.",
|
|
icon: (
|
|
<svg
|
|
width="18"
|
|
height="18"
|
|
viewBox="0 0 18 18"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.6"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<circle cx="9" cy="9" r="3" />
|
|
<path d="M9 2.5v2M9 13.5v2M2.5 9h2M13.5 9h2" />
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
id: "owner",
|
|
label: "I'm building an internal tool for my work or business",
|
|
hint: "Automate your operations or replace the software you rent.",
|
|
icon: (
|
|
<svg
|
|
width="18"
|
|
height="18"
|
|
viewBox="0 0 18 18"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.6"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<path d="M3 6h12l-1 9H4L3 6Z" />
|
|
<path d="M6 6V4.5a3 3 0 0 1 6 0V6" />
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
id: "undecided",
|
|
label: "I'm not sure yet.",
|
|
hint: "Explore possibilities and see what AI can build.",
|
|
icon: (
|
|
<svg
|
|
width="18"
|
|
height="18"
|
|
viewBox="0 0 18 18"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.6"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<circle cx="9" cy="9" r="6" />
|
|
<path d="M9 11v1M9 6a2 2 0 0 1 2 2c0 2-2 2-2 2" />
|
|
</svg>
|
|
),
|
|
},
|
|
];
|
|
|
|
export function ForkScreen({ name, value, onChange, onClose, onNext }) {
|
|
return (
|
|
<>
|
|
<WizardTop
|
|
onBack={null}
|
|
onClose={onClose}
|
|
stepText="Pick your lane"
|
|
current={1}
|
|
total={4}
|
|
/>
|
|
<WizardBody>
|
|
<WizardQ
|
|
title={
|
|
name
|
|
? `Welcome, ${name}. Which sounds like you?`
|
|
: "Which one sounds like you?"
|
|
}
|
|
sub="Vibn asks different questions on the next screens depending on the answer. You can change this later."
|
|
/>
|
|
|
|
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
|
{FORKS.map((f) => {
|
|
const active = value === f.id;
|
|
return (
|
|
<button
|
|
key={f.id}
|
|
type="button"
|
|
onClick={() => onChange(f.id)}
|
|
onDoubleClick={() => {
|
|
onChange(f.id);
|
|
onNext();
|
|
}}
|
|
className={active ? "fork-card active" : "fork-card"}
|
|
>
|
|
<span
|
|
style={{
|
|
width: 36,
|
|
height: 36,
|
|
flexShrink: 0,
|
|
borderRadius: 9,
|
|
background: active
|
|
? "oklch(0.74 0.175 35 / 0.18)"
|
|
: "oklch(0.22 0.011 60)",
|
|
border: "1px solid var(--hairline)",
|
|
color: active ? "var(--accent)" : "var(--fg-mute)",
|
|
display: "grid",
|
|
placeItems: "center",
|
|
}}
|
|
>
|
|
{f.icon}
|
|
</span>
|
|
<span
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: 2,
|
|
flex: 1,
|
|
}}
|
|
>
|
|
<span
|
|
style={{
|
|
fontSize: 15,
|
|
fontWeight: 500,
|
|
letterSpacing: "-0.008em",
|
|
}}
|
|
>
|
|
{f.label}
|
|
</span>
|
|
<span
|
|
style={{
|
|
fontSize: 13,
|
|
color: "var(--fg-mute)",
|
|
lineHeight: 1.4,
|
|
}}
|
|
>
|
|
{f.hint}
|
|
</span>
|
|
</span>
|
|
|
|
<span
|
|
style={{
|
|
width: 18,
|
|
height: 18,
|
|
flexShrink: 0,
|
|
borderRadius: "50%",
|
|
border: `1.5px solid ${active ? "var(--accent)" : "var(--hairline-2)"}`,
|
|
background: active ? "var(--accent)" : "transparent",
|
|
display: "grid",
|
|
placeItems: "center",
|
|
color: "var(--accent-fg)",
|
|
transition: "border-color .15s, background .15s",
|
|
}}
|
|
>
|
|
{active && (
|
|
<svg
|
|
width="10"
|
|
height="10"
|
|
viewBox="0 0 16 16"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<path d="m3 8.5 3.2 3.2L13 5" />
|
|
</svg>
|
|
)}
|
|
</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<WizardFooter
|
|
canNext={!!value}
|
|
onNext={onNext}
|
|
nextLabel="Continue"
|
|
hint={value ? "Press ⌘↵" : null}
|
|
/>
|
|
</WizardBody>
|
|
</>
|
|
);
|
|
}
|