mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-23 09:18:36 +02:00
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
This commit is contained in:
@@ -1,32 +1,77 @@
|
||||
// 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');
|
||||
if (!themeToggle) {
|
||||
return;
|
||||
}
|
||||
const themeToggle = document.querySelector('.theme-controller');
|
||||
const themePreference = document.documentElement.getAttribute('data-theme-preference');
|
||||
|
||||
// Detect system preference
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
if (themeToggle) {
|
||||
// Anonymous mode
|
||||
if (isSystemListenerAttached) {
|
||||
systemMediaQuery.removeEventListener('change', handleSystemThemeChange);
|
||||
isSystemListenerAttached = false;
|
||||
}
|
||||
|
||||
// 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';
|
||||
// Avoid re-binding if already bound
|
||||
if (themeToggle.dataset.bound) return;
|
||||
themeToggle.dataset.bound = "true";
|
||||
|
||||
// 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);
|
||||
});
|
||||
// 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';
|
||||
|
||||
// Run the initialization after the DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initializeTheme();
|
||||
});
|
||||
// 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);
|
||||
});
|
||||
|
||||
// Reinitialize theme toggle after HTMX swaps
|
||||
document.addEventListener('htmx:afterSwap', initializeTheme);
|
||||
document.addEventListener('htmx:afterSettle', initializeTheme);
|
||||
} 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);
|
||||
|
||||
Reference in New Issue
Block a user