Scrum4Me/app/page.tsx
janpeter visser ec9de5a962 fix: header en footer sticky op landingspagina
Zelfde patroon als (app) layout: h-screen overflow-hidden op de wrapper,
flex-1 overflow-y-auto op main, shrink-0 op footer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:32:32 +02:00

290 lines
18 KiB
TypeScript

import Link from 'next/link'
import { AppIcon } from '@/components/shared/app-icon'
export default function LandingPage() {
return (
<div className="h-screen bg-background text-foreground flex flex-col overflow-hidden">
{/* ── Header ─────────────────────────────────────────────────── */}
<header className="h-14 border-b border-border bg-surface-container-low flex items-center px-6 gap-4 shrink-0">
<Link href="/" className="flex items-center gap-2 font-semibold text-primary">
<AppIcon size={24} />
Scrum4Me
</Link>
<nav className="ml-auto flex items-center gap-2">
<Link
href="/login"
className="px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors"
>
Inloggen
</Link>
<Link
href="/register"
className="px-4 py-1.5 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90 transition-opacity font-medium"
>
Registreren
</Link>
</nav>
</header>
<main className="flex-1 overflow-y-auto">
{/* ── Hero ───────────────────────────────────────────────────── */}
<section className="bg-primary-container px-6 py-16 text-center">
<div className="max-w-2xl mx-auto space-y-4">
<h1 className="text-3xl font-semibold text-primary-container-foreground">
Scrum planner voor solo developers en kleine teams
</h1>
<p className="text-base text-primary-container-foreground/80 leading-relaxed">
Houd meerdere projecten bij in één overzicht. Plan Product Backlogs, beheer Sprints
met drag-and-drop en laat Claude Code taken oppakken via een REST API.
</p>
<div className="flex gap-3 justify-center pt-2">
<Link
href="/register"
className="px-5 py-2.5 rounded-lg bg-primary text-primary-foreground text-sm font-medium hover:opacity-90 transition-opacity"
>
Account aanmaken
</Link>
<Link
href="/login"
className="px-5 py-2.5 rounded-lg border border-primary text-primary bg-transparent text-sm font-medium hover:bg-primary/10 transition-colors"
>
Demo bekijken
</Link>
</div>
<p className="text-xs text-primary-container-foreground/60 pt-1">
Demo-login: gebruikersnaam <code className="font-mono bg-primary-container-foreground/10 px-1 rounded">demo</code> · wachtwoord <code className="font-mono bg-primary-container-foreground/10 px-1 rounded">demo1234</code>
</p>
</div>
</section>
{/* ── Wat is Scrum4Me ────────────────────────────────────────── */}
<section className="px-6 py-14 bg-background">
<div className="max-w-4xl mx-auto">
<h2 className="text-xl font-semibold mb-2">Wat is Scrum4Me?</h2>
<p className="text-muted-foreground text-sm mb-10 max-w-2xl">
Scrum4Me is een desktop-first webapplicatie die Scrum lichtgewicht maakt zonder
de overhead van grote tools als Jira of Linear. Ontworpen voor developers die
zelf de regie willen houden over hun planning.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-2">
<div className="text-sm font-medium text-primary">Hiërarchisch plannen</div>
<p className="text-sm text-muted-foreground leading-relaxed">
Organiseer werk in producten, Product Backlog Items, stories en taken.
Alles op één plek, gegroepeerd op prioriteit.
</p>
</div>
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-2">
<div className="text-sm font-medium text-primary">Sprint-beheer</div>
<p className="text-sm text-muted-foreground leading-relaxed">
Start een Sprint met een doel, sleep stories naar de Sprint Backlog en
volg de voortgang per story via taken en statusupdates.
</p>
</div>
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-2">
<div className="text-sm font-medium text-primary">Claude Code-integratie</div>
<p className="text-sm text-muted-foreground leading-relaxed">
Maak een API-token aan en laat Claude Code de volgende story ophalen,
taken uitvoeren en resultaten vastleggen via de REST API.
</p>
</div>
</div>
</div>
</section>
{/* ── Scrum samenvatting ─────────────────────────────────────── */}
<section className="px-6 py-14 bg-surface-container-low border-y border-border">
<div className="max-w-4xl mx-auto">
<h2 className="text-xl font-semibold mb-2">Scrum in Scrum4Me</h2>
<p className="text-muted-foreground text-sm mb-10 max-w-2xl">
Scrum4Me past een lichtgewicht versie van Scrum toe de essentie zonder ceremony-overhead.
Hieronder staat hoe de kernbegrippen zijn vertaald naar de app.
</p>
{/* Hiërarchie */}
<div className="mb-10">
<h3 className="text-sm font-semibold text-foreground mb-4 uppercase tracking-wide">Hiërarchie</h3>
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-2">
{[
{ label: 'Product', sub: 'Een softwareproject of codebase' },
{ label: 'PBI', sub: 'Product Backlog Item — een feature of verbetering' },
{ label: 'Story', sub: 'Concrete user story binnen een PBI' },
{ label: 'Taak', sub: 'Implementatiestap binnen een story' },
].map((item, i, arr) => (
<div key={item.label} className="flex items-center gap-2">
<div className="bg-primary-container border border-primary/20 rounded-lg px-4 py-2.5 min-w-[100px]">
<div className="text-sm font-medium text-primary-container-foreground">{item.label}</div>
<div className="text-xs text-primary-container-foreground/60 leading-tight mt-0.5">{item.sub}</div>
</div>
{i < arr.length - 1 && (
<span className="text-muted-foreground text-lg hidden sm:block"></span>
)}
</div>
))}
</div>
</div>
{/* Terminologie */}
<div className="mb-10">
<h3 className="text-sm font-semibold text-foreground mb-4 uppercase tracking-wide">Terminologie</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{[
{ term: 'Product Backlog', def: 'Geordende lijst van alle PBI\'s per product, gesorteerd op prioriteit (kritiek → laag) en positie.' },
{ term: 'Sprint', def: 'Actief tijdblok met een Sprint Goal. Per product is er maximaal één actieve Sprint tegelijk.' },
{ term: 'Sprint Backlog', def: 'De stories die voor deze Sprint zijn geselecteerd. Stories worden vanuit de Product Backlog gesleept.' },
{ term: 'Sprint Planning', def: 'Scherm waar taken per story worden aangemaakt en geordend. Claude Code werkt vanuit dit niveau.' },
{ term: 'Story-status', def: 'OPEN → IN_SPRINT → DONE. Bepaalt zichtbaarheid in backlogs en Sprint-schermen.' },
{ term: 'Taakstatus', def: 'TO_DO → IN_PROGRESS → DONE. Wordt bijgehouden via UI of REST API door Claude Code.' },
{ term: 'Activiteitenlog', def: 'Per story worden implementatieplan, testresultaat en commit vastgelegd via de API of UI.' },
{ term: 'Sprint afronden', def: 'Bij afsluiting wordt per story gekozen: markeer als Done of zet terug naar Backlog.' },
].map(({ term, def }) => (
<div key={term} className="bg-background border border-border rounded-lg p-4">
<div className="text-sm font-medium mb-1">{term}</div>
<div className="text-xs text-muted-foreground leading-relaxed">{def}</div>
</div>
))}
</div>
</div>
{/* Rollen */}
<div>
<h3 className="text-sm font-semibold text-foreground mb-4 uppercase tracking-wide">Rollen</h3>
<div className="flex flex-wrap gap-3">
{[
{ role: 'Product Owner', desc: 'Bepaalt prioriteit van PBI\'s en beheert de Product Backlog.' },
{ role: 'Scrum Master', desc: 'Bewaakt het Scrum-proces en verwijdert obstakels.' },
{ role: 'Developer', desc: 'Voert stories en taken uit; werkt via UI of Claude Code.' },
].map(({ role, desc }) => (
<div key={role} className="bg-secondary-container border border-secondary/20 rounded-lg px-4 py-3 flex-1 min-w-[180px]">
<div className="text-sm font-medium text-secondary-container-foreground">{role}</div>
<div className="text-xs text-secondary-container-foreground/70 mt-1">{desc}</div>
</div>
))}
</div>
<p className="text-xs text-muted-foreground mt-3">
In v1 is één account gelijk aan één gebruiker met alle rollen. Teamgebruik met rolscheiding volgt in v2.
</p>
</div>
</div>
</section>
{/* ── Gebruikershandleiding ─────────────────────────────────── */}
<section className="px-6 py-14 bg-background">
<div className="max-w-4xl mx-auto">
<h2 className="text-xl font-semibold mb-2">Gebruikershandleiding</h2>
<p className="text-muted-foreground text-sm mb-10 max-w-2xl">
Volg deze stappen om van een leeg account naar een volledig ingeplande Sprint te gaan.
</p>
<div className="space-y-3">
{[
{
step: '1',
title: 'Account aanmaken',
desc: 'Ga naar Registreren en kies een gebruikersnaam en wachtwoord. Na registratie word je direct doorgestuurd naar het dashboard. Wil je eerst rondkijken? Log in met de demo-account (alleen leesrechten).',
},
{
step: '2',
title: 'Product aanmaken',
desc: 'Klik op "Nieuw product" op het dashboard. Vul naam, optionele beschrijving, repo-URL en je Definition of Done in. Het product wordt zichtbaar op het dashboard.',
},
{
step: '3',
title: 'Product Backlog opbouwen',
desc: 'Open het product en voeg PBI\'s toe via het linkerpaneel. Geef elk PBI een prioriteit (Kritiek / Hoog / Gemiddeld / Laag). Klik op een PBI om in het rechterpaneel stories toe te voegen. Versleep PBI\'s en stories om de volgorde aan te passen.',
},
{
step: '4',
title: 'Sprint starten',
desc: 'Klik op "Sprint starten" op de productpagina en voer een Sprint Goal in. Per product is er maximaal één actieve Sprint tegelijk. Het Sprint-scherm wordt zichtbaar via de navigatie.',
},
{
step: '5',
title: 'Sprint Backlog vullen',
desc: 'Ga naar het Sprint-scherm. Sleep stories vanuit de Product Backlog (rechterpaneel) naar de Sprint Backlog (linkerpaneel). Stories krijgen automatisch de status IN_SPRINT.',
},
{
step: '6',
title: 'Taken aanmaken (Sprint Planning)',
desc: 'Ga naar Sprint Planning. Selecteer een story in het linkerpaneel om taken toe te voegen in het rechterpaneel. Maak concrete implementatiestappen als taken en orden ze met drag-and-drop.',
},
{
step: '7',
title: 'API-token aanmaken voor Claude Code',
desc: 'Ga naar Instellingen → Tokens. Maak een nieuw token aan en kopieer de waarde direct — die is daarna niet meer zichtbaar. Gebruik het token als Bearer-token in Claude Code of je eigen scripts.',
},
{
step: '8',
title: 'Claude Code koppelen',
desc: 'Configureer Claude Code met je API-token. Claude haalt via GET /api/products/:id/next-story de hoogst geprioriteerde open story op, werkt taken bij via PATCH /api/tasks/:id en legt het implementatieplan, testresultaten en commits vast via POST /api/stories/:id/log.',
},
{
step: '9',
title: 'Sprint afronden',
desc: 'Klik op "Sprint afronden" op het Sprint-scherm. Voor elke story kies je: markeer als Done of zet terug naar de Product Backlog. Daarna is een nieuwe Sprint aanmaakbaar.',
},
].map(({ step, title, desc }) => (
<div key={step} className="flex gap-4 bg-surface-container-low border border-border rounded-xl p-5">
<div className="shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground text-sm font-semibold flex items-center justify-center">
{step}
</div>
<div className="space-y-1">
<div className="text-sm font-medium">{title}</div>
<div className="text-sm text-muted-foreground leading-relaxed">{desc}</div>
</div>
</div>
))}
</div>
</div>
</section>
{/* ── API-overzicht ─────────────────────────────────────────── */}
<section className="px-6 py-14 bg-surface-container-low border-t border-border">
<div className="max-w-4xl mx-auto">
<h2 className="text-xl font-semibold mb-2">REST API voor Claude Code</h2>
<p className="text-muted-foreground text-sm mb-8 max-w-2xl">
Alle API-endpoints vereisen een <code className="font-mono bg-surface-container px-1 rounded text-xs">Authorization: Bearer &lt;token&gt;</code> header.
Tokens beheer je via Instellingen Tokens.
</p>
<div className="space-y-2">
{[
{ method: 'GET', path: '/api/products', desc: 'Lijst van actieve producten' },
{ method: 'GET', path: '/api/products/:id/next-story', desc: 'Hoogst geprioriteerde open story van de actieve Sprint' },
{ method: 'GET', path: '/api/sprints/:id/tasks?limit=10', desc: 'Eerste N taken van de Sprint op volgorde' },
{ method: 'PATCH', path: '/api/stories/:id/tasks/reorder', desc: 'Taakvolgorde aanpassen (body: { task_ids: string[] })' },
{ method: 'POST', path: '/api/stories/:id/log', desc: 'Activiteit vastleggen: implementatieplan, testresultaat of commit' },
{ method: 'PATCH', path: '/api/tasks/:id', desc: 'Taakstatus of implementatieplan bijwerken' },
{ method: 'POST', path: '/api/todos', desc: 'Todo aanmaken (body: { title, product_id })' },
].map(({ method, path, desc }) => (
<div key={path} className="flex items-start gap-3 bg-background border border-border rounded-lg px-4 py-3">
<span className={`shrink-0 text-xs font-mono font-semibold px-2 py-0.5 rounded ${
method === 'GET' ? 'bg-tertiary-container text-tertiary-container-foreground' :
method === 'POST' ? 'bg-success-container text-success-container-foreground' :
'bg-warning-container text-warning-container-foreground'
}`}>
{method}
</span>
<code className="text-xs font-mono text-foreground shrink-0">{path}</code>
<span className="text-xs text-muted-foreground">{desc}</span>
</div>
))}
</div>
</div>
</section>
</main>
{/* ── Footer ─────────────────────────────────────────────────── */}
<footer className="shrink-0 border-t border-border bg-surface-container-low px-6 py-4 flex items-center justify-between text-xs text-muted-foreground">
<span>© {new Date().getFullYear()} Scrum4Me</span>
<div className="flex gap-4">
<Link href="/login" className="hover:text-foreground transition-colors">Inloggen</Link>
<Link href="/register" className="hover:text-foreground transition-colors">Registreren</Link>
</div>
</footer>
</div>
)
}