Files
bookhoard/web/src/header.ts
T
john-okeefe 7a420ef975 refactor(theme): fix theme consistency and persistence
- Apply server-side theme rendering to authenticated pages
  - bookshelf.templ: use dynamic theme-{ user.Theme }
  - admin pages: use dynamic theme rendering
- Add progressive enhancement for public pages
  - index.templ, login.templ, register.templ: inline localStorage check
  - Prevents theme flash on page load
- Consolidate wood theme logic into theme.ts
  - Move wood gradient handling from header.ts to theme.ts
  - Apply wood themes consistently via applyTheme()
- Export applyTheme to window for use by header.ts
- Fix theme selector by adding theme.js to header template
2026-02-24 10:25:06 -05:00

87 lines
2.7 KiB
TypeScript

// Header functionality
const toggleThemeDropdown = (): void => {
const dropdown = document.getElementById('theme-dropdown');
if (dropdown) {
dropdown.classList.toggle('hidden');
// Close user menu if open
const userMenu = document.getElementById('user-menu');
if (userMenu && !dropdown.classList.contains('hidden')) {
userMenu.classList.add('hidden');
}
}
};
const toggleUserMenu = (): void => {
const menu = document.getElementById('user-menu');
if (menu) {
menu.classList.toggle('hidden');
// Close theme dropdown if open
const themeDropdown = document.getElementById('theme-dropdown');
if (themeDropdown && !menu.classList.contains('hidden')) {
themeDropdown.classList.add('hidden');
}
}
};
const changeThemeTo = (theme: string): void => {
// Apply the theme using the consolidated function from theme.ts
if ((window as any).applyTheme) {
(window as any).applyTheme(theme);
}
// Save to server if logged in
const token = localStorage.getItem('token');
if (token) {
fetch('/api/auth/theme', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ theme })
}).catch(err => console.log('Theme save failed', err));
}
// Close dropdown
const dropdown = document.getElementById('theme-dropdown');
if (dropdown) {
dropdown.classList.add('hidden');
}
};
const logout = (): void => {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/';
};
// Close dropdowns when clicking outside
document.addEventListener('click', (e) => {
const target = e.target as HTMLElement;
const themeDropdown = document.getElementById('theme-dropdown');
const userMenu = document.getElementById('user-menu');
const themeButton = target?.closest('button[onclick="toggleThemeDropdown()"]');
const userButton = target?.closest('button[onclick="toggleUserMenu()"]');
if (!themeButton && themeDropdown && !themeDropdown.classList.contains('hidden')) {
if (!themeDropdown.contains(target)) {
themeDropdown.classList.add('hidden');
}
}
if (!userButton && userMenu && !userMenu.classList.contains('hidden')) {
if (!userMenu.contains(target)) {
userMenu.classList.add('hidden');
}
}
});
// Make functions available globally
(window as any).toggleThemeDropdown = toggleThemeDropdown;
(window as any).toggleUserMenu = toggleUserMenu;
(window as any).changeThemeTo = changeThemeTo;
(window as any).logout = logout;