Files
minne/html-router/assets/theme-toggle.js
Per Stark b25cfb4633 feat: add user theme preference
- Add theme field to User model (common)
- Create migration for theme field
- Add theme selection to Account Settings (html-router)
- Implement server-side theme rendering in base template
- Update JS for system/preference theme handling
- Remove header theme toggle for authenticated users
2026-01-16 13:54:07 +01:00

78 lines
3.1 KiB
JavaScript

// Global media query and listener state
const systemMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
let isSystemListenerAttached = false;
const handleSystemThemeChange = (e) => {
const themePreference = document.documentElement.getAttribute('data-theme-preference');
if (themePreference === 'system') {
document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light');
}
};
const initializeTheme = () => {
const themeToggle = document.querySelector('.theme-controller');
const themePreference = document.documentElement.getAttribute('data-theme-preference');
if (themeToggle) {
// Anonymous mode
if (isSystemListenerAttached) {
systemMediaQuery.removeEventListener('change', handleSystemThemeChange);
isSystemListenerAttached = false;
}
// Avoid re-binding if already bound
if (themeToggle.dataset.bound) return;
themeToggle.dataset.bound = "true";
// Detect system preference
const prefersDark = systemMediaQuery.matches;
// Initialize theme from local storage or system preference
const savedTheme = localStorage.getItem('theme');
const initialTheme = savedTheme ? savedTheme : (prefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', initialTheme);
themeToggle.checked = initialTheme === 'dark';
// Update theme and local storage on toggle
themeToggle.addEventListener('change', () => {
const theme = themeToggle.checked ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
});
} else {
// Authenticated mode
localStorage.removeItem('theme');
if (themePreference === 'system') {
// Ensure correct theme is set immediately
const currentSystemTheme = systemMediaQuery.matches ? 'dark' : 'light';
// Only update if needed
if (document.documentElement.getAttribute('data-theme') !== currentSystemTheme) {
document.documentElement.setAttribute('data-theme', currentSystemTheme);
}
if (!isSystemListenerAttached) {
systemMediaQuery.addEventListener('change', handleSystemThemeChange);
isSystemListenerAttached = true;
}
} else {
if (isSystemListenerAttached) {
systemMediaQuery.removeEventListener('change', handleSystemThemeChange);
isSystemListenerAttached = false;
}
// Ensure data-theme matches preference
if (themePreference && document.documentElement.getAttribute('data-theme') !== themePreference) {
document.documentElement.setAttribute('data-theme', themePreference);
}
}
}
};
// Run the initialization after the DOM is fully loaded
document.addEventListener('DOMContentLoaded', initializeTheme);
// Reinitialize theme toggle after HTMX swaps
document.addEventListener('htmx:afterSwap', initializeTheme);
document.addEventListener('htmx:afterSettle', initializeTheme);