# 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` → `theme-{ user.Theme }` - `templates/admin_users.templ` → `theme-{ currentUser.Theme }` (note: parameter is `currentUser`, not `user`) - `templates/bookshelf.templ` → `theme-{ user.Theme }` **Change:** ```templ ``` **Requires:** Verify the correct parameter name in each template (`user` vs `currentUser`). #### Phase 2: Update Public Pages with Default Theme **Files to modify:** - `templates/index.templ` - `templates/login.templ` - `templates/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