2.6 KiB
2.6 KiB
Context
The current UI defaults to dark presentation and lacks a global theme control. Users with different preference and accessibility needs cannot choose light/system/high-contrast alternatives.
This change introduces an icon-based theme switcher and persistent client-side preference restoration.
Goals / Non-Goals
Goals:
- Add a header theme switcher with system, light, dark, and high-contrast options.
- Apply theme choice globally with minimal visual regression.
- Persist preference in localStorage with cookie fallback.
- Restore returning-user choice; default to system when unset.
Non-Goals:
- Server-side profile theme persistence.
- Theme-specific content changes.
- Full design-system rewrite.
Decisions
Decision: Centralize theme state on document.documentElement
Decision: Set a root theme attribute/class and drive color tokens from CSS variables.
Rationale:
- Single source of truth for whole page styling.
- Works with existing Tailwind utility classes via custom CSS variable bridge.
Alternatives considered:
- Component-level theming flags: rejected due to drift and maintenance overhead.
Decision: Keep system mode dynamic via prefers-color-scheme
Decision: For system, listen to media query changes and update resolved theme automatically.
Rationale:
- Matches user OS preference behavior.
Alternatives considered:
- One-time system snapshot: rejected as surprising for users changing OS theme at runtime.
Decision: Use icon-only options with accessible labels
Decision: Theme controls are icon buttons with ARIA labels and visible selected state.
Rationale:
- Meets UX requirement while preserving accessibility.
Alternatives considered:
- Text dropdown: rejected due to explicit icon requirement.
Risks / Trade-offs
- [Risk] Existing hardcoded color classes may not adapt perfectly -> Mitigation: prioritize core surfaces/text and progressively map remaining variants.
- [Risk] High-contrast mode may expose layout artifacts -> Mitigation: audit focus outlines, borders, and semantic contrast first.
- [Trade-off] Additional JS for persistence and media listeners -> Mitigation: keep logic modular and lightweight.
Migration Plan
- Add theme tokens and root theme resolver.
- Implement icon switcher in header and state persistence.
- Wire system preference listener and fallback behavior.
- Validate across refresh/returning sessions and responsive breakpoints.
Rollback:
- Remove theme switcher and resolver, revert to existing dark-default classes.
Open Questions
- Should high-contrast mode align with OS
prefers-contrastin a later phase?