Scrum4Me/docs/design/styling.md
Janpeter Visser 7e45bbdbc0
docs: AI-optimized docs restructure (Phases 1–8) (#61)
* docs(dialog-pattern): add generic entity-dialog spec

Introduceert docs/patterns/dialog.md als bron-of-truth voor elke
create/edit/detail-dialog in Scrum4Me, ongeacht het achterliggende
dataobject. Bevat 14 secties: uitgangspunten, stack, component-
architectuur, layout, validatie, drielaagse demo-policy, submission,
dialog-gedrag, theming, footer, triggers/URL-state, per-entiteit
profile-template, out-of-scope, en een verificatie-checklist.

Registreert het patroon in CLAUDE.md "Implementatiepatronen"-tabel
zodat Claude (en mensen) de spec verplicht raadplegen voor elke
nieuwe dialog.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(dialog-pattern): convert task spec + add pbi/story entity-profiles

Reduceert docs/scrum4me-task-dialog.md van 507 naar ~140 regels: alle
gedeelde regels verhuisd naar docs/patterns/dialog.md, dit document
bevat nu alleen Task-specifieke velden, URL-pattern, status-veld,
server actions, triggers en bewuste out-of-scope-keuzes.

Voegt twee nieuwe entity-profielen toe voor bestaande dialogen:
- docs/scrum4me-pbi-dialog.md (PbiDialog: state-based, code+title-rij,
  PbiStatusSelect, geen delete in v1)
- docs/scrum4me-story-dialog.md (StoryDialog: state-based, header met
  status/priority badges, inline activity-log, demo-readonly-fallback,
  inline-delete-confirm i.p.v. AlertDialog)

Beide profielen documenteren expliciet de "Bekende gaps t.o.v.
generieke spec" zodat opvolgende PR's de afwijkingen kunnen
rechtzetten of bewust kunnen accorderen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Added pdevelopment docs

* docs(plans): add docs-restructure plan for AI-optimized lookup

Audit of existing 39 doc files (~10.700 lines) and a phased restructure
proposal aimed at minimising the tokens an AI agent has to read to find
the right reference. Captures resolved decisions on language (English),
ADR template (Nygard default with MADR escape-hatch), index generator
(node script), and folder taxonomy. Proposal status — fase 1 to follow.

* docs(adr): add ADR scaffolding (templates, README, meta-ADR)

Set up docs/adr/ as the canonical home for architecture decisions:

- templates/nygard.md — default four-section format (Status, Context,
  Decision, Consequences) for one-way-door decisions.
- templates/madr.md — MADR v4 with YAML front-matter and explicit
  Considered Options for decisions where rejected alternatives matter.
- README.md — naming convention (NNNN-kebab-case), template-selection
  guidance (Nygard default; MADR for auth, queue mechanics, agent
  integration), status lifecycle, and ADR roster.
- 0000-record-architecture-decisions.md — meta-ADR establishing the
  practice itself, in Nygard format.

Backfilling existing implicit decisions (base-ui-over-radix, float
sort_order, demo-user three-layer policy, etc.) is fase 6 of the
docs-restructure plan.

* feat(docs): add docs index generator + initial INDEX.md

scripts/generate-docs-index.mjs walks docs/**/*.md, parses YAML
front-matter (or first H1 fallback) and a Nygard-style ## Status
section, then writes docs/INDEX.md with grouped tables for ADRs,
Specs, Plans (with archive subsection), Patterns, and Other.

Pure Node 20 (no external deps); idempotent — running it twice
produces byte-identical output. Excludes adr/templates/, the ADR
README, INDEX.md itself, and any *_*.md sidecar file.

Wire-up:
- package.json: docs:index → node scripts/generate-docs-index.mjs

Initial run indexed 35 docs across the existing structure; the
generated INDEX.md is committed so the table is reviewable in the
PR before hooking generation into a pre-commit step.

* chore: ignore Obsidian vault and personal sidecar files

Add .obsidian/ (Obsidian vault config) and _*.md (personal sidecar
notes) to .gitignore so the docs/ tree can serve as canonical source
of truth while still being usable as an Obsidian vault for personal
authoring. The docs index generator already excludes the same _*.md
pattern from INDEX.md.

* docs(plans): add PBI bulk-create spec for docs-restructure

Machine-parseable spec for an executor that calls the scrum4me MCP
(create_pbi → create_story → create_task) to seed the docs-restructure
work into the DB.

- Section 1 (Context) is the PBI description; serves as task-context
  via mcp__scrum4me__get_claude_context.
- Section 2 lists the 6 resolved decisions (English, MD3+styling
  merged, solo-paneel merged, .Plans archived, Nygard ADR default,
  node index script).
- Section 3 records what already shipped on this branch so the
  executor doesn't duplicate the ADR scaffolding or index generator.
- Section 4 carries the structured YAML graph: 1 PBI, 8 stories
  (one per phase), 39 tasks. product_id is REPLACE_ME — fill before
  running.
- YAML validated with PyYAML; field schema sanity-checked.

* docs(junk-cleanup): remove stub patterns/test.md

* docs(junk-cleanup): archive .Plans/ to docs/plans/archive/

* docs(front-matter): add YAML front-matter to docs/ root

* docs(front-matter): add YAML front-matter to patterns/

* docs(front-matter): add YAML front-matter to plans + agent files

* docs(index): regenerate INDEX.md after front-matter pass

* docs(naming): drop scrum4me- prefix from doc filenames

* docs(naming): lowercase API.md and MD3 filenames

* docs(naming): rename plan file to kebab-case ASCII

* docs(naming): rename middleware.md to proxy.md (next 16)

* docs(naming): polish CLAUDE.md doc-index after renames

* docs(taxonomy): scaffold topical folders under docs/

* docs(taxonomy): move spec files into docs/specs/

* docs(taxonomy): move design/api/qa/backlog/assets into folders

* docs(taxonomy): move agent-instruction-audit into decisions/

* docs(split): break architecture.md into 6 topical files

* docs(split): merge solo-paneel-spec into specs/functional.md

* docs(split): merge md3-color-scheme into design/styling

* docs(trim): extract branch/commit rules into runbook

* docs(trim): extract MCP integration into runbook

* docs(adr): add 0001-base-ui-over-radix

* docs(adr): add 0002-float-sort-order

* docs(adr): add 0003-one-branch-per-milestone

* docs(adr): add 0004-status-enum-mapping

* docs(adr): add 0005-iron-session-over-nextauth

* docs(adr): add 0006-demo-user-three-layer-policy

* docs(adr): add 0007-claude-question-channel-design

* docs(adr): add 0008-agent-instructions-in-claude-md + update README index

* docs(index): regenerate after ADR 0001-0008

* docs(glossary): add docs/glossary.md

* chore(docs): regenerate INDEX.md in pre-commit hook

* docs(readme): link INDEX + glossary + agent instructions

* feat(docs): add doc-link checker script

* chore(docs): wire docs:check-links and docs npm scripts

* ci(docs): block merge on broken doc links

* docs(links): fix broken cross-references after restructure

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 03:21:59 +02:00

43 KiB
Raw Blame History

title status audience language last_updated
Scrum4Me — Styling & Design System active
ai-agent
contributor
nl 2026-05-03

Scrum4Me — Styling & Design System

Versie: 0.1 — april 2026 Onderdeel van: CLAUDE.md context-set


Overzicht

Scrum4Me gebruikt Material Design 3 (MD3) als kleurfilosofie, geïmplementeerd via CSS custom properties in theme.css en direct bruikbaar als Tailwind utility classes. shadcn/ui levert alle UI-primitieven (Button, Dialog, Sheet, Badge, etc.) en is volledig compatibel met het MD3-kleurensysteem via de legacy-token-mapping.

Lees dit document voordat je een component schrijft. Gebruik nooit willekeurige Tailwind-kleuren zoals bg-blue-500 of bg-green-600 — gebruik altijd de semantische tokens uit dit systeem.


Setup

1. theme.css plaatsen

Kopieer het meegeleverde theme.css bestand naar:

app/globals.css   ← importeer theme.css hier, of plak de inhoud direct

Of als apart bestand:

styles/theme.css

Importeer in app/globals.css:

@import './styles/theme.css';

2. shadcn/ui initialiseren

npx shadcn@latest init

Kies bij de setup:

  • Style: Default
  • Base color: Slate (wordt overschreven door theme.css)
  • CSS variables: Yes

De theme.css overschrijft alle shadcn default-kleuren via CSS custom properties. Geen extra configuratie nodig.

3. Tailwind configuratie

theme.css registreert alle tokens via @theme inline — ze zijn direct beschikbaar als Tailwind utility classes:

// Werkt direct:
className="bg-primary text-primary-foreground"
className="bg-surface-container-low"
className="bg-status-done"
className="bg-priority-critical"

4. Dark mode

Dark mode werkt via de .dark class op <html>:

// components/theme-toggle.tsx
'use client'
import { useState, useEffect } from 'react'

export function ThemeToggle() {
  const [isDark, setIsDark] = useState(false)

  useEffect(() => {
    const stored = localStorage.getItem('theme')
    if (stored === 'dark') {
      document.documentElement.classList.add('dark')
      setIsDark(true)
    }
  }, [])

  const toggle = () => {
    document.documentElement.classList.toggle('dark')
    const next = !isDark
    setIsDark(next)
    localStorage.setItem('theme', next ? 'dark' : 'light')
  }

  return (
    <button onClick={toggle} className="text-muted-foreground hover:text-foreground">
      {isDark ? '☀️' : '🌙'}
    </button>
  )
}

Kleurfilosofie

Drie hoofdrollen, elk met een semantische betekenis voor een Scrum-planner:

Rol Kleur Betekenis Gebruik in Scrum4Me
Primary Blauw #0061a4 Productiviteit, vertrouwen Primaire knoppen, actieve navigatie, Sprint Goal
Secondary Paars #5b5e71 Planning, organisatie Secundaire acties, filters, toolbar-items
Tertiary Teal #006874 Voortgang, data Voortgangsindicatoren, story-tellers, metrics

Diepte wordt gecreëerd via tonal elevation (lichtere/donkerdere oppervlakken), niet via schaduwen.


Surface Elevation System

Gebruik deze hiërarchie consequent — nooit shadow-lg voor diepte:

HOOGSTE ELEVATIE (voorgrond)
  surface-container-lowest   → dialogs, modals, popovers
  surface-container-low      → kaarten, panelen
  surface-container          → standaard container
  surface-container-high     → geneste containers
  surface-container-highest  → achtergrondcontainers
LAAGSTE ELEVATIE (achtergrond)
  background                 → app-achtergrond

In Scrum4Me specifiek

Element Surface token
App achtergrond bg-background
Navigatiebalk bg-surface-container-low
Gesplitst scherm (elk paneel) bg-surface-container-low
PBI-rij bg-surface-container
Geselecteerde PBI-rij bg-primary-container
Story-blok bg-surface-container-low border border-border
Story-blok (geselecteerd) bg-primary-container border border-primary
Taakregel bg-surface-container
Dialogs / modals bg-surface-container-lowest
Slide-over (story detail) bg-surface-container-lowest
Todo-item bg-surface-container
Navigatiebar per paneel bg-surface-container-highest

Statuskleur mapping

Story- en taakstatus

Gebruik altijd icoon + tekst naast kleur (toegankelijkheid):

// Status badge component
const statusConfig = {
  OPEN: {
    label: 'Open',
    className: 'bg-status-todo text-white',
  },
  IN_SPRINT: {
    label: 'In Sprint',
    className: 'bg-status-in-progress text-white',
  },
  DONE: {
    label: 'Done',
    className: 'bg-status-done text-white',
  },
}

// Taakstatus
const taskStatusConfig = {
  TO_DO: {
    label: 'To Do',
    className: 'bg-status-todo text-white',
  },
  IN_PROGRESS: {
    label: 'In Progress',
    className: 'bg-status-in-progress text-white',
  },
  DONE: {
    label: 'Done',
    className: 'bg-status-done text-white',
  },
}

Prioriteitskleur mapping

const priorityConfig = {
  1: {
    label: 'Kritiek',
    className: 'bg-priority-critical text-white',
    borderClassName: 'border-l-4 border-priority-critical',
  },
  2: {
    label: 'Hoog',
    className: 'bg-priority-high text-white',
    borderClassName: 'border-l-4 border-priority-high',
  },
  3: {
    label: 'Middel',
    className: 'bg-priority-medium text-white',
    borderClassName: 'border-l-4 border-priority-medium',
  },
  4: {
    label: 'Laag',
    className: 'bg-priority-low text-white',
    borderClassName: 'border-l-4 border-priority-low',
  },
}

Story-activiteitenlog

const logTypeConfig = {
  IMPLEMENTATION_PLAN: {
    label: 'Implementatieplan',
    className: 'bg-info-container text-info-container-foreground border-l-4 border-info',
  },
  TEST_RESULT: {
    PASSED: {
      label: 'Tests geslaagd',
      className: 'bg-success-container text-success-container-foreground border-l-4 border-success',
    },
    FAILED: {
      label: 'Tests mislukt',
      className: 'bg-error-container text-error-container-foreground border-l-4 border-error',
    },
  },
  COMMIT: {
    label: 'Commit',
    className: 'bg-secondary-container text-secondary-container-foreground border-l-4 border-secondary',
  },
}

shadcn/ui componenten — gebruik in Scrum4Me

Alle shadcn-componenten gebruiken automatisch het MD3-kleurensysteem. Hieronder de aanbevolen varianten per context.

Button

import { Button } from '@/components/ui/button'

// Primaire actie (Sprint starten, PBI aanmaken, Opslaan)
<Button>Sprint starten</Button>

// Secundaire actie (Annuleren, Filters, Exporteren)
<Button variant="secondary">Annuleren</Button>

// Destructieve actie (Verwijderen, Archiveren)
<Button variant="destructive">Verwijderen</Button>

// Ghost (icon-knoppen in navigatiebar)
<Button variant="ghost" size="icon">
  <PlusIcon className="h-4 w-4" />
</Button>

// Outline (minder urgente acties)
<Button variant="outline">Details bekijken</Button>

Badge (status en prioriteit)

import { Badge } from '@/components/ui/badge'

// Gebruik custom className voor MD3-kleuren
// shadcn Badge variant="secondary" is ook bruikbaar voor neutrale badges

<Badge className="bg-status-done text-white">Done</Badge>
<Badge className="bg-priority-critical text-white">Kritiek</Badge>
<Badge className="bg-status-in-progress text-white">In Sprint</Badge>

// Neutrale info badge (bijv. "3 taken")
<Badge variant="secondary">3 taken</Badge>

PBI-status (READY / BLOCKED / DONE): hergebruikt bestaande tokens — status-todo voor READY, status-blocked voor BLOCKED, status-done voor DONE. Centraal gedefinieerd in components/shared/pbi-status-select.tsx (PBI_STATUS_LABELS, PBI_STATUS_COLORS); importeer die in plaats van kleuren ad-hoc te kopiëren.

Dialog (bevestigingsdialogen)

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog'

// Standaard bevestigingsdialoog voor verwijderacties
<AlertDialogContent className="bg-surface-container-lowest">
  <AlertDialogHeader>
    <AlertDialogTitle>PBI verwijderen?</AlertDialogTitle>
    <AlertDialogDescription>
      Dit verwijdert ook alle gekoppelde stories en taken. Deze actie is niet ongedaan te maken.
    </AlertDialogDescription>
  </AlertDialogHeader>
  <AlertDialogFooter>
    <AlertDialogCancel>Annuleren</AlertDialogCancel>
    <AlertDialogAction className="bg-destructive text-destructive-foreground">
      Verwijderen
    </AlertDialogAction>
  </AlertDialogFooter>
</AlertDialogContent>

Sheet (story detail slide-over)

import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet'

<Sheet>
  <SheetContent
    side="right"
    className="w-[480px] bg-surface-container-lowest border-l border-border"
  >
    <SheetHeader>
      <SheetTitle className="text-foreground">{story.title}</SheetTitle>
    </SheetHeader>
    {/* story detail inhoud */}
  </SheetContent>
</Sheet>

Input en Textarea

import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'

// shadcn Input gebruikt --input-background automatisch uit theme.css
<Input
  placeholder="PBI titel"
  className="bg-input-background border-border focus:ring-primary"
/>

<Textarea
  placeholder="Omschrijving (optioneel)"
  className="bg-input-background border-border focus:ring-primary resize-none"
/>

Select (prioriteit dropdown)

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'

<Select>
  <SelectTrigger className="bg-input-background border-border">
    <SelectValue placeholder="Prioriteit" />
  </SelectTrigger>
  <SelectContent className="bg-surface-container-lowest border-border">
    <SelectItem value="1">
      <span className="flex items-center gap-2">
        <span className="w-2 h-2 rounded-full bg-priority-critical" />
        Kritiek
      </span>
    </SelectItem>
    <SelectItem value="2">
      <span className="flex items-center gap-2">
        <span className="w-2 h-2 rounded-full bg-priority-high" />
        Hoog
      </span>
    </SelectItem>
    <SelectItem value="3">
      <span className="flex items-center gap-2">
        <span className="w-2 h-2 rounded-full bg-priority-medium" />
        Middel
      </span>
    </SelectItem>
    <SelectItem value="4">
      <span className="flex items-center gap-2">
        <span className="w-2 h-2 rounded-full bg-priority-low" />
        Laag
      </span>
    </SelectItem>
  </SelectContent>
</Select>

Skeleton (loading states)

import { Skeleton } from '@/components/ui/skeleton'

// PBI lijst skeleton
function PbiListSkeleton() {
  return (
    <div className="space-y-2 p-4">
      {Array.from({ length: 5 }).map((_, i) => (
        <Skeleton key={i} className="h-12 w-full bg-surface-container-high" />
      ))}
    </div>
  )
}

// Story blokken skeleton
function StoryGridSkeleton() {
  return (
    <div className="flex flex-wrap gap-3 p-4">
      {Array.from({ length: 6 }).map((_, i) => (
        <Skeleton key={i} className="h-24 w-[10%] min-w-[100px] bg-surface-container-high" />
      ))}
    </div>
  )
}

Tooltip (demo-gebruiker write-protection)

import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'

// Gebruik voor alle uitgeschakelde knoppen bij demo-gebruiker
function DemoProtectedButton({ children, isDemo, onClick, ...props }) {
  if (!isDemo) {
    return <Button onClick={onClick} {...props}>{children}</Button>
  }

  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <span>
            <Button disabled {...props}>{children}</Button>
          </span>
        </TooltipTrigger>
        <TooltipContent className="bg-surface-container-lowest border-border">
          <p className="text-sm text-muted-foreground">Niet beschikbaar in demo-modus</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  )
}

Scrum4Me component patronen

PBI-rij

// Geselecteerd PBI heeft primary-container achtergrond
<div
  className={cn(
    "flex items-center gap-3 px-4 py-3 rounded-lg cursor-pointer transition-colors border-l-4",
    priorityConfig[pbi.priority].borderClassName,
    isSelected
      ? "bg-primary-container text-primary-container-foreground"
      : "bg-surface-container hover:bg-surface-container-high"
  )}
  onClick={() => setSelectedPbi(pbi.id)}
>
  <span className="flex-1 text-sm font-medium truncate">{pbi.title}</span>
  <Badge className={priorityConfig[pbi.priority].className}>
    {priorityConfig[pbi.priority].label}
  </Badge>
</div>

Story-blok

// ~10% schermbreedte, compacte weergave
<div
  className={cn(
    "relative flex flex-col gap-1 p-3 rounded-lg border cursor-pointer",
    "min-w-[100px] w-[10%] h-24 text-xs",
    "transition-colors hover:border-primary",
    "bg-surface-container-low border-border"
  )}
>
  <span className="font-medium leading-tight line-clamp-2">{story.title}</span>
  <div className="mt-auto flex items-center justify-between">
    <span className={cn("px-1.5 py-0.5 rounded text-[10px] font-medium", statusConfig[story.status].className)}>
      {statusConfig[story.status].label}
    </span>
    <span className={cn("w-2 h-2 rounded-full", `bg-priority-${priorityLabel}`)}>
    </span>
  </div>
</div>

Prioriteitsgroep scheidingslijn

// Visuele scheiding per prioriteitsgroep in PBI-lijst en story-grid
<div className="mt-4 mb-2">
  <div className="flex items-center gap-2">
    <span className={cn(
      "text-xs font-semibold uppercase tracking-wider",
      priority === 1 && "text-priority-critical",
      priority === 2 && "text-priority-high",
      priority === 3 && "text-priority-medium",
      priority === 4 && "text-priority-low",
    )}>
      {priorityConfig[priority].label}
    </span>
    <div className={cn(
      "flex-1 h-px",
      priority === 1 && "bg-priority-critical/30",
      priority === 2 && "bg-priority-high/30",
      priority === 3 && "bg-priority-medium/30",
      priority === 4 && "bg-priority-low/30",
    )} />
    <span className="text-xs text-muted-foreground">{count}</span>
  </div>
</div>

Voortgangsindicator (story → taken)

// Gebruikt tertiary kleur voor voortgang
function StoryProgress({ done, total }: { done: number; total: number }) {
  const pct = total === 0 ? 0 : Math.round((done / total) * 100)

  return (
    <div className="flex items-center gap-2 text-xs">
      <div className="flex-1 h-1.5 bg-surface-container-highest rounded-full overflow-hidden">
        <div
          className="h-full bg-tertiary rounded-full transition-all"
          style={{ width: `${pct}%` }}
        />
      </div>
      <span className="text-muted-foreground tabular-nums">
        {done}/{total}
      </span>
    </div>
  )
}

Activiteitenlog entry

function LogEntry({ entry }: { entry: StoryLog }) {
  const config = entry.type === 'TEST_RESULT'
    ? logTypeConfig.TEST_RESULT[entry.status ?? 'PASSED']
    : logTypeConfig[entry.type]

  return (
    <div className={cn("rounded-lg p-3 text-sm", config.className)}>
      <div className="flex items-center justify-between mb-1">
        <span className="font-medium text-xs uppercase tracking-wide">
          {config.label}
        </span>
        <span className="text-xs opacity-70">
          {formatDate(entry.created_at)}
        </span>
      </div>
      <p className="text-sm leading-relaxed whitespace-pre-wrap">
        {entry.content}
      </p>
      {entry.commit_hash && (
        <a
          href={`${repoUrl}/commit/${entry.commit_hash}`}
          target="_blank"
          rel="noopener noreferrer"
          className="mt-1 inline-flex items-center gap-1 text-xs font-mono opacity-80 hover:opacity-100 underline"
        >
          {entry.commit_hash.slice(0, 7)}  {entry.commit_message}
        </a>
      )}
    </div>
  )
}

Sprint Goal banner

// Prominent bovenaan Sprint-schermen
<div className="bg-primary-container text-primary-container-foreground rounded-lg px-4 py-3 mb-4">
  <span className="text-xs font-semibold uppercase tracking-wider opacity-70">
    Sprint Goal
  </span>
  <p className="mt-0.5 font-medium">{sprint.sprint_goal}</p>
</div>

Toast notificaties (Sonner)

import { toast } from 'sonner'

// Success (aanmaken, opslaan)
toast.success('PBI aangemaakt')
toast.success('Story toegevoegd aan Sprint')

// Error (mislukte Server Action)
toast.error('Opslaan mislukt. Probeer opnieuw.')

// Info (neutrale melding)
toast.info('Sprint afgerond')

// Geen toast bij drag-and-drop (te frequent)

Regels (nooit overtreden)

❌ bg-blue-500, bg-green-600, bg-red-400    → gebruik semantische tokens
❌ shadow-lg, shadow-md                     → gebruik surface elevation
❌ opacity-50 op een primary button         → gebruik -container variant
❌ Kleur alleen voor status (geen tekst)    → altijd tekst + kleur
❌ Hardcoded hex-waarden in className       → altijd via CSS token
❌ bg-white of bg-black                     → bg-background of bg-foreground

✅ bg-primary text-primary-foreground
✅ bg-surface-container-low
✅ bg-status-done + tekst "Done"
✅ bg-error-container text-error-container-foreground
✅ border-l-4 border-priority-critical

Bestandslocaties

styles/
  theme.css                 ← bronbestand, niet aanpassen
app/
  globals.css               ← importeert theme.css
components/
  ui/                       ← shadcn/ui (auto-gegenereerd, niet aanpassen)
  shared/
    status-badge.tsx        ← herbruikbare status badge
    priority-badge.tsx      ← herbruikbare prioriteit badge
    demo-button.tsx         ← Button met demo-protection tooltip
    story-log.tsx           ← activiteitenlog entries
    story-progress.tsx      ← voortgangsindicator
    priority-group.tsx      ← prioriteitsgroep scheidingslijn

Toegankelijkheid

  • Alle kleurcombinaties voldoen aan WCAG AA (contrast ratio ≥ 4.5:1 voor normale tekst)
  • Gebruik altijd tekst + kleur voor statusindicatoren, nooit kleur alleen
  • Alle interactieve elementen hebben een zichtbare focus:ring-primary
  • Dark mode is volledig ondersteund via de .dark class

Bijlage bij CLAUDE.md — lees beide voor je begint met bouwen.


MD3 Color Scheme

Color Philosophy

This color scheme follows Material Design 3 principles with three main color roles optimized for productivity software:

  • Primary (Blue) - Represents productivity, trust, and professionalism. Used for main actions and navigation.
  • Secondary (Purple) - Represents planning and organization. Used for supporting UI elements.
  • Tertiary (Teal) - Represents progress and data visualization. Used for highlights and metrics.

The system uses tonal elevation instead of shadows to create depth, providing a modern, clean interface suitable for extended desktop work sessions.


Complete Color Palette

Light Theme Colors

Primary Colors (Blue - Productivity)

Color Token Hex Code Usage
--primary #0061a4 Primary buttons, key actions
--primary-foreground #ffffff Text on primary background
--primary-container #d1e4ff Low emphasis primary elements
--primary-container-foreground #001d36 Text on primary container

Secondary Colors (Purple - Planning)

Color Token Hex Code Usage
--secondary #5b5e71 Secondary buttons, less critical actions
--secondary-foreground #ffffff Text on secondary background
--secondary-container #dfe1f9 Low emphasis secondary elements
--secondary-container-foreground #181b2c Text on secondary container

Tertiary Colors (Teal - Progress)

Color Token Hex Code Usage
--tertiary #006874 Highlights, progress indicators
--tertiary-foreground #ffffff Text on tertiary background
--tertiary-container #97f0ff Low emphasis tertiary elements
--tertiary-container-foreground #001f24 Text on tertiary container

Surface Colors (Elevation System)

Color Token Hex Code Usage
--background #fdfcff Main app background
--foreground #1b1b1f Main text color
--surface-container-lowest #ffffff Highest elevation (dialogs)
--surface-container-low #f7f5fc Cards, elevated containers
--surface-container #f1eff6 Default container background
--surface-container-high #ebeaf0 Nested containers
--surface-container-highest #e6e3ea Lowest elevation

Semantic State Colors

Color Token Hex Code Usage
--success #006e1c Success states, completed items
--success-foreground #ffffff Text on success background
--success-container #92f894 Low emphasis success
--warning #735b00 Warning states, attention needed
--warning-foreground #ffffff Text on warning background
--warning-container #ffdf9d Low emphasis warning
--error #ba1a1a Error states, failures
--error-foreground #ffffff Text on error background
--error-container #ffdad6 Low emphasis error
--info #006493 Information, neutral alerts
--info-foreground #ffffff Text on info background
--info-container #c9e6ff Low emphasis info

Project Management Specific Colors

Work Item Status

Color Token Hex Code Status
--status-todo #6750a4 Not started (Purple)
--status-in-progress #0061a4 Active work (Blue)
--status-done #006e1c Completed (Green)
--status-blocked #ba1a1a Blocked/Issues (Red)

Priority Levels

Color Token Hex Code Priority
--priority-critical #ba1a1a Critical (Red)
--priority-high #c75300 High (Orange)
--priority-medium #735b00 Medium (Yellow)
--priority-low #006874 Low (Teal)

Dark Theme Colors

Primary Colors (Blue - Productivity)

Color Token Hex Code Usage
--primary #9fcbfa Primary buttons, key actions
--primary-foreground #003257 Text on primary background
--primary-container #00497b Low emphasis primary elements
--primary-container-foreground #d1e4ff Text on primary container

Secondary Colors (Purple - Planning)

Color Token Hex Code Usage
--secondary #c3c4dd Secondary buttons
--secondary-foreground #2c2f42 Text on secondary background
--secondary-container #434659 Low emphasis secondary elements
--secondary-container-foreground #dfe1f9 Text on secondary container

Tertiary Colors (Teal - Progress)

Color Token Hex Code Usage
--tertiary #4fd8eb Highlights, progress indicators
--tertiary-foreground #00363d Text on tertiary background
--tertiary-container #004f58 Low emphasis tertiary elements
--tertiary-container-foreground #97f0ff Text on tertiary container

Surface Colors (Elevation System)

Color Token Hex Code Usage
--background #1b1b1f Main app background
--foreground #e4e1e9 Main text color
--surface-container-lowest #0f0e13 Highest elevation (dialogs)
--surface-container-low #232227 Cards, elevated containers
--surface-container #27262b Default container background
--surface-container-high #322f36 Nested containers
--surface-container-highest #3d3a41 Lowest elevation

Semantic State Colors

Color Token Hex Code Usage
--success #77db77 Success states
--success-container #005313 Low emphasis success
--warning #efc047 Warning states
--warning-container #574400 Low emphasis warning
--error #ffb4ab Error states
--error-container #93000a Low emphasis error
--info #87ceff Information
--info-container #004c6d Low emphasis info

Project Management Specific Colors (Dark)

Work Item Status

Color Token Hex Code Status
--status-todo #cfbdfe Not started (Purple)
--status-in-progress #9fcbfa Active work (Blue)
--status-done #77db77 Completed (Green)
--status-blocked #ffb4ab Blocked/Issues (Red)

Priority Levels

Color Token Hex Code Priority
--priority-critical #ffb4ab Critical (Red)
--priority-high #ffb68d High (Orange)
--priority-medium #efc047 Medium (Yellow)
--priority-low #4fd8eb Low (Teal)

Surface Elevation System

Material Design 3 uses tonal elevation to create depth. Higher surfaces are lighter (in light mode) or darker (in dark mode).

Hierarchy (from highest to lowest elevation)

  1. surface-container-lowest - Dialogs, modals, popovers
  2. surface-container-low - Cards, panels, elevated containers
  3. surface-container - Default container background
  4. surface-container-high - Nested containers, grouped elements
  5. surface-container-highest - Background-level containers

Tailwind Usage

bg-surface-container-lowest
bg-surface-container-low
bg-surface-container
bg-surface-container-high
bg-surface-container-highest

Color Roles

Primary (Productivity & Trust)

Use for:

  • Main action buttons
  • Navigation highlights
  • Active states
  • Key interactive elements

Examples:

// Filled button
<button className="bg-primary text-primary-foreground">
  Create Sprint
</button>

// Outline button (less emphasis)
<button className="border-2 border-primary text-primary">
  View Details
</button>

// Container variant (even less emphasis)
<div className="bg-primary-container text-primary-container-foreground">
  Selected item
</div>

Secondary (Planning & Support)

Use for:

  • Secondary actions
  • Supporting UI elements
  • Less critical interactive elements
  • Toolbar items

Examples:

// Secondary action
<button className="bg-secondary text-secondary-foreground">
  Filter
</button>

// Subtle highlight
<div className="bg-secondary-container text-secondary-container-foreground">
  Planning phase
</div>

Tertiary (Progress & Highlights)

Use for:

  • Progress indicators
  • Data visualization accents
  • Highlights and callouts
  • Metrics

Examples:

// Progress indicator
<div className="bg-tertiary text-tertiary-foreground">
  75% Complete
</div>

// Metric badge
<span className="bg-tertiary-container text-tertiary-container-foreground">
  +12 stories
</span>

Semantic States

Success (Completed, Positive)

Use for:

  • Completed tasks
  • Success messages
  • Positive confirmations
  • Achievement indicators
<div className="bg-success text-success-foreground">
   Sprint completed successfully
</div>

<div className="bg-success-container text-success-container-foreground">
  8 stories completed this week
</div>

Warning (Attention Needed)

Use for:

  • Warnings
  • Potential issues
  • Items needing attention
  • Approaching deadlines
<div className="bg-warning text-warning-foreground">
   Sprint deadline in 2 days
</div>

<div className="bg-warning-container text-warning-container-foreground">
  3 stories at risk
</div>

Error (Failures, Critical Issues)

Use for:

  • Errors
  • Failed operations
  • Blocked items
  • Critical alerts
<div className="bg-error text-error-foreground">
   Failed to save changes
</div>

<div className="bg-error-container text-error-container-foreground">
  1 story blocked
</div>

Info (Neutral Information)

Use for:

  • Informational messages
  • Tips and hints
  • Neutral notifications
  • Help text
<div className="bg-info text-info-foreground">
   New feature available
</div>

<div className="bg-info-container text-info-container-foreground">
  Tip: Use drag-and-drop to reorder
</div>

Project Management Colors

Work Item Status Colors

These colors are specifically designed for Scrum workflow states:

To Do (Purple - #6750a4 / #cfbdfe)

  • Not started items
  • Backlog items
  • Planned work
<span className="bg-status-todo text-white px-3 py-1 rounded-full">
  To Do
</span>

In Progress (Blue - #0061a4 / #9fcbfa)

  • Active development
  • Current sprint items
  • Work in flight
<span className="bg-status-in-progress text-white px-3 py-1 rounded-full">
  In Progress
</span>

Done (Green - #006e1c / #77db77)

  • Completed items
  • Accepted work
  • Delivered features
<span className="bg-status-done text-white px-3 py-1 rounded-full">
  Done
</span>

Blocked (Red - #ba1a1a / #ffb4ab)

  • Blocked items
  • Impediments
  • Issues preventing progress
<span className="bg-status-blocked text-white px-3 py-1 rounded-full">
  Blocked
</span>

Priority Level Colors

Critical (Red - #ba1a1a / #ffb4ab)

  • Production issues
  • Show-stopper bugs
  • Immediate action required
<span className="bg-priority-critical text-white px-2 py-1 rounded text-sm">
  Critical
</span>

High (Orange - #c75300 / #ffb68d)

  • Important features
  • Significant bugs
  • Near-term priorities
<span className="bg-priority-high text-white px-2 py-1 rounded text-sm">
  High
</span>

Medium (Yellow - #735b00 / #efc047)

  • Standard priority
  • Regular backlog items
  • Scheduled work
<span className="bg-priority-medium text-white px-2 py-1 rounded text-sm">
  Medium
</span>

Low (Teal - #006874 / #4fd8eb)

  • Nice-to-have features
  • Minor improvements
  • Future considerations
<span className="bg-priority-low text-white px-2 py-1 rounded text-sm">
  Low
</span>

Usage Examples

Product Backlog Item Card

<div className="bg-card text-card-foreground p-6 rounded-lg border border-border">
  <div className="flex items-start justify-between mb-3">
    <h3 className="text-lg">Implement OAuth2 Authentication</h3>
    <span className="bg-priority-high text-white px-3 py-1 rounded-md text-sm">
      High
    </span>
  </div>
  
  <p className="text-muted-foreground mb-4">
    Add OAuth2 support for Google and GitHub authentication providers
    with proper session management and refresh token handling.
  </p>
  
  <div className="flex items-center justify-between">
    <div className="flex gap-2">
      <span className="bg-status-in-progress text-white px-3 py-1 rounded-full text-sm">
        In Progress
      </span>
      <span className="text-muted-foreground text-sm">
        Story Points: 8
      </span>
    </div>
    
    <div className="text-sm text-muted-foreground">
      Assigned to: Sarah
    </div>
  </div>
</div>

Sprint Dashboard Card

<div className="bg-surface-container-low p-6 rounded-xl">
  <h2 className="mb-4">Sprint 12 Progress</h2>
  
  <div className="bg-surface-container p-4 rounded-lg mb-4">
    <div className="space-y-3">
      <div className="flex justify-between items-center">
        <span className="text-muted-foreground">Total Stories</span>
        <span className="text-xl">15</span>
      </div>
      
      <div className="flex justify-between items-center">
        <span className="text-muted-foreground">Completed</span>
        <span className="text-xl text-success">10</span>
      </div>
      
      <div className="flex justify-between items-center">
        <span className="text-muted-foreground">In Progress</span>
        <span className="text-xl text-info">4</span>
      </div>
      
      <div className="flex justify-between items-center">
        <span className="text-muted-foreground">Blocked</span>
        <span className="text-xl text-error">1</span>
      </div>
    </div>
  </div>
  
  <div className="space-y-2">
    <div className="flex justify-between text-sm">
      <span className="text-muted-foreground">Progress</span>
      <span>67%</span>
    </div>
    <div className="w-full bg-surface-container-highest rounded-full h-3">
      <div 
        className="bg-success h-3 rounded-full transition-all" 
        style={{ width: '67%' }}
      />
    </div>
  </div>
</div>

Kanban Board Column

<div className="bg-surface-container p-4 rounded-lg min-w-80">
  <div className="flex items-center justify-between mb-4">
    <h3 className="flex items-center gap-2">
      <span className="w-3 h-3 rounded-full bg-status-in-progress" />
      In Progress
    </h3>
    <span className="bg-surface-container-high text-muted-foreground px-2 py-1 rounded text-sm">
      4
    </span>
  </div>
  
  <div className="space-y-3">
    {/* Story card */}
    <div className="bg-surface-container-low p-3 rounded-lg border border-border hover:border-primary cursor-pointer transition-colors">
      <div className="flex items-start justify-between mb-2">
        <h4 className="text-sm">Fix login redirect issue</h4>
        <span className="bg-priority-critical text-white px-2 py-0.5 rounded text-xs">
          Critical
        </span>
      </div>
      <p className="text-xs text-muted-foreground mb-3">
        Users are redirected to wrong page after login
      </p>
      <div className="flex items-center justify-between">
        <span className="text-xs text-muted-foreground">SP: 3</span>
        <div className="w-6 h-6 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs">
          JD
        </div>
      </div>
    </div>
  </div>
</div>

Action Buttons

{/* Primary action */}
<button className="px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity">
  Start Sprint
</button>

{/* Secondary action */}
<button className="px-6 py-3 bg-secondary text-secondary-foreground rounded-lg hover:opacity-90 transition-opacity">
  Save as Draft
</button>

{/* Outlined action */}
<button className="px-6 py-3 border-2 border-primary text-primary rounded-lg hover:bg-primary-container transition-colors">
  View Backlog
</button>

{/* Tertiary/text action */}
<button className="px-6 py-3 text-primary hover:bg-primary-container rounded-lg transition-colors">
  Cancel
</button>

{/* Destructive action */}
<button className="px-6 py-3 bg-error text-error-foreground rounded-lg hover:opacity-90 transition-opacity">
  Delete Sprint
</button>

Status Badges

{/* Pill-shaped status badges */}
<div className="flex gap-2">
  <span className="inline-flex items-center gap-1 px-3 py-1 bg-status-todo text-white rounded-full text-sm">
    <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 8 8">
      <circle cx="4" cy="4" r="3" />
    </svg>
    To Do
  </span>
  
  <span className="inline-flex items-center gap-1 px-3 py-1 bg-status-in-progress text-white rounded-full text-sm">
    <svg className="w-3 h-3 animate-spin" fill="none" viewBox="0 0 24 24">
      <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
      <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
    </svg>
    In Progress
  </span>
  
  <span className="inline-flex items-center gap-1 px-3 py-1 bg-status-done text-white rounded-full text-sm">
    <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
    </svg>
    Done
  </span>
  
  <span className="inline-flex items-center gap-1 px-3 py-1 bg-status-blocked text-white rounded-full text-sm">
    <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
      <path fillRule="evenodd" d="M13.477 14.89A6 6 0 015.11 6.524l8.367 8.368zm1.414-1.414L6.524 5.11a6 6 0 018.367 8.367zM18 10a8 8 0 11-16 0 8 8 0 0116 0z" clipRule="evenodd" />
    </svg>
    Blocked
  </span>
</div>

Implementation Guide

Setting Up the Color System

The color system is defined in /src/styles/theme.css. All colors use CSS custom properties (variables) for easy theming.

Tailwind CSS Configuration

All color tokens are automatically available as Tailwind classes through the @theme inline directive:

/* Colors are available as: */
bg-primary
text-primary-foreground
border-primary-container
bg-surface-container-low
bg-status-in-progress
bg-priority-high
/* etc. */

Dark Mode Toggle

Toggle dark mode with JavaScript:

// Toggle dark mode
document.documentElement.classList.toggle('dark');

// Set dark mode
document.documentElement.classList.add('dark');

// Set light mode
document.documentElement.classList.remove('dark');

// React component example
function DarkModeToggle() {
  const [isDark, setIsDark] = useState(false);
  
  const toggleDark = () => {
    setIsDark(!isDark);
    document.documentElement.classList.toggle('dark');
  };
  
  return (
    <button onClick={toggleDark}>
      {isDark ? '☀️ Light Mode' : '🌙 Dark Mode'}
    </button>
  );
}

Using with shadcn Components

All shadcn/ui components work seamlessly with this color system. The legacy color tokens (card, popover, muted, accent, destructive) are mapped to appropriate MD3 colors.

// shadcn Button component automatically uses the color system
<Button>Primary Action</Button>
<Button variant="secondary">Secondary Action</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outlined</Button>

Accessibility

Contrast Ratios

All color combinations meet WCAG AA standards:

  • Normal text: Minimum 4.5:1 contrast ratio
  • Large text: Minimum 3:1 contrast ratio
  • UI components: Minimum 3:1 contrast ratio

Color Blindness Considerations

The color system is designed to be distinguishable for users with common types of color blindness:

  1. Status colors use distinct hues that remain distinguishable in deuteranopia, protanopia, and tritanopia
  2. Priority levels use a progression from cool (low) to warm (high) colors
  3. All status indicators should include text labels, not just color

Best Practices for Accessibility

// ✅ Good: Color + Icon + Text
<span className="bg-status-done text-white px-3 py-1 rounded-full">
  <CheckIcon className="w-4 h-4 inline" />
  Done
</span>

// ❌ Bad: Color only
<span className="w-4 h-4 bg-status-done rounded-full" />

// ✅ Good: Semantic HTML + ARIA
<button 
  className="bg-primary text-primary-foreground"
  aria-label="Start new sprint"
>
  Start Sprint
</button>

// ✅ Good: Status with aria-label
<div 
  className="bg-status-blocked"
  role="status"
  aria-label="This item is blocked"
>
  Blocked
</div>

Best Practices

1. Use Surface Elevation for Depth

Don't use shadows for elevation

<div className="shadow-lg">Card</div>

Do use surface tones

<div className="bg-surface-container-low">Card</div>

2. Use Container Variants for Lower Emphasis

Don't reduce opacity

<button className="bg-primary opacity-50">Secondary Action</button>

Do use container variants

<button className="bg-primary-container text-primary-container-foreground">
  Secondary Action
</button>

3. Consistent Status Colors

Don't use arbitrary colors

<span className="bg-green-500">Complete</span>
<span className="bg-emerald-600">Finished</span>

Do use semantic status colors

<span className="bg-status-done">Complete</span>
<span className="bg-status-done">Finished</span>

4. Semantic Color Usage

Don't use colors for decoration only

<div className="bg-error">This is important information</div>

Do use colors for their semantic meaning

<div className="bg-error text-error-foreground">
  Error: Failed to save changes
</div>

<div className="bg-info text-info-foreground">
  This is important information
</div>

5. Proper Text Contrast

Don't forget foreground colors

<button className="bg-primary">Click me</button>

Do include foreground colors

<button className="bg-primary text-primary-foreground">Click me</button>

6. Layering and Nesting

When nesting containers, move down the elevation scale:

<div className="bg-surface-container-low p-6">
  {/* Outer container */}
  
  <div className="bg-surface-container p-4">
    {/* Inner container - lower elevation */}
    
    <div className="bg-surface-container-high p-3">
      {/* Deepest container - lowest elevation */}
    </div>
  </div>
</div>

7. Interactive States

// Buttons with hover states
<button className="bg-primary text-primary-foreground hover:opacity-90 transition-opacity">
  Click me
</button>

// Cards with hover states
<div className="bg-card border border-border hover:border-primary transition-colors cursor-pointer">
  Interactive card
</div>

// Focus states (automatically handled by theme)
<input className="border border-border focus:ring-2 focus:ring-primary" />

Quick Reference

Most Common Combinations

// Primary button
bg-primary text-primary-foreground

// Secondary button
bg-secondary text-secondary-foreground

// Card
bg-card text-card-foreground border border-border

// Success message
bg-success-container text-success-container-foreground

// Warning banner
bg-warning text-warning-foreground

// Error alert
bg-error text-error-foreground

// Info panel
bg-info-container text-info-container-foreground

// Status badge - To Do
bg-status-todo text-white

// Status badge - In Progress
bg-status-in-progress text-white

// Status badge - Done
bg-status-done text-white

// Priority badge - High
bg-priority-high text-white

// Muted text
text-muted-foreground

// Border
border-border

Additional Resources

Color Tools

Documentation


Version History

Version 1.0 (April 22, 2026)

  • Initial color scheme based on Material Design 3
  • Complete light and dark theme support
  • Project management specific colors (status, priority)
  • Full shadcn/ui compatibility
  • Accessibility WCAG AA compliant

Support

For questions or issues with the color system:

  • Review the live demo in the application
  • Check COLOR_SYSTEM.md for additional examples
  • Refer to /src/styles/theme.css for color definitions

End of Documentation