13 KiB
Mini-EPD Style Guide & UX
Geëxtraheerd uit de mini-epd-prototype codebase. Gebruik dit document om dezelfde look & feel in een ander project toe te passen.
1. Tech Stack & Tooling
| Categorie | Keuze | Versie |
|---|---|---|
| Framework | Next.js (App Router) | 14.2 |
| Taal | TypeScript | 5.x |
| Styling | Tailwind CSS | 3.4 |
| Component variants | class-variance-authority (CVA) |
0.7 |
| Class merging | tailwind-merge |
3.4 |
| Animaties | tailwindcss-animate + Framer Motion |
1.0 / 12.x |
| UI primitives | Radix UI | diverse |
| Iconen | Lucide React | 0.553 |
| State management | Zustand | 5.x |
| Formulieren | React Hook Form + Zod | 7.x / 4.x |
| Rich text | TipTap | 3.x |
Utility helper
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
2. Kleurensysteem
2.1 Basiskleuren
| Token | Hex | Gebruik |
|---|---|---|
app-background |
#F8FAFC |
Pagina-achtergrond (slate-50) |
surface |
#FFFFFF |
Cards, panels |
surface-sub |
#F1F5F9 |
Secundaire achtergrond (slate-100) |
text-primary |
#0F172A |
Primaire tekst (slate-900) |
text-secondary |
#475569 |
Secundaire/meta-tekst (slate-600) |
border |
#E2E8F0 |
Standaard borders (slate-200) |
2.2 Brand (Teal-first)
De primaire brandkleur is teal. Alle interactieve elementen, focus-states en links gebruiken deze kleur.
| Token | Hex | Ratio | Gebruik |
|---|---|---|---|
brand-50 |
#F0FDFA |
— | Subtiele achtergrond |
brand-100 |
#CCFBF1 |
— | Info-subtiel |
brand-200 |
#99F6E4 |
— | Lichte tint |
brand-400 |
#2DD4BF |
— | Decoratief |
brand-500 |
#14B8A6 |
— | Accent |
brand-600 |
#0D9488 |
3:1 | UI-componenten (non-text) |
brand-700 |
#0F766E |
5.47:1 | Primaire tekst & CTA (WCAG AA) ✓ |
brand-800 |
#115E59 |
— | Hover state |
brand-900 |
#134E4A |
— | Donkerste tint |
/* CSS custom properties */
--color-brand: #0F766E;
--color-brand-hover: #115E59;
--color-brand-active: #0D9488;
--color-brand-subtle: #F0FDFA;
2.3 AI Features (Amber)
AI-gerelateerde acties worden visueel onderscheiden door een amber kleurenpalet.
| Token | Hex | Gebruik |
|---|---|---|
ai-50 |
#FFFBEB |
Subtiele AI-achtergrond |
ai-500 |
#F59E0B |
Primaire AI-kleur |
ai-600 |
#D97706 |
AI-tekst (WCAG AA large) |
ai-700 |
#B45309 |
AI hover |
2.4 Module-accenten
Verschillende modules hebben een eigen kleurig accent:
| Module | Achtergrond | Accent | Border |
|---|---|---|---|
| Afspraken | #E8F8EF |
#16A34A (groen) |
#CDECDC |
| Medicatie | #FEF6DC |
#F59E0B (amber) |
#F6E7B6 |
| Lab | #FFEBDC |
#F97316 (oranje) |
#FFD2B8 |
2.5 Status & Feedback
| Status | Kleur | Subtiel |
|---|---|---|
| Success | #16A34A |
#ECFDF5 |
| Warning | #EAB308 |
#FEFCE8 |
| Error | #DC2626 |
#FEF2F2 |
| Info | #0F766E (teal) |
#CCFBF1 |
2.6 Severity Badges (DSM-light)
| Ernst | Achtergrond | Tekst |
|---|---|---|
| Low | #E5E7EB |
#374151 |
| Medium | #FEF3C7 |
#92400E |
| High | #FEE2E2 |
#991B1B |
2.7 Dark Mode
Dark mode is optioneel geïmplementeerd (MVP = licht thema):
.dark {
--color-bg: #0a0a0a;
--color-surface: #1a1a1a;
--color-text: #ededed;
--color-text-secondary: #a1a1a1;
--color-border: #333333;
}
3. Typografie
3.1 Font Families
Drie fonts worden lokaal geladen via next/font/local:
| Variabele | Font | Gewichten | Gebruik |
|---|---|---|---|
--font-serif |
Lora | 400, 400i, 600 | Long-form content, manifesto teksten |
--font-sans |
Roboto | 400, 500, 600 (+italic) | UI, navigatie, metadata, body |
--font-mono |
Source Code Pro | 400, 600 | Code, technische details, nummers |
Body default: var(--font-sans), system-ui, -apple-system, sans-serif
3.2 Typografische Schaal
| Token | Waarde | Toepassing |
|---|---|---|
--text-hero |
clamp(2.5rem, 6vw, 4rem) |
Hero quotes |
--text-h1 |
clamp(2rem, 5vw, 3rem) |
Sectie-koppen |
--text-h2 |
clamp(1.5rem, 4vw, 2.5rem) |
Subsecties |
--text-body |
1.25rem |
Content, lopende tekst |
--text-small |
0.875rem |
Metadata, labels |
3.3 Line Heights
| Token | Waarde | Gebruik |
|---|---|---|
--line-height-tight |
1.2 |
Headings |
--line-height-relaxed |
1.8 |
Body/content |
4. Shadows & Border Radius
Shadows
| Token | Waarde |
|---|---|
shadow-sm |
0 1px 2px rgba(15,23,42,0.06) |
shadow-md |
0 2px 6px rgba(15,23,42,0.08) |
shadow-lg |
0 8px 20px rgba(15,23,42,0.10) |
Alle shadows zijn gebaseerd op slate-900 alpha — geen hard zwart.
Border Radius
| Token | Waarde |
|---|---|
--radius |
0.625rem (10px) |
rounded-lg |
var(--radius) |
rounded-md |
calc(var(--radius) - 2px) ≈ 8px |
rounded-sm |
calc(var(--radius) - 4px) ≈ 6px |
5. Formulieren
| State | Property | Waarde |
|---|---|---|
| Default | bg | #FFFFFF |
| Default | border | #CBD5E1 |
| Default | tekst | #0F172A |
| Placeholder | kleur | #94A3B8 |
| Hover | border | #94A3B8 |
| Focus | ring/border | #0F766E (teal-700) |
| Disabled | bg | #F1F5F9 |
| Disabled | tekst | #94A3B8 |
| Invalid | border | #DC2626 |
| Invalid | tekst | #B91C1C |
Input component patroon:
<input className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1
text-base shadow-sm transition-colors placeholder:text-muted-foreground
focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
disabled:cursor-not-allowed disabled:opacity-50 md:text-sm" />
6. Component Patronen
6.1 Component Architectuur
- Alle componenten gebruiken
React.forwardRefvoor ref-forwarding - Varianten via
class-variance-authority(CVA) - Styling via Tailwind classes +
cn()utility - Radix UI als headless primitives (Dialog, Tabs, Select, Popover, etc.)
- Default = server component;
"use client"alleen wanneer interactiviteit vereist is
6.2 Button
| Variant | Stijl |
|---|---|
default |
bg-primary text-primary-foreground hover:bg-primary/90 |
destructive |
bg-destructive text-destructive-foreground hover:bg-destructive/90 |
outline |
border border-input bg-background hover:bg-accent |
secondary |
bg-secondary text-secondary-foreground hover:bg-secondary/80 |
ghost |
hover:bg-accent hover:text-accent-foreground |
link |
text-primary underline-offset-4 hover:underline |
| Size | Afmetingen |
|---|---|
default |
h-10 px-4 py-2 |
sm |
h-9 px-3 |
lg |
h-11 px-8 |
icon |
h-10 w-10 |
6.3 AI Button
Speciaal component voor AI-acties. Visueel onderscheiden door amber gradient.
| Variant | Stijl |
|---|---|
default |
Amber gradient (from-amber-600 to-amber-700) + witte tekst |
outline |
border-2 border-amber-500, tekst amber-700 |
ghost |
Transparant, tekst amber-700, hover amber-50 |
Features:
- Sparkle-icoon (✨) als visuele AI-indicator
- Loading state met
Loader2spinner - Drie maten:
sm,md,lg
6.4 Card
┌─────────────────────────────┐
│ CardHeader (p-6) │
│ CardTitle (semibold) │
│ CardDescription (muted) │
│ CardContent (p-6 pt-0) │
│ CardFooter (p-6 pt-0) │
└─────────────────────────────┘
rounded-xl,border,bg-card,shadow
6.5 Badge
Varianten: default, secondary, destructive, outline
Base: rounded-md, px-2.5 py-0.5, text-xs font-semibold
6.6 Tabs
TabsList:rounded-lg bg-muted p-1TabsTrigger:rounded-md px-3 py-1 text-sm font-medium- Active state:
bg-background text-foreground shadow
6.7 Toast
- Positie: top op mobile, bottom-right op desktop
- Swipe-to-dismiss ondersteuning
- Slide-in animatie (top op mobile, bottom op desktop)
- Varianten:
defaultendestructive
7. Layout & Navigatie
7.1 App Shell
┌──────────────────────────────────────┐
│ ┌──────────┐ ┌─────────────────────┐ │
│ │ │ │ │ │
│ │ Sidebar │ │ Main Content │ │
│ │ (fixed) │ │ (scrollable) │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ └──────────┘ └─────────────────────┘ │
└──────────────────────────────────────┘
- Container:
min-h-screen bg-slate-50 flex - Sidebar: fixed,
w-78open /w-28collapsed - Main content: flex-grow, scrollable
7.2 Sidebar UX
| Eigenschap | Waarde |
|---|---|
| Desktop breedte (open) | w-78 (312px) |
| Desktop breedte (collapsed) | w-28 (112px) |
| Achtergrond | bg-white |
| Border | border-r border-slate-200 |
| Transition | duration-300 ease-in-out |
| Mobile | Full overlay met bg-black/40 backdrop-blur-sm |
Active nav item: bg-teal-50 text-teal-700 + icoon text-teal-600
Inactive nav item: text-slate-600 hover:bg-slate-50 hover:text-slate-900
Collapsed state: tooltips verschijnen links met een pijl-indicator (bg-slate-800 text-white)
Profiel sectie: avatar cirkel, naam, rol, online-indicator (bg-green-500 dot)
Logout: text-red-600 hover:bg-red-50
8. Animaties
8.1 Float Animatie
Subtiele zweef-animatie voor badges of decoratieve elementen:
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
25% { transform: translateY(-5px) rotate(0.5deg); }
50% { transform: translateY(-3px) rotate(-0.5deg); }
75% { transform: translateY(-7px) rotate(0.3deg); }
}
.animate-float { animation: float 5s ease-in-out infinite; }
8.2 Artifact Slide-in
Panel slide-in van rechts:
@keyframes artifact-enter {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
.artifact-enter { animation: artifact-enter 200ms ease-out; }
8.3 Transition Defaults
- Navigatie / sidebar:
transition-all duration-300 ease-in-out - Buttons / interactie:
transition-colorsoftransition-all duration-200 - Toasts: slide-in + fade via
tailwindcss-animate
8.4 Reduced Motion
Volledige prefers-reduced-motion ondersteuning:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.02ms !important;
transition-duration: 0.03ms !important;
scroll-behavior: auto !important;
}
}
9. Toegankelijkheid (A11y)
| Aspect | Implementatie |
|---|---|
| Focus indicator | outline: 2px solid var(--color-brand), outline-offset: 2px |
| Focus ring (components) | ring-2 ring-ring ring-offset-2 |
| Skip to main | Verborgen link, zichtbaar bij focus |
| Kleurcontrast | Brand teal-700 = 5.47:1 op wit (WCAG AA ✓) |
| ARIA labels | Alle interactieve elementen (toggle buttons, sidebar) |
| Reduced motion | Alle animaties gerespecteerd |
| Iconen | aria-hidden="true" op decoratieve iconen |
| Taal | <html lang="nl"> |
10. AI UX Conventies
AI-functies worden visueel onderscheiden van standaard UI:
| Element | Conventie |
|---|---|
| Kleur | Amber-palet (geel/goud), nooit teal |
| Button | AIButton component met Sparkle-icoon (✨) |
| Highlight | .ai-source-highlight — lichtgeel (#fef08a) met border-radius: 2px |
| Loading | Loader2 spinner (animatie: animate-spin) |
| Feedback | Confidence indicators bij AI-gegenereerde content |
11. Quick-Start Checklist
Om deze stijl in een nieuw project over te nemen:
-
Installeer dependencies:
pnpm add class-variance-authority clsx tailwind-merge tailwindcss-animate pnpm add lucide-react framer-motion pnpm add @radix-ui/react-dialog @radix-ui/react-tabs @radix-ui/react-select # + overige Radix primitives naar behoefte -
Kopieer fonts (Lora, Roboto, Source Code Pro) naar
public/fonts/en configureer inlayout.tsx -
Kopieer CSS custom properties uit
globals.css(sectie:root) -
Kopieer Tailwind config — met name
colors,boxShadow,borderRadiusextensies -
Kopieer
cn()utility naarlib/utils.ts -
Kopieer UI components uit
components/ui/(shadcn-patroon met CVA) -
Zet
antialiasedop de<body>tag -
Zet
lang="nl"op de<html>tag
Gegenereerd op basis van de mini-epd-prototype codebase (maart 2026).