Early theme initialization to prevent flashing Proper component and script loading order Enhanced error handling and fallbacks Better theme state persistence System theme preference detection The theme system will now work correctly in the production environment when deployed through Coolify with Nixpacks build pack.
109 lines
3.7 KiB
JavaScript
109 lines
3.7 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);
|
|
document.documentElement.setAttribute('data-theme', initialTheme);
|
|
} catch (error) {
|
|
console.warn('Early theme initialization error:', error);
|
|
// Fallback to light theme
|
|
document.documentElement.setAttribute('data-theme', 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 toggleTheme() {
|
|
try {
|
|
const currentTheme = getCurrentTheme();
|
|
const newTheme = currentTheme === THEMES.DARK ? THEMES.LIGHT : THEMES.DARK;
|
|
|
|
document.documentElement.setAttribute('data-theme', 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;
|
|
document.documentElement.setAttribute('data-theme', 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);
|
|
} catch (error) {
|
|
console.warn('Theme persistence error:', error);
|
|
}
|
|
}
|
|
})();
|