Files
Homepage/js/themes.js

173 lines
4.3 KiB
JavaScript

/**
* 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
};