diff --git a/js/themes.js b/js/themes.js new file mode 100644 index 0000000..76c6f52 --- /dev/null +++ b/js/themes.js @@ -0,0 +1,172 @@ +/** + * themes.js - Theme management system + */ + +const STORAGE_KEY_THEME = 'selected-theme'; + +const themes = { + dark: { + name: 'Dark (Default)', + primary: '#1a1a2e', + secondary: '#16213e', + accent: '#0f3460', + text: '#e4e4e4', + textMuted: '#a0a0a0', + border: '#2a2a3e', + cardBg: 'rgba(30, 30, 46, 0.7)', + headerBg: 'rgba(26, 26, 46, 0.85)', + overlayBg: 'rgba(60, 60, 60, 0.35)' + }, + light: { + name: 'Light', + primary: '#f5f5f5', + secondary: '#ffffff', + accent: '#3498db', + text: '#2c3e50', + textMuted: '#7f8c8d', + border: '#dfe6e9', + cardBg: 'rgba(255, 255, 255, 0.85)', + headerBg: 'rgba(245, 245, 245, 0.95)', + overlayBg: 'rgba(255, 255, 255, 0.15)' + }, + ocean: { + name: 'Ocean', + primary: '#0a1828', + secondary: '#1a2332', + accent: '#178582', + text: '#e0f4f4', + textMuted: '#8ab4b4', + border: '#1a3a3a', + cardBg: 'rgba(26, 35, 50, 0.75)', + headerBg: 'rgba(10, 24, 40, 0.9)', + overlayBg: 'rgba(23, 133, 130, 0.15)' + }, + sunset: { + name: 'Sunset', + primary: '#1a0f1e', + secondary: '#2a1b2e', + accent: '#d4477a', + text: '#fce9e9', + textMuted: '#c4a4b4', + border: '#3a2a3e', + cardBg: 'rgba(42, 27, 46, 0.75)', + headerBg: 'rgba(26, 15, 30, 0.9)', + overlayBg: 'rgba(212, 71, 122, 0.15)' + }, + forest: { + name: 'Forest', + primary: '#0f1a0f', + secondary: '#1a2a1a', + accent: '#4a9a4a', + text: '#e4f4e4', + textMuted: '#a4c4a4', + border: '#2a3a2a', + cardBg: 'rgba(26, 42, 26, 0.75)', + headerBg: 'rgba(15, 26, 15, 0.9)', + overlayBg: 'rgba(74, 154, 74, 0.15)' + } +}; + +// Apply theme +function applyTheme(themeName) { + const theme = themes[themeName] || themes.dark; + const root = document.documentElement; + + root.style.setProperty('--color-primary', theme.primary); + root.style.setProperty('--color-secondary', theme.secondary); + root.style.setProperty('--color-accent', theme.accent); + root.style.setProperty('--color-text', theme.text); + root.style.setProperty('--color-text-muted', theme.textMuted); + root.style.setProperty('--color-border', theme.border); + root.style.setProperty('--color-card-bg', theme.cardBg); + root.style.setProperty('--color-header-bg', theme.headerBg); + root.style.setProperty('--color-overlay-bg', theme.overlayBg); + + // Save preference + try { + localStorage.setItem(STORAGE_KEY_THEME, themeName); + } catch (e) { + console.error('Error saving theme:', e); + } + + // Update active state in selector + document.querySelectorAll('.theme-option').forEach(option => { + option.classList.toggle('active', option.dataset.theme === themeName); + }); +} + +// Load saved theme +function loadSavedTheme() { + try { + const saved = localStorage.getItem(STORAGE_KEY_THEME); + return saved || 'dark'; + } catch (e) { + console.error('Error loading theme:', e); + return 'dark'; + } +} + +// Create theme selector UI +function createThemeSelector() { + const selector = document.createElement('div'); + selector.id = 'theme-selector'; + selector.className = 'theme-selector'; + + const toggle = document.createElement('button'); + toggle.className = 'theme-toggle'; + toggle.innerHTML = '🎨'; + toggle.title = 'Change Theme'; + + const menu = document.createElement('div'); + menu.className = 'theme-menu'; + + Object.entries(themes).forEach(([key, theme]) => { + const option = document.createElement('div'); + option.className = 'theme-option'; + option.dataset.theme = key; + option.textContent = theme.name; + + option.addEventListener('click', () => { + applyTheme(key); + menu.classList.remove('open'); + }); + + menu.appendChild(option); + }); + + toggle.addEventListener('click', (e) => { + e.stopPropagation(); + menu.classList.toggle('open'); + }); + + // Close menu when clicking outside + document.addEventListener('click', () => { + menu.classList.remove('open'); + }); + + selector.appendChild(toggle); + selector.appendChild(menu); + + return selector; +} + +// Initialize theme system +function initThemes() { + // Apply saved theme + const savedTheme = loadSavedTheme(); + applyTheme(savedTheme); + + // Add theme selector to header + const header = document.querySelector('header'); + if (header) { + const selector = createThemeSelector(); + header.appendChild(selector); + } +} + +// Export for use in other modules +window.themesModule = { + init: initThemes, + applyTheme: applyTheme, + themes: themes +};