/**
* 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();