/** * Theme Manager * Handles user theme preferences and theme switching */ class ThemeManager { constructor() { this.storageKey = 'gooner-theme-preference'; this.defaultTheme = 'electric-blue'; this.availableThemes = [ { id: 'electric-blue', name: 'Electric Blue', emoji: '⚡' }, { id: 'electric-violet', name: 'Electric Violet', emoji: '💜' }, { id: 'magenta-dream', name: 'Magenta Dream', emoji: '💖' }, { id: 'hot-pink-fury', name: 'Hot Pink Fury', emoji: '🔥' }, { id: 'purple-neon-dream', name: 'Purple Neon Dream', emoji: '🌈' }, { id: 'crimson-passion', name: 'Crimson Passion', emoji: '❤️' }, { id: 'golden-ember', name: 'Golden Ember', emoji: '✨' }, { id: 'aqua-mist', name: 'Aqua Mist', emoji: '🌊' }, { id: 'coral-blaze', name: 'Coral Blaze', emoji: '🔴' } ]; this.init(); } /** * Initialize theme system */ init() { // Load saved theme or use default const savedTheme = this.getSavedTheme(); this.applyTheme(savedTheme); console.log(`🎨 Theme Manager initialized with theme: ${savedTheme}`); } /** * Get saved theme from localStorage * @returns {string} Theme ID */ getSavedTheme() { try { const saved = localStorage.getItem(this.storageKey); return saved && this.isValidTheme(saved) ? saved : this.defaultTheme; } catch (error) { console.warn('Failed to load theme preference:', error); return this.defaultTheme; } } /** * Save theme preference to localStorage * @param {string} themeId - Theme ID to save */ saveTheme(themeId) { try { localStorage.setItem(this.storageKey, themeId); console.log(`💾 Theme saved: ${themeId}`); } catch (error) { console.error('Failed to save theme preference:', error); } } /** * Check if theme ID is valid * @param {string} themeId - Theme ID to validate * @returns {boolean} */ isValidTheme(themeId) { return this.availableThemes.some(theme => theme.id === themeId); } /** * Apply theme to document * @param {string} themeId - Theme ID to apply */ applyTheme(themeId) { if (!this.isValidTheme(themeId)) { console.warn(`Invalid theme ID: ${themeId}, using default`); themeId = this.defaultTheme; } // Set data-theme attribute on root element document.documentElement.setAttribute('data-theme', themeId); // Save preference this.saveTheme(themeId); // Dispatch custom event for other components to react const event = new CustomEvent('themeChanged', { detail: { themeId, themeName: this.getThemeName(themeId) } }); window.dispatchEvent(event); console.log(`✨ Theme applied: ${themeId}`); } /** * Get current active theme * @returns {string} Current theme ID */ getCurrentTheme() { return document.documentElement.getAttribute('data-theme') || this.defaultTheme; } /** * Get theme name by ID * @param {string} themeId - Theme ID * @returns {string} Theme display name */ getThemeName(themeId) { const theme = this.availableThemes.find(t => t.id === themeId); return theme ? theme.name : 'Unknown'; } /** * Get all available themes * @returns {Array} Array of theme objects */ getAvailableThemes() { return this.availableThemes; } /** * Switch to next theme in the list */ nextTheme() { const current = this.getCurrentTheme(); const currentIndex = this.availableThemes.findIndex(t => t.id === current); const nextIndex = (currentIndex + 1) % this.availableThemes.length; const nextTheme = this.availableThemes[nextIndex]; this.applyTheme(nextTheme.id); return nextTheme; } /** * Switch to previous theme in the list */ previousTheme() { const current = this.getCurrentTheme(); const currentIndex = this.availableThemes.findIndex(t => t.id === current); const prevIndex = currentIndex === 0 ? this.availableThemes.length - 1 : currentIndex - 1; const prevTheme = this.availableThemes[prevIndex]; this.applyTheme(prevTheme.id); return prevTheme; } /** * Create theme selector UI element * @returns {HTMLElement} Theme selector dropdown */ createThemeSelector() { const container = document.createElement('div'); container.className = 'theme-selector'; container.innerHTML = ` `; const select = container.querySelector('#theme-select'); select.addEventListener('change', (e) => { this.applyTheme(e.target.value); }); // Update selector when theme changes externally window.addEventListener('themeChanged', (e) => { select.value = e.detail.themeId; }); return container; } /** * Create compact theme toggle buttons * @returns {HTMLElement} Theme toggle buttons */ createThemeToggle() { const container = document.createElement('div'); container.className = 'theme-toggle'; container.innerHTML = ` 🎨 `; const updateLabel = () => { const current = this.availableThemes.find(t => t.id === this.getCurrentTheme()); container.querySelector('#theme-label').textContent = current ? current.emoji : '🎨'; }; container.querySelector('.theme-prev').addEventListener('click', () => { this.previousTheme(); updateLabel(); }); container.querySelector('.theme-next').addEventListener('click', () => { this.nextTheme(); updateLabel(); }); window.addEventListener('themeChanged', updateLabel); updateLabel(); return container; } } // Create global instance window.themeManager = new ThemeManager();