Add top navigation shell and about page

This commit is contained in:
Janpeter Visser 2026-04-19 03:50:06 +02:00
parent 414491801a
commit 4966d493cc
14 changed files with 630 additions and 310 deletions

View file

@ -1,9 +1,9 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { signOutAction } from "@/app/auth-actions";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { AppShell } from "@/components/navigation/app-shell";
import { PageIntro } from "@/components/navigation/page-intro";
import { CheckInForm } from "@/components/check-in/check-in-form";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
@ -18,7 +18,6 @@ import { getTodayCheckInForCurrentUser } from "@/lib/check-in/service";
import { getCheckInStatusToast } from "@/lib/feedback/status-messages";
import { getProfileBundleForCurrentUser } from "@/lib/profile/service";
import { getParamValue, type PageSearchParams } from "@/lib/search-params";
import { cn } from "@/lib/utils";
export const dynamic = "force-dynamic";
@ -55,45 +54,23 @@ export default async function CheckInPage({ searchParams }: CheckInPageProps) {
);
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} paramKeys={["error", "status"]} />
<header className="app-page-header">
<div>
<div className="app-page-breadcrumb">
<Link href="/dashboard" className="app-page-link">
Dashboard
</Link>
<span>/</span>
<span>Ochtendcheck-in</span>
</div>
<h1 className="mt-3 font-[family-name:var(--font-display)] text-4xl leading-tight">
Ochtendcheck-in van vandaag
</h1>
<p className="app-page-copy">
Houd je start rustig en klein. Je legt alleen een energiescore en een
globale slaapindruk vast voor vandaag.
</p>
</div>
<div className="flex flex-wrap items-center gap-3">
<PageIntro
eyebrow="Check-in"
title="Ochtendcheck-in van vandaag"
description="Houd je start rustig en klein. Je legt alleen een energiescore en een globale slaapindruk vast voor vandaag."
aside={
<Link
href="/dashboard"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary"
>
Terug naar dashboard
</Link>
<form action={signOutAction}>
<Button type="submit" size="lg" className="h-11 rounded-full px-5">
Uitloggen
</Button>
</form>
</div>
</header>
}
/>
<section className="grid gap-5 lg:grid-cols-[1.1fr_0.9fr]">
<CheckInForm todayCheckIn={checkInStatus?.todayCheckIn ?? null} />
@ -138,6 +115,6 @@ export default async function CheckInPage({ searchParams }: CheckInPageProps) {
</aside>
</section>
</div>
</main>
</AppShell>
);
}

View file

@ -1,10 +1,10 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { signOutAction } from "@/app/auth-actions";
import { CheckInCard } from "@/components/check-in/check-in-card";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { AppShell } from "@/components/navigation/app-shell";
import { PageIntro } from "@/components/navigation/page-intro";
import { EnergyMeterCard } from "@/components/planning/energy-meter-card";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
@ -21,7 +21,6 @@ import { getTodayActivitiesForCurrentUser } from "@/lib/planning/service";
import { calculatePlanningMeterSnapshot } from "@/lib/planning/meter";
import { getProfileBundleForCurrentUser } from "@/lib/profile/service";
import { getParamValue, type PageSearchParams } from "@/lib/search-params";
import { cn } from "@/lib/utils";
export const dynamic = "force-dynamic";
@ -77,62 +76,25 @@ export default async function DashboardPage({ searchParams }: DashboardPageProps
);
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} />
<header className="app-page-header">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Protected route
</p>
<h1 className="mt-3 font-[family-name:var(--font-display)] text-4xl leading-tight">
Dashboard placeholder voor release 1
</h1>
<p className="app-page-copy">
Je sessie is server-side gevalideerd en het minimale profielbundle is
nu beschikbaar. Daarmee staat de fundering voor onboarding, settings
en de eerste energieflows klaar.
</p>
</div>
<form action={signOutAction}>
<div className="flex flex-wrap items-center gap-3">
<PageIntro
eyebrow="Dashboard"
title="Je huidige dagstatus"
description="Hier zie je in één overzicht je profielbasis, ochtendcheck-in, planningstatus en huidige energiemeter voor vandaag."
aside={
isTestWizardEnabled() ? (
<Link
href="/settings"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
href="/wizard-test"
className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary"
>
Instellingen
Test wizard
</Link>
<Link
href="/planning"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
>
Dagplanning
</Link>
{isTestWizardEnabled() ? (
<Link
href="/wizard-test"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
>
Test wizard
</Link>
) : null}
<Button type="submit" size="lg" className="h-11 rounded-full px-5">
Uitloggen
</Button>
</div>
</form>
</header>
) : null
}
/>
<section className="grid gap-5 md:grid-cols-3">
<Card className="py-0">
@ -214,13 +176,7 @@ export default async function DashboardPage({ searchParams }: DashboardPageProps
Plan kleine, concrete activiteiten voor vandaag en bouw daarna verder op budgetfeedback en evaluatie.
</CardDescription>
<div className="mt-4">
<Link
href="/planning"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
>
<Link href="/planning" className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary">
Open dagplanning
</Link>
</div>
@ -256,15 +212,9 @@ export default async function DashboardPage({ searchParams }: DashboardPageProps
en eerste voorkeuren vast te leggen.
</p>
</div>
<Link
href="/onboarding"
className={cn(
buttonVariants({ variant: "warning", size: "lg" }),
"h-11 shrink-0 rounded-full px-5",
)}
>
Rond onboarding af
</Link>
<Link href="/onboarding" className="inline-flex items-center rounded-full bg-warning px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:brightness-[0.98]">
Rond onboarding af
</Link>
</CardContent>
</Card>
) : (
@ -277,19 +227,13 @@ export default async function DashboardPage({ searchParams }: DashboardPageProps
timezone en zichtbaarheid van punten later zelfstandig kunt aanpassen.
</p>
</div>
<Link
href="/settings"
className={cn(
buttonVariants({ variant: "secondary", size: "lg" }),
"h-11 shrink-0 rounded-full px-5",
)}
>
Open instellingen
</Link>
</CardContent>
</Card>
)}
<Link href="/settings" className="inline-flex items-center rounded-full bg-secondary px-4 py-2 text-sm font-medium text-secondary-foreground shadow-[var(--shadow-1)] transition-colors hover:brightness-[0.98]">
Open instellingen
</Link>
</CardContent>
</Card>
)}
</div>
</main>
</AppShell>
);
}

View file

@ -1,5 +1,6 @@
import { redirect } from "next/navigation";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { AppShell } from "@/components/navigation/app-shell";
import { OnboardingFlow } from "@/components/onboarding/onboarding-flow";
import { sanitizeNextPath } from "@/lib/auth/navigation";
import { getAuthState } from "@/lib/auth/session";
@ -41,11 +42,11 @@ export default async function OnboardingPage({ searchParams }: OnboardingPagePro
);
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} paramKeys={["error", "status"]} />
<OnboardingFlow profileBundle={profileBundle} />
</div>
</main>
</AppShell>
);
}

View file

@ -1,7 +1,7 @@
import Link from "next/link";
import { signOutAction } from "@/app/auth-actions";
import { AppShell } from "@/components/navigation/app-shell";
import { PageIntro } from "@/components/navigation/page-intro";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
@ -9,14 +9,12 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { getAuthState } from "@/lib/auth/session";
import { getAuthStatusToast } from "@/lib/feedback/status-messages";
import { getParamValue, type PageSearchParams } from "@/lib/search-params";
import { cn } from "@/lib/utils";
export const dynamic = "force-dynamic";
const loopSteps = [
const productLoop = [
{
title: "Check-in",
copy: "Start de dag met een korte energiescore en slaapkwaliteit, zonder overbodige frictie.",
@ -31,8 +29,15 @@ const loopSteps = [
},
];
const releaseFocus = [
const makerNotes = [
"Jan Peter Visser ontwikkelt deze app als rustige, praktische dagtool.",
"De app is bewust gericht op helderheid, lage cognitieve belasting en een wellness-first toon.",
"Elke stap wordt klein gehouden zodat de flow bruikbaar blijft zonder medische framing.",
];
const appSpecs = [
"Alleen individuele gebruikers in release 1",
"Volwassen doelgroep en Nederlands als voertaal",
"Wellness/self-management positionering",
"Geen sharing, AI of medische workflows in de MVP",
"Vercel + Supabase als technische basis",
@ -43,7 +48,6 @@ type HomePageProps = {
};
export default async function Home({ searchParams }: HomePageProps) {
const authState = await getAuthState();
const resolvedSearchParams = await searchParams;
const statusToast = getAuthStatusToast(
getParamValue(resolvedSearchParams, "error"),
@ -51,95 +55,38 @@ export default async function Home({ searchParams }: HomePageProps) {
);
return (
<main className="app-page">
<div className="mx-auto flex min-h-screen w-full max-w-6xl flex-col px-6 py-10 sm:px-8 lg:px-10">
<header className="mb-10 flex items-center justify-between border-b border-border/70 pb-5">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Inspannings Monitor
</p>
<h1 className="font-[family-name:var(--font-display)] text-3xl leading-tight sm:text-5xl">
Rustige basis voor een wellness-first MVP
</h1>
</div>
<div className="flex flex-wrap items-center justify-end gap-3">
{authState.isConfigured ? (
authState.isAuthenticated ? (
<>
<Link
href="/dashboard"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 shrink-0 whitespace-nowrap rounded-full px-5",
)}
>
Naar dashboard
</Link>
<form action={signOutAction}>
<Button type="submit" variant="outline" size="lg" className="h-11 shrink-0 whitespace-nowrap rounded-full px-5">
Uitloggen
</Button>
</form>
</>
) : (
<>
<Link
href="/login"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 shrink-0 whitespace-nowrap rounded-full px-5",
)}
>
Inloggen
</Link>
<Link
href="/sign-up"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 shrink-0 whitespace-nowrap rounded-full px-5",
)}
>
Account aanmaken
</Link>
</>
)
) : (
<span className="rounded-full border border-warning/30 bg-warning/14 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)]">
Supabase nog niet geconfigureerd
</span>
)}
</div>
</header>
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} paramKeys={["error", "status"]} />
<section className="grid gap-6 lg:grid-cols-[1.35fr_0.95fr]">
<Card elevation="raised" className="rounded-[var(--radius-4xl)] py-0 backdrop-blur">
<PageIntro
eyebrow="About"
title="Over de maker en de app"
description="Inspannings Monitor is een rustige wellness-first webapp voor volwassenen die hun energie willen plannen, uitvoeren en evalueren zonder medische claims of overmatige frictie."
aside={
<Link
href="/planning"
className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary"
>
Bekijk planning
</Link>
}
/>
<section className="grid gap-6 lg:grid-cols-[1.05fr_0.95fr]">
<Card elevation="raised" className="py-0">
<CardContent className="p-6 sm:p-8">
<p className="mb-4 max-w-2xl text-lg leading-8 text-muted-foreground">
De projectbasis staat nu, inclusief de eerste auth-laag via Supabase.
Release 1 blijft bewust smal: publieke landing, aparte login/signup
routes en een eerste protected dashboard als basis voor de volgende stories.
<p className="mb-5 max-w-2xl text-lg leading-8 text-muted-foreground">
Deze app wordt ontwikkeld door Jan Peter Visser als compacte dagtool
voor energieplanning en zelfregie. Het doel is niet om te diagnosticeren
of te behandelen, maar om een rustige plan-doe-evalueer-structuur te bieden
die licht genoeg blijft voor dagelijks gebruik.
</p>
<div className="grid gap-4 md:grid-cols-3">
{loopSteps.map((step, index) => (
<Card
key={step.title}
tone="subtle"
className="rounded-[var(--radius-2xl)] py-0 shadow-none"
>
<CardHeader className="pb-0">
<p className="text-xs font-semibold uppercase tracking-[0.22em] text-muted-foreground">
Stap {index + 1}
</p>
<CardTitle className="font-[family-name:var(--font-display)] text-2xl">
{step.title}
</CardTitle>
</CardHeader>
<CardContent className="pb-5">
<CardDescription className="text-sm leading-7 text-muted-foreground">
{step.copy}
</CardDescription>
<div className="grid gap-4">
{makerNotes.map((note) => (
<Card key={note} tone="subtle" className="py-0 shadow-none">
<CardContent className="px-5 py-4 text-sm leading-7 text-muted-foreground">
{note}
</CardContent>
</Card>
))}
@ -147,14 +94,14 @@ export default async function Home({ searchParams }: HomePageProps) {
</CardContent>
</Card>
<Card tone="primary" elevation="raised" className="rounded-[var(--radius-4xl)] py-0">
<Card tone="primary" elevation="raised" className="py-0">
<CardHeader className="px-6 pt-7 sm:px-8">
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-primary-foreground/75">
Release 1 focus
Specificaties van de app
</p>
</CardHeader>
<CardContent className="space-y-3 px-6 pb-7 sm:px-8">
{releaseFocus.map((item) => (
{appSpecs.map((item) => (
<Card
key={item}
className="rounded-[var(--radius-2xl)] border-white/10 bg-white/8 py-0 text-primary-foreground shadow-none"
@ -162,26 +109,49 @@ export default async function Home({ searchParams }: HomePageProps) {
<CardContent className="px-4 py-3 text-sm leading-7">{item}</CardContent>
</Card>
))}
{authState.isConfigured ? (
<p className="pt-2 text-sm leading-7 text-primary-foreground/80">
Auth is ingericht met e-mail, wachtwoord en verplichte e-mailverificatie.
</p>
) : (
<p className="pt-2 text-sm leading-7 text-primary-foreground/80">
Voeg `.env.local` toe om login, signup en protected routes lokaal te activeren.
</p>
)}
<p className="pt-2 text-sm leading-7 text-primary-foreground/80">
De huidige codebasis bevat al auth, onboarding, ochtendcheck-in,
planning, energiemeter en Dusk-theming.
</p>
</CardContent>
</Card>
</section>
<Card tone="subtle" className="mt-8 rounded-[var(--radius-4xl)] py-0 backdrop-blur">
<Card elevation="raised" className="py-0">
<CardHeader className="pb-0">
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Dagflow
</p>
<CardTitle className="text-2xl">De hoofdstructuur van release 1</CardTitle>
</CardHeader>
<CardContent className="grid gap-5 p-6 md:grid-cols-3">
{productLoop.map((step, index) => (
<Card key={step.title} tone="subtle" className="py-0 shadow-none">
<CardHeader className="pb-0">
<p className="text-xs font-semibold uppercase tracking-[0.22em] text-muted-foreground">
Stap {index + 1}
</p>
<CardTitle className="font-[family-name:var(--font-display)] text-2xl">
{step.title}
</CardTitle>
</CardHeader>
<CardContent className="pb-5">
<CardDescription className="text-sm leading-7 text-muted-foreground">
{step.copy}
</CardDescription>
</CardContent>
</Card>
))}
</CardContent>
</Card>
<Card tone="subtle" className="py-0 backdrop-blur">
<CardContent className="grid gap-5 p-6 sm:grid-cols-2 lg:grid-cols-4">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Volgende story
Positionering
</p>
<p className="mt-2 font-semibold text-foreground">ST-201 Ochtendcheck-in</p>
<p className="mt-2 font-semibold text-foreground">Wellness / self-management</p>
</div>
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
@ -191,19 +161,19 @@ export default async function Home({ searchParams }: HomePageProps) {
</div>
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Positionering
Auth en data
</p>
<p className="mt-2 font-semibold text-foreground">Wellness / self-management</p>
<p className="mt-2 font-semibold text-foreground">Supabase Auth + PostgreSQL</p>
</div>
<div>
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted-foreground">
Status
Hosting
</p>
<p className="mt-2 font-semibold text-foreground">Auth, onboarding en settings actief</p>
<p className="mt-2 font-semibold text-foreground">Next.js op Vercel</p>
</div>
</CardContent>
</Card>
</div>
</main>
</AppShell>
);
}

View file

@ -1,11 +1,11 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { signOutAction } from "@/app/auth-actions";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { AppShell } from "@/components/navigation/app-shell";
import { PageIntro } from "@/components/navigation/page-intro";
import { ActivityForm } from "@/components/planning/activity-form";
import { EnergyMeterCard } from "@/components/planning/energy-meter-card";
import { TodayActivitiesList } from "@/components/planning/today-activities-list";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
@ -21,7 +21,6 @@ import { getPlanningPageDataForCurrentUser } from "@/lib/planning/service";
import { calculatePlanningMeterSnapshot } from "@/lib/planning/meter";
import { getProfileBundleForCurrentUser } from "@/lib/profile/service";
import { getParamValue, type PageSearchParams } from "@/lib/search-params";
import { cn } from "@/lib/utils";
export const dynamic = "force-dynamic";
@ -70,45 +69,23 @@ export default async function PlanningPage({ searchParams }: PlanningPageProps)
);
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} paramKeys={["error", "status"]} />
<header className="app-page-header">
<div>
<div className="app-page-breadcrumb">
<Link href="/dashboard" className="app-page-link">
Dashboard
</Link>
<span>/</span>
<span>Dagplanning</span>
</div>
<h1 className="mt-3 font-[family-name:var(--font-display)] text-4xl leading-tight">
Plan vandaag bewust klein
</h1>
<p className="app-page-copy">
Voeg alleen activiteiten toe die vandaag echt relevant zijn. Houd de lijst licht,
zodat je later goed kunt bijsturen zonder druk op te bouwen.
</p>
</div>
<div className="flex flex-wrap items-center gap-3">
<PageIntro
eyebrow="Planning"
title="Plan vandaag bewust klein"
description="Voeg alleen activiteiten toe die vandaag echt relevant zijn. Houd de lijst licht, zodat je later goed kunt bijsturen zonder druk op te bouwen."
aside={
<Link
href="/dashboard"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary"
>
Terug naar dashboard
</Link>
<form action={signOutAction}>
<Button type="submit" size="lg" className="h-11 rounded-full px-5">
Uitloggen
</Button>
</form>
</div>
</header>
}
/>
<section className="grid gap-5 lg:grid-cols-[1.1fr_0.9fr]">
<ActivityForm
@ -158,7 +135,7 @@ export default async function PlanningPage({ searchParams }: PlanningPageProps)
<CardContent className="space-y-3 pb-6 text-sm leading-7 text-primary-foreground/90">
<p>Deze planning blokkeert je niet en geeft nog geen harde waarschuwingen.</p>
<p>Je meter gebruikt een eenvoudige, uitlegbare afleiding uit duur en impact.</p>
<p>Niet-blokkerende overschrijdingsfeedback volgt in `ST-305`.</p>
<p>Bij overschrijding krijg je nu een warme, niet-blokkerende waarschuwing in plaats van een harde blokkade.</p>
</CardContent>
</Card>
</aside>
@ -169,6 +146,6 @@ export default async function PlanningPage({ searchParams }: PlanningPageProps)
categories={planningPageData.categories}
/>
</div>
</main>
</AppShell>
);
}

View file

@ -1,9 +1,9 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { signOutAction } from "@/app/auth-actions";
import { StatusToastBridge } from "@/components/feedback/status-toast-bridge";
import { AppShell } from "@/components/navigation/app-shell";
import { PageIntro } from "@/components/navigation/page-intro";
import { SettingsForm } from "@/components/settings/settings-form";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
@ -16,7 +16,6 @@ import { getAuthState } from "@/lib/auth/session";
import { getSettingsStatusToast } from "@/lib/feedback/status-messages";
import { getProfileBundleForCurrentUser } from "@/lib/profile/service";
import { getParamValue, type PageSearchParams } from "@/lib/search-params";
import { cn } from "@/lib/utils";
export const dynamic = "force-dynamic";
@ -57,45 +56,23 @@ export default async function SettingsPage({ searchParams }: SettingsPageProps)
"Ingelogde gebruiker";
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<StatusToastBridge toast={statusToast} paramKeys={["error", "status"]} />
<header className="app-page-header">
<div>
<div className="app-page-breadcrumb">
<Link href="/dashboard" className="app-page-link">
Dashboard
</Link>
<span>/</span>
<span>Instellingen</span>
</div>
<h1 className="mt-3 font-[family-name:var(--font-display)] text-4xl leading-tight">
Instellingen
</h1>
<p className="app-page-copy">
Pas je basisvoorkeuren rustig aan. Alles blijft beperkt tot jouw eigen
account en de wellness-first scope van release 1.
</p>
</div>
<div className="flex flex-wrap items-center gap-3">
<PageIntro
eyebrow="Instellingen"
title="Basisinstellingen voor jouw account"
description="Pas je basisvoorkeuren rustig aan. Alles blijft beperkt tot jouw eigen account en de wellness-first scope van release 1."
aside={
<Link
href="/dashboard"
className={cn(
buttonVariants({ variant: "outline", size: "lg" }),
"h-11 rounded-full px-5",
)}
className="inline-flex items-center rounded-full border border-border/80 bg-card/84 px-4 py-2 text-sm font-medium text-foreground shadow-[var(--shadow-1)] transition-colors hover:bg-secondary"
>
Terug naar dashboard
</Link>
<form action={signOutAction}>
<Button type="submit" size="lg" className="h-11 rounded-full px-5">
Uitloggen
</Button>
</form>
</div>
</header>
}
/>
<section className="grid gap-5 lg:grid-cols-[1.1fr_0.9fr]">
<SettingsForm profileBundle={profileBundle} />
@ -134,6 +111,6 @@ export default async function SettingsPage({ searchParams }: SettingsPageProps)
</aside>
</section>
</div>
</main>
</AppShell>
);
}

View file

@ -1,4 +1,5 @@
import { redirect } from "next/navigation";
import { AppShell } from "@/components/navigation/app-shell";
import { TestWizardFlow } from "@/components/wizard/test-wizard-flow";
import { sanitizeNextPath } from "@/lib/auth/navigation";
import { getAuthState } from "@/lib/auth/session";
@ -22,10 +23,10 @@ export default async function WizardTestPage() {
}
return (
<main className="app-page">
<div className="mx-auto flex max-w-6xl flex-col gap-8">
<AppShell contentClassName="space-y-8">
<div className="space-y-8">
<TestWizardFlow />
</div>
</main>
</AppShell>
);
}