From 47417d13a02d8ca68313c148cfbe3c6d74a3c395 Mon Sep 17 00:00:00 2001 From: mawkone Date: Sat, 6 Jun 2026 18:32:57 -0700 Subject: [PATCH] feat: support root-level _marketing and _onboarding directories (T12) --- .../{marketing => _marketing}/README.md | 0 .../components/index.ts | 0 .../components/justine/JustineAuthShell.tsx | 0 .../components/justine/JustineFooter.tsx | 0 .../components/justine/JustineHomePage.tsx | 0 .../components/justine/JustineNav.tsx | 0 .../components/justine/index.ts | 0 .../components/new-site/index.tsx | 0 .../content/homepage.ts | 0 .../onboarding-agency-mock.ts | 0 .../onboarding-agency-types.ts | 0 .../onboarding-agency.tsx | 0 .../onboarding-build.tsx | 0 .../onboarding-consultant.tsx | 0 .../onboarding-entrepreneur.tsx | 0 .../onboarding-fork.tsx | 0 .../onboarding-owner.tsx | 0 .../onboarding-primitives.tsx | 0 .../onboarding => _onboarding}/onboarding.css | 0 vibn-frontend/_onboarding/page.tsx | 685 ++++++++++++++++++ .../app/(onboarding)/onboarding/page.tsx | 684 +---------------- vibn-frontend/tsconfig.json | 14 +- 22 files changed, 695 insertions(+), 688 deletions(-) rename vibn-frontend/{marketing => _marketing}/README.md (100%) rename vibn-frontend/{marketing => _marketing}/components/index.ts (100%) rename vibn-frontend/{marketing => _marketing}/components/justine/JustineAuthShell.tsx (100%) rename vibn-frontend/{marketing => _marketing}/components/justine/JustineFooter.tsx (100%) rename vibn-frontend/{marketing => _marketing}/components/justine/JustineHomePage.tsx (100%) rename vibn-frontend/{marketing => _marketing}/components/justine/JustineNav.tsx (100%) rename vibn-frontend/{marketing => _marketing}/components/justine/index.ts (100%) rename vibn-frontend/{marketing => _marketing}/components/new-site/index.tsx (100%) rename vibn-frontend/{marketing => _marketing}/content/homepage.ts (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-agency-mock.ts (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-agency-types.ts (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-agency.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-build.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-consultant.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-entrepreneur.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-fork.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-owner.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding-primitives.tsx (100%) rename vibn-frontend/{app/(onboarding)/onboarding => _onboarding}/onboarding.css (100%) create mode 100644 vibn-frontend/_onboarding/page.tsx diff --git a/vibn-frontend/marketing/README.md b/vibn-frontend/_marketing/README.md similarity index 100% rename from vibn-frontend/marketing/README.md rename to vibn-frontend/_marketing/README.md diff --git a/vibn-frontend/marketing/components/index.ts b/vibn-frontend/_marketing/components/index.ts similarity index 100% rename from vibn-frontend/marketing/components/index.ts rename to vibn-frontend/_marketing/components/index.ts diff --git a/vibn-frontend/marketing/components/justine/JustineAuthShell.tsx b/vibn-frontend/_marketing/components/justine/JustineAuthShell.tsx similarity index 100% rename from vibn-frontend/marketing/components/justine/JustineAuthShell.tsx rename to vibn-frontend/_marketing/components/justine/JustineAuthShell.tsx diff --git a/vibn-frontend/marketing/components/justine/JustineFooter.tsx b/vibn-frontend/_marketing/components/justine/JustineFooter.tsx similarity index 100% rename from vibn-frontend/marketing/components/justine/JustineFooter.tsx rename to vibn-frontend/_marketing/components/justine/JustineFooter.tsx diff --git a/vibn-frontend/marketing/components/justine/JustineHomePage.tsx b/vibn-frontend/_marketing/components/justine/JustineHomePage.tsx similarity index 100% rename from vibn-frontend/marketing/components/justine/JustineHomePage.tsx rename to vibn-frontend/_marketing/components/justine/JustineHomePage.tsx diff --git a/vibn-frontend/marketing/components/justine/JustineNav.tsx b/vibn-frontend/_marketing/components/justine/JustineNav.tsx similarity index 100% rename from vibn-frontend/marketing/components/justine/JustineNav.tsx rename to vibn-frontend/_marketing/components/justine/JustineNav.tsx diff --git a/vibn-frontend/marketing/components/justine/index.ts b/vibn-frontend/_marketing/components/justine/index.ts similarity index 100% rename from vibn-frontend/marketing/components/justine/index.ts rename to vibn-frontend/_marketing/components/justine/index.ts diff --git a/vibn-frontend/marketing/components/new-site/index.tsx b/vibn-frontend/_marketing/components/new-site/index.tsx similarity index 100% rename from vibn-frontend/marketing/components/new-site/index.tsx rename to vibn-frontend/_marketing/components/new-site/index.tsx diff --git a/vibn-frontend/marketing/content/homepage.ts b/vibn-frontend/_marketing/content/homepage.ts similarity index 100% rename from vibn-frontend/marketing/content/homepage.ts rename to vibn-frontend/_marketing/content/homepage.ts diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-agency-mock.ts b/vibn-frontend/_onboarding/onboarding-agency-mock.ts similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-agency-mock.ts rename to vibn-frontend/_onboarding/onboarding-agency-mock.ts diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-agency-types.ts b/vibn-frontend/_onboarding/onboarding-agency-types.ts similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-agency-types.ts rename to vibn-frontend/_onboarding/onboarding-agency-types.ts diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-agency.tsx b/vibn-frontend/_onboarding/onboarding-agency.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-agency.tsx rename to vibn-frontend/_onboarding/onboarding-agency.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-build.tsx b/vibn-frontend/_onboarding/onboarding-build.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-build.tsx rename to vibn-frontend/_onboarding/onboarding-build.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-consultant.tsx b/vibn-frontend/_onboarding/onboarding-consultant.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-consultant.tsx rename to vibn-frontend/_onboarding/onboarding-consultant.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-entrepreneur.tsx b/vibn-frontend/_onboarding/onboarding-entrepreneur.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-entrepreneur.tsx rename to vibn-frontend/_onboarding/onboarding-entrepreneur.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-fork.tsx b/vibn-frontend/_onboarding/onboarding-fork.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-fork.tsx rename to vibn-frontend/_onboarding/onboarding-fork.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-owner.tsx b/vibn-frontend/_onboarding/onboarding-owner.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-owner.tsx rename to vibn-frontend/_onboarding/onboarding-owner.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding-primitives.tsx b/vibn-frontend/_onboarding/onboarding-primitives.tsx similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding-primitives.tsx rename to vibn-frontend/_onboarding/onboarding-primitives.tsx diff --git a/vibn-frontend/app/(onboarding)/onboarding/onboarding.css b/vibn-frontend/_onboarding/onboarding.css similarity index 100% rename from vibn-frontend/app/(onboarding)/onboarding/onboarding.css rename to vibn-frontend/_onboarding/onboarding.css diff --git a/vibn-frontend/_onboarding/page.tsx b/vibn-frontend/_onboarding/page.tsx new file mode 100644 index 0000000..cf56df4 --- /dev/null +++ b/vibn-frontend/_onboarding/page.tsx @@ -0,0 +1,685 @@ +"use client"; + +import React, { useState, useEffect, useMemo, Fragment } from "react"; +import "./onboarding.css"; +import { ForkScreen } from "./onboarding-fork"; +import { EntrepreneurPath } from "./onboarding-entrepreneur"; +import { OwnerPath } from "./onboarding-owner"; +import { ConsultantPath } from "./onboarding-consultant"; +import { BuildScreen } from "./onboarding-build"; +import { ReadyScreen } from "./onboarding-build"; // Assuming ReadyScreen is exported from build +import { AgencyOnboarding } from "./onboarding-agency"; +import { type AgencyOnboardingResult } from "./onboarding-agency-types"; +import { WizardTop, WizardBody, WizardQ } from "./onboarding-primitives"; + +// Root onboarding app — owns the route state and the answers dict. +// Routes: fork → → build → ready. A floating debug navigator (toggle +// in the lower-right) lets reviewers jump between any screen without +// filling out the form. + +export default function OnboardingApp() { + const initialName = React.useMemo(() => { + try { + return typeof window !== "undefined" + ? localStorage.getItem("vibn:firstName") || "" + : ""; + } catch { + return ""; + } + }, []); + + const [stage, setStage] = React.useState("door"); // door | agency | fork | path | choice | build | ready + const [path, setPath] = React.useState(null); // entrepreneur | owner | consultant + const [forkChoice, setForkChoice] = React.useState(null); + const [step, setStep] = React.useState(0); + const [data, setData] = React.useState>({}); + const [createdSlug, setCreatedSlug] = React.useState(null); + const [saving, setSaving] = React.useState(false); + + const [debugOpen, setDebugOpen] = React.useState(false); + + const update = (patch: Record) => + setData((d) => ({ ...d, ...patch })); + + // ── GTM Onboarding database saving endpoints ──────────────────────────────── + const saveOnboarding = async ( + payload: Record, + ): Promise => { + setSaving(true); + try { + const res = await fetch("/api/onboarding", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + if (res.ok) { + const bodyData = await res.json(); + setCreatedSlug(bodyData.slug); + setSaving(false); + return bodyData.slug; + } + } catch (err) { + console.error("Failed to save onboarding selections:", err); + } + setSaving(false); + return null; + }; + + const finishAgency = async (result: AgencyOnboardingResult) => { + const slug = await saveOnboarding({ + isAgency: true, + profile: result.profile, + expertise: result.expertise, + tools: result.tools, + }); + if (slug && typeof window !== "undefined") { + window.location.href = "/" + slug; + } + }; + + const finishPersonal = async (choice: "workspace" | "build") => { + const slug = await saveOnboarding({ isAgency: false, data }); + if (slug && typeof window !== "undefined") { + if (choice === "workspace") { + window.location.href = "/" + slug; + } else { + setStage("build"); + } + } + }; + + // ── transitions ────────────────────────────────────────────────────── + const confirmFork = () => { + if (!forkChoice) return; + setPath(forkChoice); + setStep(0); + setStage("path"); + }; + const backToFork = () => { + setStage("fork"); + setStep(0); + }; + const completePath = () => setStage("choice"); + const openWorkspace = () => { + if (createdSlug && typeof window !== "undefined") { + window.location.href = "/" + createdSlug; // Route directly to their live chat workspace! + } else { + setStage("ready"); + } + }; + const close = () => { + if (typeof window !== "undefined") window.location.href = "/"; + }; + const openChat = () => { + if (createdSlug && typeof window !== "undefined") { + window.location.href = "/" + createdSlug; + } else if (typeof window !== "undefined") { + window.location.href = "/"; + } + }; + const openAgency = () => setStage("agency"); + const openSelf = () => { + setStage("fork"); + setStep(0); + }; + + // ⌘↵ advances on whatever the current primary action is + React.useEffect(() => { + const handler = (e) => { + if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { + const btn = document.querySelector( + ".btn-primary:not([disabled])", + ) as HTMLElement; + if (btn) btn.click(); + } + }; + window.addEventListener("keydown", handler); + return () => window.removeEventListener("keydown", handler); + }, []); + + // ── render ─────────────────────────────────────────────────────────── + let body; + if (stage === "door") { + body = ( + + ); + } else if (stage === "agency") { + body = ( + setStage("door")} + /> + ); + } else if (stage === "fork") { + body = ( + + ); + } else if (stage === "path") { + const props = { + data, + onUpdate: update, + onBack: backToFork, + onClose: close, + onComplete: completePath, + onJumpToStep: setStep, + step, + }; + if (path === "entrepreneur") body = ; + else if (path === "owner") body = ; + else body = ; + } else if (stage === "choice") { + body = ( + finishPersonal("workspace")} + onBuild={() => finishPersonal("build")} + onClose={close} + resolving={saving} + /> + ); + } else if (stage === "build") { + body = ( + setStage("path")} + onClose={close} + onOpen={openWorkspace} + /> + ); + } else { + body = ( + + ); + } + + return ( +
+ {body} + { + if (s === "fork") setStage("fork"); + else if (s === "build") { + setPath(p); + setStage("build"); + } else if (s === "ready") { + setPath(p); + setStage("ready"); + } else { + setPath(p); + setStep(idx); + setStage("path"); + } + }} + /> +
+ ); +} + +// ── Debug navigator ────────────────────────────────────────────────────── +function DebugNav({ open, setOpen, stage, path, step, onJump }) { + const groups = [ + { + title: "Start", + rows: [ + { + label: "01 · Fork", + active: stage === "fork", + go: () => onJump("fork"), + }, + ], + }, + { + title: "Entrepreneur", + rows: [ + { + label: "02 · Idea", + active: stage === "path" && path === "entrepreneur" && step === 0, + go: () => onJump("path", "entrepreneur", 0), + }, + { + label: "03 · Audience", + active: stage === "path" && path === "entrepreneur" && step === 1, + go: () => onJump("path", "entrepreneur", 1), + }, + { + label: "04 · Goal", + active: stage === "path" && path === "entrepreneur" && step === 2, + go: () => onJump("path", "entrepreneur", 2), + }, + { + label: "05 · Vibe", + active: stage === "path" && path === "entrepreneur" && step === 3, + go: () => onJump("path", "entrepreneur", 3), + }, + ], + }, + { + title: "Owner", + rows: [ + { + label: "02 · Business", + active: stage === "path" && path === "owner" && step === 0, + go: () => onJump("path", "owner", 0), + }, + { + label: "03 · Stack", + active: stage === "path" && path === "owner" && step === 1, + go: () => onJump("path", "owner", 1), + }, + { + label: "04 · First fix", + active: stage === "path" && path === "owner" && step === 2, + go: () => onJump("path", "owner", 2), + }, + { + label: "05 · Scale", + active: stage === "path" && path === "owner" && step === 3, + go: () => onJump("path", "owner", 3), + }, + ], + }, + { + title: "Consultant", + rows: [ + { + label: "02 · Client", + active: stage === "path" && path === "consultant" && step === 0, + go: () => onJump("path", "consultant", 0), + }, + { + label: "03 · Brief", + active: stage === "path" && path === "consultant" && step === 1, + go: () => onJump("path", "consultant", 1), + }, + { + label: "04 · Scope", + active: stage === "path" && path === "consultant" && step === 2, + go: () => onJump("path", "consultant", 2), + }, + { + label: "05 · Handoff", + active: stage === "path" && path === "consultant" && step === 3, + go: () => onJump("path", "consultant", 3), + }, + ], + }, + { + title: "Finish", + rows: [ + { + label: "Build · entrepreneur", + active: stage === "build" && path === "entrepreneur", + go: () => onJump("build", "entrepreneur"), + }, + { + label: "Build · owner", + active: stage === "build" && path === "owner", + go: () => onJump("build", "owner"), + }, + { + label: "Build · consultant", + active: stage === "build" && path === "consultant", + go: () => onJump("build", "consultant"), + }, + { + label: "Ready", + active: stage === "ready", + go: () => onJump("ready", path || "entrepreneur"), + }, + ], + }, + ]; + + return ( +
+ {open && ( +
+ {groups.map((g) => ( + +
+ {g.title} +
+ {g.rows.map((r) => ( + + ))} +
+ ))} + +
+ )} + +
+ ); +} + +// ── Transition Choice Screen ──────────────────────────────────────────────── +// Displays after completing Step 3 (Design) on the Self-Builder / Personal path. +// Lets them choose whether they want to explore their workspace console first, +// or go straight into the co-founder build chat session. +function ChoiceScreen({ onWorkspace, onBuild, onClose, resolving }) { + if (resolving) { + return ( + <> + + +
+ + + +
+
+ Registering your workspace... +
+
+ Setting up Gitea & GMB pipelines on the server… +
+
+
+
+ + ); + } + + return ( + <> + + + +
+
+
+ + ); +} + +// ── Front door ───────────────────────────────────────────────────────────── +// The very first choice. Motivations are opposite, so the openings diverge: +// consultants set up an agency; self-builders go straight to build. +function DoorCard({ + emphasized, + icon, + title, + sub, + onClick, +}: { + emphasized?: boolean; + icon: React.ReactNode; + title: React.ReactNode; + sub: React.ReactNode; + onClick: () => void; +}) { + return ( + + ); +} + +function DoorScreen({ onAgency, onSelf, onClose }) { + return ( + <> + + + +
+ + I want to build my own ideas + + Go from idea to market, and beyond. + + + } + icon={ + + } + /> + + I want to do billable AI work for others + + VIBN will help you find local businesses that you can build + custom solutions for + + + } + icon={ + + } + /> +
+
+ + ); +} diff --git a/vibn-frontend/app/(onboarding)/onboarding/page.tsx b/vibn-frontend/app/(onboarding)/onboarding/page.tsx index cf56df4..923a44d 100644 --- a/vibn-frontend/app/(onboarding)/onboarding/page.tsx +++ b/vibn-frontend/app/(onboarding)/onboarding/page.tsx @@ -1,685 +1,5 @@ "use client"; -import React, { useState, useEffect, useMemo, Fragment } from "react"; -import "./onboarding.css"; -import { ForkScreen } from "./onboarding-fork"; -import { EntrepreneurPath } from "./onboarding-entrepreneur"; -import { OwnerPath } from "./onboarding-owner"; -import { ConsultantPath } from "./onboarding-consultant"; -import { BuildScreen } from "./onboarding-build"; -import { ReadyScreen } from "./onboarding-build"; // Assuming ReadyScreen is exported from build -import { AgencyOnboarding } from "./onboarding-agency"; -import { type AgencyOnboardingResult } from "./onboarding-agency-types"; -import { WizardTop, WizardBody, WizardQ } from "./onboarding-primitives"; +import OnboardingPage from "@/_onboarding/page"; -// Root onboarding app — owns the route state and the answers dict. -// Routes: fork → → build → ready. A floating debug navigator (toggle -// in the lower-right) lets reviewers jump between any screen without -// filling out the form. - -export default function OnboardingApp() { - const initialName = React.useMemo(() => { - try { - return typeof window !== "undefined" - ? localStorage.getItem("vibn:firstName") || "" - : ""; - } catch { - return ""; - } - }, []); - - const [stage, setStage] = React.useState("door"); // door | agency | fork | path | choice | build | ready - const [path, setPath] = React.useState(null); // entrepreneur | owner | consultant - const [forkChoice, setForkChoice] = React.useState(null); - const [step, setStep] = React.useState(0); - const [data, setData] = React.useState>({}); - const [createdSlug, setCreatedSlug] = React.useState(null); - const [saving, setSaving] = React.useState(false); - - const [debugOpen, setDebugOpen] = React.useState(false); - - const update = (patch: Record) => - setData((d) => ({ ...d, ...patch })); - - // ── GTM Onboarding database saving endpoints ──────────────────────────────── - const saveOnboarding = async ( - payload: Record, - ): Promise => { - setSaving(true); - try { - const res = await fetch("/api/onboarding", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(payload), - }); - if (res.ok) { - const bodyData = await res.json(); - setCreatedSlug(bodyData.slug); - setSaving(false); - return bodyData.slug; - } - } catch (err) { - console.error("Failed to save onboarding selections:", err); - } - setSaving(false); - return null; - }; - - const finishAgency = async (result: AgencyOnboardingResult) => { - const slug = await saveOnboarding({ - isAgency: true, - profile: result.profile, - expertise: result.expertise, - tools: result.tools, - }); - if (slug && typeof window !== "undefined") { - window.location.href = "/" + slug; - } - }; - - const finishPersonal = async (choice: "workspace" | "build") => { - const slug = await saveOnboarding({ isAgency: false, data }); - if (slug && typeof window !== "undefined") { - if (choice === "workspace") { - window.location.href = "/" + slug; - } else { - setStage("build"); - } - } - }; - - // ── transitions ────────────────────────────────────────────────────── - const confirmFork = () => { - if (!forkChoice) return; - setPath(forkChoice); - setStep(0); - setStage("path"); - }; - const backToFork = () => { - setStage("fork"); - setStep(0); - }; - const completePath = () => setStage("choice"); - const openWorkspace = () => { - if (createdSlug && typeof window !== "undefined") { - window.location.href = "/" + createdSlug; // Route directly to their live chat workspace! - } else { - setStage("ready"); - } - }; - const close = () => { - if (typeof window !== "undefined") window.location.href = "/"; - }; - const openChat = () => { - if (createdSlug && typeof window !== "undefined") { - window.location.href = "/" + createdSlug; - } else if (typeof window !== "undefined") { - window.location.href = "/"; - } - }; - const openAgency = () => setStage("agency"); - const openSelf = () => { - setStage("fork"); - setStep(0); - }; - - // ⌘↵ advances on whatever the current primary action is - React.useEffect(() => { - const handler = (e) => { - if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { - const btn = document.querySelector( - ".btn-primary:not([disabled])", - ) as HTMLElement; - if (btn) btn.click(); - } - }; - window.addEventListener("keydown", handler); - return () => window.removeEventListener("keydown", handler); - }, []); - - // ── render ─────────────────────────────────────────────────────────── - let body; - if (stage === "door") { - body = ( - - ); - } else if (stage === "agency") { - body = ( - setStage("door")} - /> - ); - } else if (stage === "fork") { - body = ( - - ); - } else if (stage === "path") { - const props = { - data, - onUpdate: update, - onBack: backToFork, - onClose: close, - onComplete: completePath, - onJumpToStep: setStep, - step, - }; - if (path === "entrepreneur") body = ; - else if (path === "owner") body = ; - else body = ; - } else if (stage === "choice") { - body = ( - finishPersonal("workspace")} - onBuild={() => finishPersonal("build")} - onClose={close} - resolving={saving} - /> - ); - } else if (stage === "build") { - body = ( - setStage("path")} - onClose={close} - onOpen={openWorkspace} - /> - ); - } else { - body = ( - - ); - } - - return ( -
- {body} - { - if (s === "fork") setStage("fork"); - else if (s === "build") { - setPath(p); - setStage("build"); - } else if (s === "ready") { - setPath(p); - setStage("ready"); - } else { - setPath(p); - setStep(idx); - setStage("path"); - } - }} - /> -
- ); -} - -// ── Debug navigator ────────────────────────────────────────────────────── -function DebugNav({ open, setOpen, stage, path, step, onJump }) { - const groups = [ - { - title: "Start", - rows: [ - { - label: "01 · Fork", - active: stage === "fork", - go: () => onJump("fork"), - }, - ], - }, - { - title: "Entrepreneur", - rows: [ - { - label: "02 · Idea", - active: stage === "path" && path === "entrepreneur" && step === 0, - go: () => onJump("path", "entrepreneur", 0), - }, - { - label: "03 · Audience", - active: stage === "path" && path === "entrepreneur" && step === 1, - go: () => onJump("path", "entrepreneur", 1), - }, - { - label: "04 · Goal", - active: stage === "path" && path === "entrepreneur" && step === 2, - go: () => onJump("path", "entrepreneur", 2), - }, - { - label: "05 · Vibe", - active: stage === "path" && path === "entrepreneur" && step === 3, - go: () => onJump("path", "entrepreneur", 3), - }, - ], - }, - { - title: "Owner", - rows: [ - { - label: "02 · Business", - active: stage === "path" && path === "owner" && step === 0, - go: () => onJump("path", "owner", 0), - }, - { - label: "03 · Stack", - active: stage === "path" && path === "owner" && step === 1, - go: () => onJump("path", "owner", 1), - }, - { - label: "04 · First fix", - active: stage === "path" && path === "owner" && step === 2, - go: () => onJump("path", "owner", 2), - }, - { - label: "05 · Scale", - active: stage === "path" && path === "owner" && step === 3, - go: () => onJump("path", "owner", 3), - }, - ], - }, - { - title: "Consultant", - rows: [ - { - label: "02 · Client", - active: stage === "path" && path === "consultant" && step === 0, - go: () => onJump("path", "consultant", 0), - }, - { - label: "03 · Brief", - active: stage === "path" && path === "consultant" && step === 1, - go: () => onJump("path", "consultant", 1), - }, - { - label: "04 · Scope", - active: stage === "path" && path === "consultant" && step === 2, - go: () => onJump("path", "consultant", 2), - }, - { - label: "05 · Handoff", - active: stage === "path" && path === "consultant" && step === 3, - go: () => onJump("path", "consultant", 3), - }, - ], - }, - { - title: "Finish", - rows: [ - { - label: "Build · entrepreneur", - active: stage === "build" && path === "entrepreneur", - go: () => onJump("build", "entrepreneur"), - }, - { - label: "Build · owner", - active: stage === "build" && path === "owner", - go: () => onJump("build", "owner"), - }, - { - label: "Build · consultant", - active: stage === "build" && path === "consultant", - go: () => onJump("build", "consultant"), - }, - { - label: "Ready", - active: stage === "ready", - go: () => onJump("ready", path || "entrepreneur"), - }, - ], - }, - ]; - - return ( -
- {open && ( -
- {groups.map((g) => ( - -
- {g.title} -
- {g.rows.map((r) => ( - - ))} -
- ))} - -
- )} - -
- ); -} - -// ── Transition Choice Screen ──────────────────────────────────────────────── -// Displays after completing Step 3 (Design) on the Self-Builder / Personal path. -// Lets them choose whether they want to explore their workspace console first, -// or go straight into the co-founder build chat session. -function ChoiceScreen({ onWorkspace, onBuild, onClose, resolving }) { - if (resolving) { - return ( - <> - - -
- - - -
-
- Registering your workspace... -
-
- Setting up Gitea & GMB pipelines on the server… -
-
-
-
- - ); - } - - return ( - <> - - - -
-
-
- - ); -} - -// ── Front door ───────────────────────────────────────────────────────────── -// The very first choice. Motivations are opposite, so the openings diverge: -// consultants set up an agency; self-builders go straight to build. -function DoorCard({ - emphasized, - icon, - title, - sub, - onClick, -}: { - emphasized?: boolean; - icon: React.ReactNode; - title: React.ReactNode; - sub: React.ReactNode; - onClick: () => void; -}) { - return ( - - ); -} - -function DoorScreen({ onAgency, onSelf, onClose }) { - return ( - <> - - - -
- - I want to build my own ideas - - Go from idea to market, and beyond. - - - } - icon={ - - } - /> - - I want to do billable AI work for others - - VIBN will help you find local businesses that you can build - custom solutions for - - - } - icon={ - - } - /> -
-
- - ); -} +export default OnboardingPage; diff --git a/vibn-frontend/tsconfig.json b/vibn-frontend/tsconfig.json index 0324d70..0beb4ab 100644 --- a/vibn-frontend/tsconfig.json +++ b/vibn-frontend/tsconfig.json @@ -16,12 +16,14 @@ "noImplicitAny": false, "plugins": [ { - "name": "next" - } + "name": "next", + }, ], "paths": { - "@/*": ["./*"] - } + "@/marketing/*": ["./_marketing/*"], + "@/onboarding/*": ["./_onboarding/*"], + "@/*": ["./*"], + }, }, "include": [ "next-env.d.ts", @@ -29,7 +31,7 @@ "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", - "**/*.mts" + "**/*.mts", ], - "exclude": ["node_modules"] + "exclude": ["node_modules"], }