import { For, Show, createSignal } from "solid-js"; import { Capacitor } from "@capacitor/core"; import { PeachWordmark } from "../components/PeachMark"; import { RuneBackground } from "../components/RuneBackground"; import { registerPlugin } from "@capacitor/core"; import { storageSet } from "../../shared/storage"; interface OnboardingCard { headline: string; body: string[]; warning: string | null; mobileCard?: boolean; } 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: "One rule.", body: [ "Your master password is yours alone. Peach cannot recover it. There is no reset.", "Choose something you will remember. Write it down somewhere safe.", ], warning: "If you forget it, your vault cannot be opened.", }, { headline: "Everything\nyou need.", body: [ "Passwords, passkeys, cards, secure notes, two-factor codes.", "Autofills on every site. Generates strong passwords. Detects breaches.", "Free forever. Pro adds sync, mobile, and passkeys.", ], warning: null, }, ]; function getAutofillPlugin() { try { return registerPlugin<{ openAutofillSettings(): Promise; }>("Autofill"); } catch { return null; } } const AutofillPlugin = getAutofillPlugin(); const MOBILE_CARD: OnboardingCard = { headline: "Enable autofill.", body: [ "Peach fills passwords in Chrome, Safari, and every app on your phone.", ], warning: null, mobileCard: true, }; const CARDS: OnboardingCard[] = Capacitor.isNativePlatform() ? [...BASE_CARDS, MOBILE_CARD] : BASE_CARDS; const CARD_EXIT_MS = 120; const CARD_ENTER_GAP_MS = 60; interface OnboardingProps { onComplete: () => 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; // Mobile card has its own buttons — don't advance on click if (CARDS[card()]?.mobileCard) 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); try { await storageSet("peach_onboarded", "true"); } catch { // storage unavailable — still complete the flow } window.setTimeout(() => { void props.onComplete(); }, 200); } } async function handleEnableAutofill() { if (AutofillPlugin) { await AutofillPlugin.openAutofillSettings(); } setCompleting(true); try { await storageSet("peach_onboarded", "true"); } catch { // storage unavailable — still complete the flow } window.setTimeout(() => { void props.onComplete(); }, 200); } async function handleSkipAutofill() { setCompleting(true); try { await storageSet("peach_onboarded", "true"); } catch { // storage unavailable — still complete the flow } window.setTimeout(() => { void props.onComplete(); }, 200); } return (
{ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); advance(); } }} >

{CARDS[card()]!.headline}


{(para) =>

{para}

}

{CARDS[card()]!.warning}

); }