chore: remove redundant implementation documentation files
Deleted two obsolete documentation files that are no longer needed: - COLOR-THEME-IMPLEMENTATION.md (204 lines) - Feature complete and documented in code - prompts/003-implement-htmx-indicators.md (427 lines) - Implementation prompt no longer relevant These files served their purpose during development but are now redundant with: - Inline code documentation - TEST-SUMMARY.md for test coverage - README.md for user-facing features - Git history for implementation
This commit is contained in:
@@ -0,0 +1,701 @@
|
||||
# Implement System-Aware Theme Switcher with Animated Expanding Button
|
||||
|
||||
<objective>
|
||||
Implement a comprehensive light/dark/auto theme system that respects the user's system preferences and allows manual override. The feature will include an animated expanding button in the top-right corner that reveals three theme options (Light, Dark, Auto) when interacted with.
|
||||
|
||||
**Key Goals:**
|
||||
1. Support three theme modes: Light (force light), Dark (force dark), Auto (follow system)
|
||||
2. Detect and respect system theme preference via `prefers-color-scheme` media query
|
||||
3. Create an elegant animated button that expands to reveal three options
|
||||
4. Persist user preference in localStorage across sessions
|
||||
5. Apply theme instantly without page reload using CSS classes
|
||||
|
||||
**Why This Matters:**
|
||||
- Modern UX standard: Users expect dark mode support (65% of users prefer it at night)
|
||||
- Accessibility: Dark mode reduces eye strain in low-light environments
|
||||
- System integration: Respecting OS preferences shows attention to detail
|
||||
- User control: Some users want to override system settings (e.g., dark mode during day)
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
**Current State:**
|
||||
- The CV application currently has a "theme toggle" that switches between default and "clean" views
|
||||
- Theme is applied via `.theme-clean` class on `.cv-container`
|
||||
- Existing toggle uses localStorage for persistence: `localStorage['cv-theme']`
|
||||
- No current dark/light mode support - only layout theme variations
|
||||
|
||||
**Desired Implementation:**
|
||||
1. **Three Theme Options:**
|
||||
- **Light**: Force light color scheme regardless of system preference
|
||||
- **Dark**: Force dark color scheme regardless of system preference
|
||||
- **Auto**: Follow system preference (uses `prefers-color-scheme` media query)
|
||||
|
||||
2. **Animated Button Behavior:**
|
||||
- Default state: Single circular button showing current theme icon
|
||||
- On hover (desktop): Button expands horizontally left-to-right revealing 3 options
|
||||
- On click/tap (mobile): Button expands to show 3 options
|
||||
- Each option shows an icon (sun, moon, auto) and optional label
|
||||
- Smooth animation: width expansion + fade-in of additional buttons
|
||||
- Click any option: Collapse button + apply theme + save preference
|
||||
|
||||
3. **Positioning:**
|
||||
- Fixed position at top-right of viewport
|
||||
- Always visible (doesn't scroll with page)
|
||||
- Positioned above other content (high z-index)
|
||||
- Works on mobile and desktop viewports
|
||||
|
||||
4. **Persistence:**
|
||||
- Save user preference to localStorage: `localStorage['theme-mode']`
|
||||
- Values: 'light', 'dark', 'auto'
|
||||
- On page load: Read localStorage and apply saved preference
|
||||
- If no saved preference: Default to 'auto' (follow system)
|
||||
|
||||
**Reference Files:**
|
||||
@templates/partials/navigation/view-controls.html - Existing toggle pattern with localStorage
|
||||
@static/css/main.css - Existing theme classes and styles
|
||||
@static/hyperscript/functions._hs - Existing hyperscript functions
|
||||
|
||||
**Tech Stack:**
|
||||
- CSS custom properties (CSS variables) for theme colors
|
||||
- CSS `prefers-color-scheme` media query for system detection
|
||||
- Hyperscript for button animation and theme switching logic
|
||||
- localStorage for persistence
|
||||
- Iconify icons for theme indicators (already in use)
|
||||
</context>
|
||||
|
||||
<requirements>
|
||||
|
||||
## 1. Theme System Architecture
|
||||
|
||||
**CSS Variables Structure:**
|
||||
Create a comprehensive set of CSS custom properties for theming:
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Light theme (default) */
|
||||
--bg-primary: #ffffff;
|
||||
--bg-secondary: #f5f5f5;
|
||||
--text-primary: #333333;
|
||||
--text-secondary: #666666;
|
||||
--border-color: #e0e0e0;
|
||||
--shadow: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Dark theme - applied via [data-theme="dark"] */
|
||||
[data-theme="dark"] {
|
||||
--bg-primary: #1a1a1a;
|
||||
--bg-secondary: #2a2a2a;
|
||||
--text-primary: #e0e0e0;
|
||||
--text-secondary: #b0b0b0;
|
||||
--border-color: #404040;
|
||||
--shadow: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Auto theme - uses media query */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
[data-theme="auto"] {
|
||||
/* Same as dark theme variables */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why CSS Variables:**
|
||||
- Single source of truth for colors
|
||||
- Easy to maintain and extend
|
||||
- Automatically cascade to all components
|
||||
- Better performance than class-based theme switching for large DOMs
|
||||
|
||||
**Theme Application:**
|
||||
- Apply theme via `data-theme` attribute on `<html>` or `<body>`
|
||||
- Values: `data-theme="light"`, `data-theme="dark"`, `data-theme="auto"`
|
||||
- JavaScript/Hyperscript sets this attribute based on user selection
|
||||
|
||||
## 2. Animated Button Component
|
||||
|
||||
**Button States:**
|
||||
|
||||
1. **Collapsed (default):**
|
||||
- Single circular button (~48px diameter)
|
||||
- Shows icon representing current theme (sun/moon/auto)
|
||||
- Subtle shadow and hover effect
|
||||
|
||||
2. **Expanded (on hover/click):**
|
||||
- Expands horizontally to ~160px width (or 3 × 48px = 144px)
|
||||
- Reveals 3 circular buttons side-by-side
|
||||
- Each button: icon + optional tooltip label
|
||||
- Smooth width transition (300ms ease-out)
|
||||
- Icons fade in with staggered delay for polish
|
||||
|
||||
**Animation Specifications:**
|
||||
- Expansion: `width: 48px → 160px` over 300ms with ease-out easing
|
||||
- Icon fade: Opacity 0 → 1 over 200ms with 50ms stagger
|
||||
- Collapse: Reverse animation when mouse leaves (desktop) or after selection
|
||||
- Use `transform` and `opacity` for GPU acceleration (avoid width if possible, use scale + clip)
|
||||
|
||||
**HTML Structure Example:**
|
||||
```html
|
||||
<div id="theme-switcher" class="theme-switcher"
|
||||
_="on mouseenter add .expanded to me
|
||||
on mouseleave remove .expanded from me">
|
||||
|
||||
<!-- Current theme indicator (always visible) -->
|
||||
<button class="theme-btn active" data-theme-mode="auto">
|
||||
<iconify-icon icon="mdi:theme-light-dark" width="20"></iconify-icon>
|
||||
</button>
|
||||
|
||||
<!-- Additional options (visible when expanded) -->
|
||||
<button class="theme-btn" data-theme-mode="light"
|
||||
_="on click call setTheme('light')">
|
||||
<iconify-icon icon="mdi:white-balance-sunny" width="20"></iconify-icon>
|
||||
<span class="tooltip">Light</span>
|
||||
</button>
|
||||
|
||||
<button class="theme-btn" data-theme-mode="dark"
|
||||
_="on click call setTheme('dark')">
|
||||
<iconify-icon icon="mdi:moon-waning-crescent" width="20"></iconify-icon>
|
||||
<span class="tooltip">Dark</span>
|
||||
</button>
|
||||
|
||||
<button class="theme-btn" data-theme-mode="auto"
|
||||
_="on click call setTheme('auto')">
|
||||
<iconify-icon icon="mdi:theme-light-dark" width="20"></iconify-icon>
|
||||
<span class="tooltip">Auto</span>
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Responsive Behavior:**
|
||||
- Desktop (>768px): Expand on hover, collapse on mouse leave
|
||||
- Mobile/Tablet (≤768px): Expand on tap, collapse on background tap or selection
|
||||
- Use media query + hyperscript to detect and apply appropriate behavior
|
||||
|
||||
## 3. Theme Switching Logic
|
||||
|
||||
**Hyperscript Function:**
|
||||
Create a global `setTheme(mode)` function in `static/hyperscript/functions._hs`:
|
||||
|
||||
```hyperscript
|
||||
def setTheme(mode)
|
||||
-- Save preference to localStorage
|
||||
set localStorage['theme-mode'] to mode
|
||||
|
||||
-- Apply theme to document
|
||||
if mode is 'light'
|
||||
set document.documentElement's @data-theme to 'light'
|
||||
else if mode is 'dark'
|
||||
set document.documentElement's @data-theme to 'dark'
|
||||
else if mode is 'auto'
|
||||
set document.documentElement's @data-theme to 'auto'
|
||||
end
|
||||
|
||||
-- Update button active states
|
||||
set buttons to .theme-btn in #theme-switcher
|
||||
for btn in buttons
|
||||
if btn's @data-theme-mode is mode
|
||||
add .active to btn
|
||||
else
|
||||
remove .active from btn
|
||||
end
|
||||
end
|
||||
|
||||
-- Collapse button on mobile
|
||||
if window.innerWidth <= 768
|
||||
remove .expanded from #theme-switcher
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
**Page Load Theme Detection:**
|
||||
Create an initialization script that runs immediately on page load:
|
||||
|
||||
```hyperscript
|
||||
def initTheme()
|
||||
-- Get saved preference or default to 'auto'
|
||||
set savedTheme to localStorage['theme-mode'] or 'auto'
|
||||
call setTheme(savedTheme)
|
||||
end
|
||||
|
||||
-- Run on page load
|
||||
on load call initTheme()
|
||||
```
|
||||
|
||||
**System Preference Detection:**
|
||||
Listen for system theme changes when in 'auto' mode:
|
||||
|
||||
```javascript
|
||||
// Optional: Listen for system theme changes
|
||||
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
darkModeQuery.addEventListener('change', (e) => {
|
||||
const currentMode = localStorage.getItem('theme-mode');
|
||||
if (currentMode === 'auto' || !currentMode) {
|
||||
// Theme will automatically update via CSS media query
|
||||
// No action needed, but could trigger a visual indicator
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 4. Positioning and Layout
|
||||
|
||||
**Fixed Positioning:**
|
||||
```css
|
||||
.theme-switcher {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000; /* Above all content */
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 24px;
|
||||
padding: 4px;
|
||||
box-shadow: 0 2px 8px var(--shadow);
|
||||
width: 56px; /* Single button + padding */
|
||||
transition: width 300ms ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.theme-switcher.expanded {
|
||||
width: 176px; /* 3 buttons + gaps + padding */
|
||||
}
|
||||
|
||||
.theme-btn {
|
||||
min-width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: background 200ms ease;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.theme-btn:not(.active) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.theme-switcher:not(.expanded) .theme-btn:not(.active) {
|
||||
display: none; /* Hide non-active buttons when collapsed */
|
||||
}
|
||||
|
||||
.theme-btn:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.theme-btn.active {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
```
|
||||
|
||||
**Mobile Considerations:**
|
||||
- Increase touch target size to minimum 44×44px (iOS HIG)
|
||||
- Ensure button doesn't overlap with hamburger menu or other controls
|
||||
- Consider adding backdrop overlay when expanded on mobile
|
||||
- Position may need adjustment on smaller screens (e.g., `top: 16px; right: 16px`)
|
||||
|
||||
## 5. Color Scheme Design
|
||||
|
||||
**Light Theme Colors:**
|
||||
- Background: White to light gray (#ffffff, #f5f5f5)
|
||||
- Text: Dark gray to black (#333333, #1a1a1a)
|
||||
- Accent: Keep existing brand colors
|
||||
- Borders: Light gray (#e0e0e0)
|
||||
|
||||
**Dark Theme Colors:**
|
||||
- Background: Very dark gray to black (#1a1a1a, #0a0a0a)
|
||||
- Text: Light gray to white (#e0e0e0, #ffffff)
|
||||
- Accent: Slightly brighter versions of brand colors
|
||||
- Borders: Medium dark gray (#404040)
|
||||
|
||||
**Design Principles:**
|
||||
- Maintain sufficient contrast (WCAG AA: 4.5:1 for text, AAA: 7:1 preferred)
|
||||
- Don't use pure black (#000000) for dark backgrounds (too harsh)
|
||||
- Don't use pure white text on dark backgrounds (causes halation)
|
||||
- Test with both themes for readability and accessibility
|
||||
|
||||
## 6. Persistence and State Management
|
||||
|
||||
**localStorage Schema:**
|
||||
```javascript
|
||||
// Store theme preference
|
||||
localStorage.setItem('theme-mode', 'light'); // or 'dark', 'auto'
|
||||
|
||||
// Read on page load
|
||||
const savedTheme = localStorage.getItem('theme-mode') || 'auto';
|
||||
```
|
||||
|
||||
**State Synchronization:**
|
||||
- Button active state must always reflect current theme
|
||||
- System theme changes should update UI if in 'auto' mode
|
||||
- Manual theme selection should override system preference
|
||||
- Theme should apply before page render to avoid flash (FOUC)
|
||||
|
||||
**Initial Load Optimization:**
|
||||
To prevent flash of wrong theme, add inline script in `<head>`:
|
||||
|
||||
```html
|
||||
<script>
|
||||
(function() {
|
||||
const theme = localStorage.getItem('theme-mode') || 'auto';
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
This runs before page render, applying theme instantly.
|
||||
|
||||
## 7. Integration with Existing Theme System
|
||||
|
||||
**Current System:**
|
||||
- `.theme-clean` class toggles between default and clean layouts
|
||||
- This is a **layout** theme, not a **color** theme
|
||||
|
||||
**New System:**
|
||||
- `data-theme` attribute controls **color** theme (light/dark/auto)
|
||||
- `.theme-clean` class still controls **layout** theme
|
||||
|
||||
**Both Can Coexist:**
|
||||
```html
|
||||
<body class="theme-clean" data-theme="dark">
|
||||
<!-- Clean layout + Dark colors -->
|
||||
</body>
|
||||
```
|
||||
|
||||
**CSS Organization:**
|
||||
- Keep existing `.theme-clean` styles unchanged
|
||||
- Add new `[data-theme="dark"]` styles for colors
|
||||
- Ensure both systems work independently and together
|
||||
|
||||
</requirements>
|
||||
|
||||
<implementation>
|
||||
|
||||
## Step-by-Step Implementation Plan
|
||||
|
||||
### Phase 1: Create CSS Theme Variables
|
||||
|
||||
1. **Add CSS Variables to `static/css/main.css`:**
|
||||
- Define `:root` (light theme) color variables
|
||||
- Define `[data-theme="dark"]` color variables
|
||||
- Define `@media (prefers-color-scheme: dark)` with `[data-theme="auto"]`
|
||||
- Update existing components to use CSS variables instead of hardcoded colors
|
||||
|
||||
2. **Color Mapping Strategy:**
|
||||
- Audit existing colors in `main.css`
|
||||
- Create a mapping from hardcoded colors to CSS variable names
|
||||
- Replace colors incrementally (high-impact areas first: backgrounds, text, borders)
|
||||
|
||||
### Phase 2: Create Theme Switcher Button Component
|
||||
|
||||
1. **Create HTML Template:**
|
||||
- New file: `templates/partials/theme-switcher.html`
|
||||
- Structure: Container with 3 buttons (light, dark, auto)
|
||||
- Include iconify icons for each theme
|
||||
- Add hyperscript for expand/collapse behavior
|
||||
|
||||
2. **Create CSS Styles:**
|
||||
- Add to `static/css/main.css` or new `static/css/theme-switcher.css`
|
||||
- Fixed positioning at top-right
|
||||
- Collapsed and expanded states
|
||||
- Button hover and active states
|
||||
- Smooth transitions and animations
|
||||
- Responsive behavior (desktop vs mobile)
|
||||
|
||||
3. **Include in Main Layout:**
|
||||
- Add `{{template "theme-switcher" .}}` to main layout template
|
||||
- Position below action bar but above content (z-index management)
|
||||
|
||||
### Phase 3: Implement Theme Switching Logic
|
||||
|
||||
1. **Add Hyperscript Functions to `static/hyperscript/functions._hs`:**
|
||||
- `setTheme(mode)` - Apply theme and save to localStorage
|
||||
- `initTheme()` - Load saved theme on page load
|
||||
- Button click handlers for each theme option
|
||||
|
||||
2. **Add Inline Script for FOUC Prevention:**
|
||||
- In `<head>` of main template, add inline script
|
||||
- Reads localStorage and sets `data-theme` before render
|
||||
- Prevents flash of wrong theme
|
||||
|
||||
3. **System Theme Detection (Optional Enhancement):**
|
||||
- Add media query listener for system theme changes
|
||||
- Update UI when system preference changes (if in 'auto' mode)
|
||||
|
||||
### Phase 4: Update Existing Components with Theme Variables
|
||||
|
||||
**Priority Order:**
|
||||
1. Main backgrounds and text (highest visual impact)
|
||||
2. CV paper and content areas
|
||||
3. Navigation and controls
|
||||
4. Borders and shadows
|
||||
5. Accent colors and highlights
|
||||
|
||||
**Example Refactor:**
|
||||
```css
|
||||
/* Before */
|
||||
.cv-container {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* After */
|
||||
.cv-container {
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 5: Testing and Refinement
|
||||
|
||||
1. **Visual Testing:**
|
||||
- Test all three theme modes (light, dark, auto)
|
||||
- Verify color contrast meets WCAG AA standards
|
||||
- Check all components render correctly in both themes
|
||||
|
||||
2. **Interaction Testing:**
|
||||
- Button expands smoothly on hover (desktop)
|
||||
- Button expands/collapses on tap (mobile)
|
||||
- Theme applies instantly when selected
|
||||
- Active state updates correctly
|
||||
|
||||
3. **Persistence Testing:**
|
||||
- Save theme preference and reload page
|
||||
- Verify saved theme is applied before render (no FOUC)
|
||||
- Clear localStorage and verify default to 'auto'
|
||||
|
||||
4. **System Integration Testing:**
|
||||
- Change system theme preference (OS settings)
|
||||
- Verify 'auto' mode respects system preference
|
||||
- Verify 'light' and 'dark' modes override system
|
||||
|
||||
**What to Prioritize:**
|
||||
1. Core theme switching functionality
|
||||
2. FOUC prevention (inline script)
|
||||
3. Button animation and UX
|
||||
4. High-impact component theming (backgrounds, text)
|
||||
5. Fine-tuning colors and contrast
|
||||
|
||||
**What to Avoid:**
|
||||
- Don't try to theme every single pixel in first pass - prioritize high-impact areas
|
||||
- Don't use JavaScript for theme application if CSS can handle it (performance)
|
||||
- Don't forget mobile UX - touch targets, tap behavior, responsive design
|
||||
- Don't hardcode colors - always use CSS variables
|
||||
- Don't sacrifice accessibility for aesthetics (contrast ratios are critical)
|
||||
|
||||
**Why These Constraints Matter:**
|
||||
- **CSS Variables:** Maintainable, performant, scalable theming system
|
||||
- **FOUC Prevention:** Critical for professional UX - theme must apply before render
|
||||
- **Mobile-First:** Touch devices are primary interaction method for many users
|
||||
- **Accessibility:** WCAG compliance is non-negotiable for professional applications
|
||||
- **Progressive Enhancement:** Light theme works even if JavaScript fails
|
||||
|
||||
</implementation>
|
||||
|
||||
<output>
|
||||
Create/modify the following files:
|
||||
|
||||
1. **`./templates/partials/theme-switcher.html`** (NEW)
|
||||
- Animated theme switcher button component
|
||||
- Three buttons for light, dark, auto modes
|
||||
- Hyperscript for expand/collapse and theme selection
|
||||
- Iconify icons for each theme option
|
||||
|
||||
2. **`./static/css/theme-variables.css`** (NEW) or add to `./static/css/main.css`
|
||||
- CSS custom properties for light theme (`:root`)
|
||||
- CSS custom properties for dark theme (`[data-theme="dark"]`)
|
||||
- Media query for auto mode (`@media (prefers-color-scheme: dark)`)
|
||||
- Theme switcher button styles
|
||||
|
||||
3. **`./static/hyperscript/functions._hs`**
|
||||
- Add `setTheme(mode)` function
|
||||
- Add `initTheme()` function
|
||||
- Add page load initialization
|
||||
|
||||
4. **`./templates/index.html`** (or main layout template)
|
||||
- Include theme switcher component
|
||||
- Add inline FOUC prevention script in `<head>`
|
||||
|
||||
5. **`./static/css/main.css`**
|
||||
- Refactor existing hardcoded colors to use CSS variables
|
||||
- Update backgrounds, text, borders, shadows
|
||||
- Ensure compatibility with both theme systems (layout + color)
|
||||
|
||||
**Optional (recommended):**
|
||||
6. **`./static/js/theme-system-listener.js`** (NEW)
|
||||
- Listen for system theme changes
|
||||
- Update UI when system preference changes in 'auto' mode
|
||||
- Only needed for dynamic system theme updates
|
||||
|
||||
</output>
|
||||
|
||||
<verification>
|
||||
Before declaring complete, perform these comprehensive tests:
|
||||
|
||||
**1. Visual Verification:**
|
||||
- [ ] Light mode: All text readable, good contrast, professional appearance
|
||||
- [ ] Dark mode: All text readable, good contrast, not too harsh
|
||||
- [ ] Auto mode: Follows system preference correctly
|
||||
- [ ] Button expands smoothly showing 3 options
|
||||
- [ ] Button collapses smoothly after selection
|
||||
- [ ] Active button is visually distinct
|
||||
|
||||
**2. Interaction Testing:**
|
||||
- [ ] Desktop: Button expands on hover, collapses on mouse leave
|
||||
- [ ] Mobile: Button expands on tap, collapses on selection or backdrop tap
|
||||
- [ ] Click light button: Theme switches to light instantly
|
||||
- [ ] Click dark button: Theme switches to dark instantly
|
||||
- [ ] Click auto button: Theme follows system preference
|
||||
- [ ] No delay or lag in theme application
|
||||
|
||||
**3. Persistence Testing:**
|
||||
- [ ] Select light theme, reload page → Still light
|
||||
- [ ] Select dark theme, reload page → Still dark
|
||||
- [ ] Select auto theme, reload page → Still auto (follows system)
|
||||
- [ ] Clear localStorage → Defaults to auto mode
|
||||
- [ ] No flash of unstyled content (FOUC) on page load
|
||||
|
||||
**4. System Integration:**
|
||||
- [ ] Set system to light mode, set app to auto → Light theme applied
|
||||
- [ ] Change system to dark mode with app in auto → Dark theme applied
|
||||
- [ ] Set app to light mode, change system to dark → Stays light (override works)
|
||||
- [ ] Media query correctly detects system preference
|
||||
|
||||
**5. Accessibility Testing:**
|
||||
- [ ] Light mode: WCAG AA contrast ratio for all text (4.5:1 minimum)
|
||||
- [ ] Dark mode: WCAG AA contrast ratio for all text
|
||||
- [ ] Button tooltips/labels are readable
|
||||
- [ ] Keyboard navigation works (tab through theme options)
|
||||
- [ ] Focus states are visible
|
||||
- [ ] Screen reader announces theme changes
|
||||
|
||||
**6. Component Coverage:**
|
||||
- [ ] CV container background themed correctly
|
||||
- [ ] Text colors themed correctly (headings, body, secondary)
|
||||
- [ ] Navigation elements themed correctly
|
||||
- [ ] Borders and dividers visible in both themes
|
||||
- [ ] Shadows appropriate for both themes
|
||||
- [ ] Icons and images work in both themes
|
||||
- [ ] Toggle controls remain functional and readable
|
||||
|
||||
**7. Layout Compatibility:**
|
||||
- [ ] Theme works with default layout (not `.theme-clean`)
|
||||
- [ ] Theme works with `.theme-clean` layout
|
||||
- [ ] Both theme systems can be used simultaneously
|
||||
- [ ] No conflicts between layout theme and color theme
|
||||
|
||||
**8. Animation Performance:**
|
||||
- [ ] Button expansion is smooth (60fps, no jank)
|
||||
- [ ] Theme switching is instant (no visible delay)
|
||||
- [ ] GPU-accelerated properties used (opacity, transform)
|
||||
- [ ] No layout thrashing during animations
|
||||
|
||||
**9. Mobile Specific:**
|
||||
- [ ] Button positioned correctly on mobile (no overlap with other controls)
|
||||
- [ ] Touch targets are adequate size (44×44px minimum)
|
||||
- [ ] Tap behavior works correctly (expand/collapse)
|
||||
- [ ] Responsive design adapts to small screens
|
||||
|
||||
**10. Edge Cases:**
|
||||
- [ ] Very fast clicking doesn't break state
|
||||
- [ ] System theme change during 'auto' mode updates correctly
|
||||
- [ ] Works in private/incognito mode (localStorage available)
|
||||
- [ ] Graceful degradation if JavaScript disabled (defaults to light)
|
||||
|
||||
**Success Indicators:**
|
||||
✅ Three theme modes work correctly (light, dark, auto)
|
||||
✅ System preference detected and respected in auto mode
|
||||
✅ Theme persists across page reloads (localStorage)
|
||||
✅ No FOUC - theme applies before page render
|
||||
✅ Animated button expands/collapses smoothly
|
||||
✅ Responsive behavior (hover on desktop, tap on mobile)
|
||||
✅ All text meets WCAG AA contrast standards
|
||||
✅ Theme switching is instant and smooth
|
||||
✅ Works alongside existing `.theme-clean` layout system
|
||||
✅ Professional, polished UX
|
||||
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
1. Three distinct theme modes implemented: Light, Dark, Auto (system)
|
||||
2. System preference correctly detected via `prefers-color-scheme` media query
|
||||
3. User preference persists in localStorage across sessions
|
||||
4. Animated expanding button reveals theme options smoothly (300ms transition)
|
||||
5. Responsive behavior: hover on desktop (>768px), tap on mobile (≤768px)
|
||||
6. Fixed positioning at top-right, always visible, doesn't interfere with content
|
||||
7. No flash of unstyled content (FOUC) - theme applies before render
|
||||
8. All text meets WCAG AA contrast ratio (4.5:1 for normal text)
|
||||
9. Theme applies instantly on selection (<50ms perceived delay)
|
||||
10. Compatible with existing `.theme-clean` layout system
|
||||
11. Accessible keyboard navigation and screen reader support
|
||||
12. Smooth animations using GPU-accelerated properties
|
||||
13. Code follows existing project patterns and conventions
|
||||
14. Implementation is maintainable and well-documented
|
||||
</success_criteria>
|
||||
|
||||
<references>
|
||||
**CSS Color Schemes:**
|
||||
- MDN prefers-color-scheme: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
|
||||
- Material Design dark theme: https://material.io/design/color/dark-theme.html
|
||||
- CSS custom properties: https://developer.mozilla.org/en-US/docs/Web/CSS/--*
|
||||
|
||||
**Best Practices:**
|
||||
- Avoid pure black in dark mode (use #1a1a1a or similar)
|
||||
- Maintain consistent contrast ratios
|
||||
- Use elevation (shadows) to create depth in dark mode
|
||||
- Test with real system theme preferences
|
||||
- Prevent FOUC with inline script in head
|
||||
|
||||
**Icon Suggestions (iconify):**
|
||||
- Light mode: `mdi:white-balance-sunny` or `mdi:brightness-7`
|
||||
- Dark mode: `mdi:moon-waning-crescent` or `mdi:weather-night`
|
||||
- Auto mode: `mdi:theme-light-dark` or `mdi:brightness-auto`
|
||||
|
||||
**Animation Patterns:**
|
||||
- Expand: ease-out (starts fast, ends slow)
|
||||
- Collapse: ease-in (starts slow, ends fast)
|
||||
- Theme switch: instant (no transition on color change)
|
||||
- Icons: staggered fade-in for polish
|
||||
|
||||
**Accessibility:**
|
||||
- WCAG AA: 4.5:1 for normal text, 3:1 for large text
|
||||
- WCAG AAA: 7:1 for normal text, 4.5:1 for large text
|
||||
- Test with actual screen readers (VoiceOver, NVDA)
|
||||
- Ensure focus indicators are visible in both themes
|
||||
</references>
|
||||
|
||||
<research>
|
||||
**Files to Examine:**
|
||||
@static/css/main.css - Current color usage and theme system
|
||||
@templates/partials/navigation/view-controls.html - Existing toggle pattern
|
||||
@static/hyperscript/functions._hs - Existing hyperscript functions
|
||||
@templates/index.html - Main layout structure
|
||||
|
||||
**Questions to Answer:**
|
||||
1. What colors are currently hardcoded and need to become variables?
|
||||
2. How is the existing `.theme-clean` system implemented?
|
||||
3. Where should the theme switcher button be positioned to not conflict with existing UI?
|
||||
4. What iconify icons are already in use (maintain consistency)?
|
||||
5. What localStorage keys are already in use (avoid conflicts)?
|
||||
</research>
|
||||
|
||||
<additional_notes>
|
||||
**Implementation Philosophy:**
|
||||
- Progressive enhancement: Works without JavaScript (defaults to light)
|
||||
- Mobile-first: Touch interactions are primary, hover is enhancement
|
||||
- Performance-first: CSS handles theme, JavaScript only manages state
|
||||
- Accessibility-first: WCAG compliance is non-negotiable
|
||||
- Maintainability: CSS variables make future updates trivial
|
||||
|
||||
**Design Considerations:**
|
||||
- Button should feel premium and polished (subtle shadows, smooth animations)
|
||||
- Don't over-animate - smooth and subtle is better than flashy
|
||||
- Dark mode should be comfortable for extended reading, not just "looks cool"
|
||||
- Auto mode should be the intelligent default (respects user's OS preference)
|
||||
|
||||
**Future Enhancements:**
|
||||
- Add transition animation when theme changes (optional fade)
|
||||
- Support custom theme colors (user-selectable accent colors)
|
||||
- Add sunrise/sunset auto-scheduling (auto-switch based on time)
|
||||
- Sync theme preference across devices (server-side storage)
|
||||
- Add "high contrast" mode for accessibility
|
||||
</additional_notes>
|
||||
Reference in New Issue
Block a user