import { For, Show, createSignal } from "solid-js"; import { PeachWordmark } from "../components/PeachMark"; import { RuneBackground } from "../components/RuneBackground"; interface OnboardingCard { headline: string; body: string[]; warning: string | null; } const BASE_CARDS: OnboardingCard[] = [ { headline: "Your passwords\nlive here.\nNowhere else.", body: [ "No account. No server. No one but you can ever see your vault.", "Everything is encrypted on your device with a password only you know.", ], warning: null, }, { headline: "Two keys.", body: [ "Your master password is yours alone. Peach never sees it.", "If you forget it, your 12 recovery words can reset it from settings — save them somewhere safe.", ], warning: "Lose both and your vault cannot be opened.", }, { headline: "Everything\nyou need.", body: [ "Free includes passwords, cards, secure notes, two-factor codes, autofill, strong passwords, and breach checks.", "Pro adds encrypted sync, Peach Codex paper restore, passkeys, advanced vault health, canary entries, and duress tools.", ], warning: null, }, ]; const CARDS: OnboardingCard[] = BASE_CARDS; const CARD_EXIT_MS = 120; const CARD_ENTER_GAP_MS = 60; interface OnboardingProps { onComplete: () => void | Promise; onRestore?: () => void | Promise; onAdopt?: () => void | Promise; } export function Onboarding(props: OnboardingProps) { const [card, setCard] = createSignal(0); const [exiting, setExiting] = createSignal(false); const [completing, setCompleting] = createSignal(false); async function advance() { if (exiting() || completing()) return; if (card() < CARDS.length - 1) { setExiting(true); window.setTimeout(() => { setCard((c) => c + 1); setExiting(false); }, CARD_EXIT_MS + CARD_ENTER_GAP_MS); } else { setCompleting(true); // Don't persist peach_onboarded here. App.tsx persists it only when a // vault actually exists — so a user who quits mid-vault-creation // returns to the start of onboarding instead of getting stranded on // the create-vault screen with no back path. window.setTimeout(() => { void props.onComplete(); }, 200); } } function goBack() { if (exiting() || completing()) return; if (card() === 0) return; setExiting(true); window.setTimeout(() => { setCard((c) => c - 1); setExiting(false); }, CARD_EXIT_MS + CARD_ENTER_GAP_MS); } return (
{ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); advance(); } }} >

{CARDS[card()]!.headline}


{(para) =>

{para}

}

{CARDS[card()]!.warning}

0} fallback={
}>
); }