- 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
218 lines
7.6 KiB
Markdown
218 lines
7.6 KiB
Markdown
# 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` → `<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">`
|
|
|
|
2. **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
|
|
|
|
1. Page loads with hardcoded `<body class="theme-tokyo-night">`
|
|
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
|
|
<!-- 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)
|
|
|
|
```templ
|
|
<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`:**
|
|
```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
|