- Add THEME_FIX_PLAN.md: comprehensive plan for theme system consistency - Add ADMIN_SIDEBAR_PLAN.md: reusable admin sidebar component plan - Add WOOD_PANELING_PLAN.md: wood paneling and full-width layout plan
7.6 KiB
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:
-
Hardcoded theme templates (problematic):
admin_library.templ→<body class="theme-tokyo-night">admin_users.templ→<body class="theme-tokyo-night">bookshelf.templ→<body class="theme-tokyo-night">index.templ→<body class="theme-tokyo-night">login.templ→<body class="theme-tokyo-night">register.templ→<body class="theme-tokyo-night">
-
Dynamic theme templates (working correctly):
dashboard.templ→<body class="theme-{ user.Theme }">analytics.templ→<body class="theme-{ user.Theme }">collections.templ→<body class="theme-{ user.Theme }">conflicts.templ→<body class="theme-{ user.Theme }">custom_section.templ→<body class="theme-{ user.Theme }">devices.templ→<body class="theme-{ user.Theme }">docs.templ→<body class={ "theme-" + user.Theme + ... }profile.templ→<body class="theme-{ user.Theme }">progress.templ→<body class="theme-{ user.Theme }">queue.templ→<body class="theme-{ user.Theme }">unlinked_books.templ→<body class="theme-{ user.Theme }">
Why It Breaks
- Page loads with hardcoded
<body class="theme-tokyo-night"> - Browser renders initial paint with wrong theme
- JavaScript (
theme.js) loads from localStorage - JavaScript corrects the theme
- 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 iscurrentUser, notuser)templates/bookshelf.templ→theme-{ user.Theme }
Change:
<!-- Before -->
<body class="theme-tokyo-night">
<!-- After (admin_library.templ, bookshelf.templ) -->
<body class="theme-{ user.Theme }">
<!-- After (admin_users.templ) -->
<body class="theme-{ currentUser.Theme }">
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)
<body class="theme-tokyo-night">
<script>
// Progressive enhancement: check localStorage immediately
(function() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme && savedTheme !== 'tokyo-night') {
document.body.className = 'theme-' + savedTheme;
}
})();
</script>
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:
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()fromtheme.tsinstead - Or consolidate wood theme logic into shared utility
Phase 4: Consolidate Theme Functions
Problem: Two separate theme-changing functions:
changeThemeTo()inheader.ts(handles wood themes)changeTheme()intheme.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.tswith all theme logic- Both
header.tsandtheme.tsimport it
Recommendation: Option A (simpler, fewer files)
Testing Checklist
After implementation:
- Navigate to
/admin/librarywith dracula theme → No flash, loads correctly - Navigate to
/admin/userswith nord theme → No flash, loads correctly - Navigate to
/bookshelfwith 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.templtemplates/admin_users.templtemplates/bookshelf.templtemplates/index.templtemplates/login.templtemplates/register.templ
TypeScript Changes (Phase 3 & 4)
web/src/theme.ts- Add wood theme logic toapplyTheme()web/src/header.ts- SimplifychangeThemeTo()or remove- Potential:
web/src/themeUtils.ts- New shared utilities (Phase 4)
Migration Notes
-
Breaking Changes: None - purely additive/fixes
-
Backward Compatibility: Full - localStorage still works as fallback
-
Database Dependencies: Requires
user.Themefield to be populated (already exists) -
Performance: Improves perceived performance (no theme flash)
-
Progressive Enhancement: Public pages still work if JavaScript fails (default theme)
Rollback Plan
If issues arise:
- Revert template changes
- JavaScript theme loading will still work (flash remains but functional)
- No data loss (theme saved in database and localStorage)
Future Improvements
- Theme preview: Show theme preview before applying
- Custom themes: Allow users to create custom themes
- Theme persistence: Remember theme per device (mobile vs desktop)
- System preference: Detect OS dark mode preference
- High contrast mode: Add accessibility-focused themes