Files
bookhoard/THEME_FIX_PLAN.md
T
john-okeefe 79d10b5b37 docs: add theme fix and admin sidebar implementation plans
- 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
2026-02-24 10:24:05 -05:00

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:

  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.templtheme-{ user.Theme }
  • templates/admin_users.templtheme-{ currentUser.Theme } (note: parameter is currentUser, not user)
  • templates/bookshelf.templtheme-{ 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() 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