Files
Webklar/.kiro/specs/system-theme-detection/tasks.md
2026-05-10 12:19:58 +02:00

115 lines
6.4 KiB
Markdown

# Implementation Plan: System-Theme-Erkennung (Light/Dark Mode)
## Overview
Integrate `next-themes` into the existing React + Vite + Tailwind + shadcn/ui app to enable automatic OS theme detection, manual theme switching (light/dark/system), and persistent user preference. The CSS variables in `src/index.css` will be restructured so `:root` defines the light theme and `.dark` defines the dark theme. A ThemeToggle component will be added to the Header, and an inline script in `index.html` will prevent FOUC.
## Tasks
- [x] 1. Restructure CSS variables and set up testing dependencies
- [x] 1.1 Restructure CSS custom properties in `src/index.css`
- Move the current `:root` dark color values into the `.dark` block
- Define new light theme values in `:root` (white backgrounds, dark text, matching design spec)
- Ensure all design tokens are covered: background, foreground, card, primary, secondary, muted, accent, border, input, ring, destructive, popover, sidebar, chart-1 through chart-5
- Update hardcoded color values in component styles (`.glass-nav`, `.card-minimal`, `.project-card`, `.btn`, `.text-gradient`, etc.) to use CSS variables where possible
- Add dark-mode-aware variants for component styles that use hardcoded HSL values
- _Requirements: 4.1, 4.2, 4.3, 4.4_
- [x] 1.2 Install `fast-check` as a dev dependency
- Run `npm install --save-dev fast-check`
- _Requirements: (testing infrastructure)_
- [x] 2. Create ThemeProvider wrapper and integrate into App
- [x] 2.1 Create `src/components/ThemeProvider.tsx`
- Export a thin wrapper around `ThemeProvider` from `next-themes`
- Configure with `attribute="class"`, `defaultTheme="system"`, `enableSystem={true}`, `storageKey="theme"`
- Accept `children` and optional override props
- _Requirements: 1.1, 1.2, 1.3, 3.1, 3.2_
- [x] 2.2 Wrap the App component tree with ThemeProvider in `src/App.tsx`
- Import ThemeProvider and wrap it as the outermost provider around the existing component tree
- _Requirements: 1.1, 2.3, 2.4, 2.5_
- [ ]* 2.3 Write property test: System-Theme-Auflösung (Property 1)
- **Property 1: System-Theme-Auflösung**
- Generate arbitrary system theme values (light/dark), set preference to "system", verify `resolvedTheme === systemTheme`
- Use `fast-check` with minimum 100 iterations
- **Validates: Requirements 1.1, 1.2, 1.3, 2.5**
- [ ]* 2.4 Write property test: Explizite Theme-Wahl überschreibt System (Property 2)
- **Property 2: Explizite Theme-Wahl überschreibt System**
- Generate arbitrary combinations of system theme and explicit choice ("light"/"dark"), verify `resolvedTheme === expliziteWahl`
- Use `fast-check` with minimum 100 iterations
- **Validates: Requirements 2.3, 2.4**
- [ ]* 2.5 Write property test: Persistenz-Round-Trip (Property 3)
- **Property 3: Persistenz-Round-Trip**
- Generate arbitrary valid theme values ("light", "dark", "system"), set via `setTheme()`, read from `localStorage`, verify equality and correct restoration on simulated reload
- Use `fast-check` with minimum 100 iterations
- **Validates: Requirements 3.1, 3.2**
- [x] 3. Checkpoint
- Ensure all tests pass, ask the user if questions arise.
- [x] 4. Create ThemeToggle component
- [x] 4.1 Create `src/components/ThemeToggle.tsx`
- Build a button component using shadcn/ui `DropdownMenu` and `Button`
- Use `useTheme()` hook from `next-themes` for `theme`, `setTheme`, `resolvedTheme`
- Display Sun icon (lucide-react) for light, Moon for dark, Monitor for system
- Implement mounted-state check to prevent hydration mismatch on icon rendering
- Dropdown offers three options: "Hell" (light), "Dunkel" (dark), "System" (system)
- Add `aria-label` describing current state (e.g., "Theme wechseln, aktuell: Dunkel")
- Ensure keyboard navigability (Tab, Enter/Space)
- Accept optional `className` prop for positioning flexibility
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 6.1, 6.2, 6.3_
- [ ]* 4.2 Write unit tests for ThemeToggle
- Test that the toggle button renders in the DOM
- Test that dropdown shows three options (Hell, Dunkel, System)
- Test correct icon rendering per theme state
- Test `aria-label` contains current theme state
- Test keyboard interaction (focus, Enter/Space opens dropdown)
- _Requirements: 2.1, 2.2, 2.6, 6.1, 6.2, 6.3_
- [x] 5. Integrate ThemeToggle into Header
- [x] 5.1 Add ThemeToggle to desktop navigation in `src/components/Header.tsx`
- Import ThemeToggle and place it in the `NavBody` actions area, before the "Kontakt" button
- _Requirements: 2.1_
- [x] 5.2 Add ThemeToggle to mobile navigation in `src/components/Header.tsx`
- Place ThemeToggle in the `MobileNavHeader`, positioned next to the hamburger toggle icon
- _Requirements: 2.1_
- [ ]* 5.3 Write unit tests for Header ThemeToggle integration
- Test that ThemeToggle is present in the rendered Header component
- _Requirements: 2.1_
- [x] 6. Add FOUC-prevention inline script to `index.html`
- [x] 6.1 Add inline `<script>` block in the `<head>` of `index.html`
- Read `localStorage.getItem("theme")`
- If value is "dark", add `class="dark"` to `<html>`
- If value is "system" or absent, check `window.matchMedia("(prefers-color-scheme: dark)")` and set class accordingly
- If value is "light", ensure no `dark` class is present
- Script must execute synchronously before any rendering
- _Requirements: 5.1, 5.2, 3.2_
- [ ]* 6.2 Write unit test for FOUC-prevention logic
- Extract the inline script logic into a testable function
- Test that correct class is applied for each localStorage value and system preference combination
- _Requirements: 5.1_
- [x] 7. Final checkpoint
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- Unit tests validate specific examples and edge cases
- The project uses TypeScript throughout — all new files should be `.tsx`/`.ts`
- `next-themes` is already installed (`^0.3.0`), `fast-check` needs to be added as a dev dependency
- `lucide-react` is already available for Sun/Moon/Monitor icons
- shadcn/ui `DropdownMenu` and `Button` components already exist in `src/components/ui/`