# 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 ```ts // 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 /* 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): ```css .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:** ```tsx ``` --- ## 6. Component Patronen ### 6.1 Component Architectuur - Alle componenten gebruiken **`React.forwardRef`** voor 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 `Loader2` spinner - 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-1` - `TabsTrigger`: `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: `default` en `destructive` --- ## 7. Layout & Navigatie ### 7.1 App Shell ``` ┌──────────────────────────────────────┐ │ ┌──────────┐ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ Sidebar │ │ Main Content │ │ │ │ (fixed) │ │ (scrollable) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────┘ └─────────────────────┘ │ └──────────────────────────────────────┘ ``` - **Container**: `min-h-screen bg-slate-50 flex` - **Sidebar**: fixed, `w-78` open / `w-28` collapsed - **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: ```css @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: ```css @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-colors` of `transition-all duration-200` - Toasts: slide-in + fade via `tailwindcss-animate` ### 8.4 Reduced Motion Volledige `prefers-reduced-motion` ondersteuning: ```css @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 | `` | --- ## 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: 1. **Installeer dependencies:** ```bash 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 ``` 2. **Kopieer fonts** (Lora, Roboto, Source Code Pro) naar `public/fonts/` en configureer in `layout.tsx` 3. **Kopieer CSS custom properties** uit `globals.css` (sectie `:root`) 4. **Kopieer Tailwind config** — met name `colors`, `boxShadow`, `borderRadius` extensies 5. **Kopieer `cn()` utility** naar `lib/utils.ts` 6. **Kopieer UI components** uit `components/ui/` (shadcn-patroon met CVA) 7. **Zet `antialiased`** op de `` tag 8. **Zet `lang="nl"`** op de `` tag --- *Gegenereerd op basis van de mini-epd-prototype codebase (maart 2026).*