// File: ./src/js/theme.js // Theme management functionality (function() { 'use strict'; let currentTheme = 'auto'; let mediaQuery; // Initialize theme system function init() { // Get stored theme or default to auto currentTheme = localStorage.getItem('theme') || 'auto'; // Set up media query listener for auto mode mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); mediaQuery.addEventListener('change', handleSystemThemeChange); // Apply initial theme applyTheme(currentTheme); // Set up theme selector buttons setupThemeSelector(); } // Set up theme selector button event handlers function setupThemeSelector() { const themeButtons = document.querySelectorAll('.theme-btn'); themeButtons.forEach(button => { const theme = button.getAttribute('data-theme'); // Set initial active state button.classList.toggle('active', theme === currentTheme); // Add click handler button.addEventListener('click', () => { setTheme(theme); }); }); } // Set theme and update UI function setTheme(theme) { if (!['light', 'dark', 'auto'].includes(theme)) { console.warn('Invalid theme:', theme); return; } currentTheme = theme; // Store in localStorage localStorage.setItem('theme', theme); // Apply theme applyTheme(theme); // Update button states updateThemeButtons(); } // Apply theme to document function applyTheme(theme) { const html = document.documentElement; // Update theme class html.className = html.className.replace(/theme-\w+/g, ''); html.classList.add(`theme-${theme}`); // Handle dark mode class if (theme === 'auto') { // Use system preference const isDark = mediaQuery ? mediaQuery.matches : window.matchMedia('(prefers-color-scheme: dark)').matches; html.classList.toggle('dark', isDark); } else { // Use explicit theme html.classList.toggle('dark', theme === 'dark'); } } // Handle system theme changes (for auto mode) function handleSystemThemeChange(event) { if (currentTheme === 'auto') { document.documentElement.classList.toggle('dark', event.matches); } } // Update theme button active states function updateThemeButtons() { const themeButtons = document.querySelectorAll('.theme-btn'); themeButtons.forEach(button => { const theme = button.getAttribute('data-theme'); button.classList.toggle('active', theme === currentTheme); }); } // Get current effective theme (resolves 'auto' to actual theme) function getEffectiveTheme() { if (currentTheme === 'auto') { return mediaQuery && mediaQuery.matches ? 'dark' : 'light'; } return currentTheme; } // Toggle between light and dark (skips auto) function toggleTheme() { const effectiveTheme = getEffectiveTheme(); setTheme(effectiveTheme === 'dark' ? 'light' : 'dark'); } // Keyboard shortcut support function setupKeyboardShortcuts() { document.addEventListener('keydown', (event) => { // Ctrl/Cmd + Shift + T to toggle theme if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.key === 'T') { event.preventDefault(); toggleTheme(); } }); } // Export functions for external use window.themeManager = { setTheme, getTheme: () => currentTheme, getEffectiveTheme, toggleTheme }; // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { init(); setupKeyboardShortcuts(); }); } else { init(); setupKeyboardShortcuts(); } })();