From 97d22687ed6a5bbed4c51f952ca991dd73a097ba Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Tue, 24 Feb 2026 08:05:04 -0500 Subject: [PATCH] docs(theme): add comprehensive theme system consistency fix plan - Document root cause of theme flashing issue - Detail implementation plan for server-side theme rendering - Include testing checklist and rollback strategy - Cover wood theme gradient persistence fix --- THEME_FIX_PLAN.md | 224 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 THEME_FIX_PLAN.md diff --git a/THEME_FIX_PLAN.md b/THEME_FIX_PLAN.md new file mode 100644 index 0000000..185b0a1 --- /dev/null +++ b/THEME_FIX_PLAN.md @@ -0,0 +1,224 @@ +# Theme System Consistency Fix + +## Problem Statement + +When users change themes via the header dropdown, new pages do not consistently apply the selected theme. Some pages flash the wrong theme (tokyo-night) before applying the correct theme, creating a poor user experience. + +## Root Cause Analysis + +### Current Implementation + +**Two types of templates exist:** + +1. **Hardcoded theme templates** (problematic): + - `admin_library.templ` → `` + - `admin_users.templ` → `` + - `bookshelf.templ` → `` + - `index.templ` → `` + - `login.templ` → `` + - `register.templ` → `` + +2. **Dynamic theme templates** (working correctly): + - `dashboard.templ` → `` + - `analytics.templ` → `` + - `collections.templ` → `` + - `conflicts.templ` → `` + - `custom_section.templ` → `` + - `devices.templ` → `` + - `docs.templ` → `` + - `progress.templ` → `` + - `queue.templ` → `` + - `unlinked_books.templ` → `` + +### Why It Breaks + +1. Page loads with hardcoded `` +2. Browser renders initial paint with wrong theme +3. JavaScript (`theme.js`) loads from localStorage +4. JavaScript corrects the theme +5. **User sees flash of tokyo-night → selected theme** + +## Solution Strategy + +### Approach: Server-Side Rendering with Progressive Enhancement + +**Principle:** The server should always render the correct theme in the HTML to prevent flashes. JavaScript provides progressive enhancement for theme switching without page reloads. + +### Implementation Plan + +#### Phase 1: Update Authenticated Pages + +**Files to modify:** +- `templates/admin_library.templ` +- `templates/admin_users.templ` +- `templates/bookshelf.templ` + +**Change:** +```templ + + + + + +``` + +**Requires:** Ensure `user` parameter is available in these templates (it should be already). + +#### Phase 2: Update Public Pages with Default Theme + +**Files to modify:** +- `templates/index.templ` +- `templates/login.templ` +- `templates/register.templ` + +**For `index.templ`:** +- Check if user object available (if logged in) +- If logged in: use `user.Theme` +- If not logged in: use default theme with localStorage check + +```templ + +``` + +**For `login.templ` and `register.templ`:** +- Use default theme since no user context +- Consider reading localStorage via inline JavaScript (progressive enhancement) + +```templ + + +``` + +#### Phase 3: Fix Wood Theme Persistence + +**Files to modify:** +- `web/src/theme.ts` + +**Problem:** Wood theme gradients are only applied in `changeThemeTo()` in `header.ts`, not in `applyTheme()` in `theme.ts`. + +**Solution:** Consolidate wood theme logic into `theme.ts` so it's consistently applied. + +**Add to `theme.ts`:** +```typescript +const applyTheme = (theme: string): void => { + // Handle wood themes with gradients + if (theme.startsWith('wood-')) { + document.body.className = `theme-${theme}`; + + let woodGradient = ''; + switch (theme) { + case 'wood-light': + woodGradient = 'linear-gradient(135deg, #deb887 0%, #d2a679 50%, #c9975b 100%)'; + break; + case 'wood-dark': + woodGradient = 'linear-gradient(135deg, #8b7355 0%, #6b5344 50%, #5a4636 100%)'; + break; + case 'wood-mahogany': + woodGradient = 'linear-gradient(135deg, #a0522d 0%, #8b4513 50%, #7a3c10 100%)'; + break; + default: + woodGradient = ''; + } + + document.body.style.background = woodGradient; + document.body.style.backgroundSize = 'cover'; + document.body.style.backgroundAttachment = 'fixed'; + } else { + // Apply regular theme + document.body.className = `theme-${theme}`; + document.body.style.background = ''; + document.body.style.backgroundSize = ''; + document.body.style.backgroundAttachment = ''; + } + + localStorage.setItem(THEME_STORAGE_KEY, theme); +}; +``` + +**Update `header.ts`:** +- Remove wood theme logic from `changeThemeTo()` +- Call `applyTheme()` from `theme.ts` instead +- Or consolidate wood theme logic into shared utility + +#### Phase 4: Consolidate Theme Functions + +**Problem:** Two separate theme-changing functions: +- `changeThemeTo()` in `header.ts` (handles wood themes) +- `changeTheme()` in `theme.ts` (doesn't handle wood themes) + +**Solution:** Create shared theme utilities + +**Option A:** Move everything to `theme.ts` +- Export `applyTheme()` to window +- Update header to use `window.applyTheme()` + +**Option B:** Create shared theme utility module +- `web/src/themeUtils.ts` with all theme logic +- Both `header.ts` and `theme.ts` import it + +**Recommendation:** Option A (simpler, fewer files) + +## Testing Checklist + +After implementation: + +- [ ] Navigate to `/admin/library` with dracula theme → No flash, loads correctly +- [ ] Navigate to `/admin/users` with nord theme → No flash, loads correctly +- [ ] Navigate to `/bookshelf` with catppuccin-mocha theme → No flash, loads correctly +- [ ] Logout → Visit `/` → Uses tokyyo-night default +- [ ] Login → Visit `/dashboard` → Uses saved theme +- [ ] Change to wood-dark → Navigate to new page → Wood gradient persists +- [ ] Change to wood-light → Navigate to new page → Wood gradient persists +- [ ] Change from wood-dark to dracula → Navigate to new page → Dracula loads correctly +- [ ] Test all theme options across all pages + +## Files Summary + +### Template Changes (Phase 1 & 2) +- `templates/admin_library.templ` +- `templates/admin_users.templ` +- `templates/bookshelf.templ` +- `templates/index.templ` +- `templates/login.templ` +- `templates/register.templ` + +### TypeScript Changes (Phase 3 & 4) +- `web/src/theme.ts` - Add wood theme logic to `applyTheme()` +- `web/src/header.ts` - Simplify `changeThemeTo()` or remove +- Potential: `web/src/themeUtils.ts` - New shared utilities (Phase 4) + +## Migration Notes + +1. **Breaking Changes:** None - purely additive/fixes + +2. **Backward Compatibility:** Full - localStorage still works as fallback + +3. **Database Dependencies:** Requires `user.Theme` field to be populated (already exists) + +4. **Performance:** Improves perceived performance (no theme flash) + +5. **Progressive Enhancement:** Public pages still work if JavaScript fails (default theme) + +## Rollback Plan + +If issues arise: +1. Revert template changes +2. JavaScript theme loading will still work (flash remains but functional) +3. No data loss (theme saved in database and localStorage) + +## Future Improvements + +1. **Theme preview:** Show theme preview before applying +2. **Custom themes:** Allow users to create custom themes +3. **Theme persistence:** Remember theme per device (mobile vs desktop) +4. **System preference:** Detect OS dark mode preference +5. **High contrast mode:** Add accessibility-focused themes