Files
web7sys/public/js/theme.js
2024-11-17 06:40:03 +01:00

115 lines
3.8 KiB
JavaScript

// Theme handling
(function() {
// Constants
const THEME_STORAGE_KEY = 'theme';
const DEFAULT_THEME = 'light';
const THEMES = {
LIGHT: 'light',
DARK: 'dark'
};
// Initialize theme immediately to prevent flash of wrong theme
initThemeEarly();
// Then initialize everything else when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeThemeSystem);
} else {
initializeThemeSystem();
}
// Functions
function initThemeEarly() {
try {
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY);
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
// Set initial theme
const initialTheme = savedTheme || (prefersDark ? THEMES.DARK : THEMES.LIGHT);
setTheme(initialTheme);
} catch (error) {
console.warn('Early theme initialization error:', error);
// Fallback to light theme
setTheme(DEFAULT_THEME);
}
}
function initializeThemeSystem() {
try {
// Set up theme toggle button
const themeToggle = document.querySelector('.theme-toggle');
if (themeToggle) {
themeToggle.addEventListener('click', toggleTheme);
updateThemeIcon(getCurrentTheme());
}
// Set up system theme change listener
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', handleSystemThemeChange);
// Ensure theme persists across page reloads
window.addEventListener('beforeunload', persistTheme);
} catch (error) {
console.warn('Theme system initialization error:', error);
}
}
function getCurrentTheme() {
return document.documentElement.getAttribute('data-theme') || DEFAULT_THEME;
}
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
document.body.dataset.theme = theme; // Add theme to body for better SSR support
}
function toggleTheme() {
try {
const currentTheme = getCurrentTheme();
const newTheme = currentTheme === THEMES.DARK ? THEMES.LIGHT : THEMES.DARK;
setTheme(newTheme);
localStorage.setItem(THEME_STORAGE_KEY, newTheme);
updateThemeIcon(newTheme);
} catch (error) {
console.warn('Theme toggle error:', error);
}
}
function updateThemeIcon(theme) {
try {
const themeIcon = document.querySelector('.theme-toggle i');
if (themeIcon) {
themeIcon.className = theme === THEMES.DARK
? 'fas fa-sun'
: 'fas fa-moon';
}
} catch (error) {
console.warn('Theme icon update error:', error);
}
}
function handleSystemThemeChange(e) {
try {
// Only update theme if user hasn't set a preference
if (!localStorage.getItem(THEME_STORAGE_KEY)) {
const newTheme = e.matches ? THEMES.DARK : THEMES.LIGHT;
setTheme(newTheme);
updateThemeIcon(newTheme);
}
} catch (error) {
console.warn('System theme change handler error:', error);
}
}
function persistTheme() {
try {
const currentTheme = getCurrentTheme();
localStorage.setItem(THEME_STORAGE_KEY, currentTheme);
document.body.dataset.theme = currentTheme; // Ensure theme is set on body before unload
} catch (error) {
console.warn('Theme persistence error:', error);
}
}
})();