feat: Add comprehensive light theme and theme switcher
✨ Features: - Complete light theme with improved color palette - Theme switcher in header with sun/moon icons - Theme persistence using localStorage - Smooth transitions between themes 🎨 Theme Improvements: - Softer, easier-on-eyes light theme colors - Fixed text contrast issues across all components - Enhanced member card and tab text readability - Fixed hover effects that made text disappear - Improved member overlay header and body styling 🔧 Technical Implementation: - CSS variables system for easy theme management - JavaScript ThemeManager class for theme switching - Responsive design for mobile devices - Comprehensive hover state fixes - Z-index solutions for text visibility 📱 Components Fixed: - Member cards (hostname, IP, latency, details) - Navigation tabs and content - Task summaries and progress items - Capability forms and API endpoints - Member overlay popup - Form inputs and dropdowns - Status indicators and label chips 🎯 Accessibility: - WCAG AA contrast compliance - Proper color hierarchy - Clear visual feedback - Mobile-responsive design Files added: - public/styles/theme.css - Theme system and variables - public/scripts/theme-manager.js - Theme management logic - THEME_README.md - Comprehensive documentation - THEME_IMPROVEMENTS.md - Improvement details Files modified: - public/index.html - Added theme switcher and script includes - public/styles/main.css - Updated to use CSS variables
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SPORE UI</title>
|
||||
<link rel="stylesheet" href="styles/main.css">
|
||||
<link rel="stylesheet" href="styles/theme.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -22,6 +23,15 @@
|
||||
<button class="nav-tab" data-view="firmware">📦 Firmware</button>
|
||||
</div>
|
||||
<div class="nav-right">
|
||||
<div class="theme-switcher">
|
||||
<span class="theme-label">Theme:</span>
|
||||
<button class="theme-toggle" id="theme-toggle" title="Toggle theme">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="cluster-status">🚀 Cluster Online</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,6 +157,7 @@
|
||||
<script src="./scripts/components/ClusterStatusComponent.js"></script>
|
||||
<script src="./scripts/components/TopologyGraphComponent.js"></script>
|
||||
<script src="./scripts/components/ComponentsLoader.js"></script>
|
||||
<script src="./scripts/theme-manager.js"></script>
|
||||
<script src="./scripts/app.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
120
public/scripts/theme-manager.js
Normal file
120
public/scripts/theme-manager.js
Normal file
@@ -0,0 +1,120 @@
|
||||
// Theme Manager - Handles theme switching and persistence
|
||||
|
||||
class ThemeManager {
|
||||
constructor() {
|
||||
this.currentTheme = this.getStoredTheme() || 'dark';
|
||||
this.themeToggle = document.getElementById('theme-toggle');
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Apply stored theme on page load
|
||||
this.applyTheme(this.currentTheme);
|
||||
|
||||
// Set up event listener for theme toggle
|
||||
if (this.themeToggle) {
|
||||
this.themeToggle.addEventListener('click', () => this.toggleTheme());
|
||||
}
|
||||
|
||||
// Listen for system theme changes
|
||||
if (window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
mediaQuery.addListener((e) => {
|
||||
if (this.getStoredTheme() === 'system') {
|
||||
this.applyTheme(e.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getStoredTheme() {
|
||||
try {
|
||||
return localStorage.getItem('spore-ui-theme');
|
||||
} catch (e) {
|
||||
console.warn('Could not access localStorage for theme preference');
|
||||
return 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
setStoredTheme(theme) {
|
||||
try {
|
||||
localStorage.setItem('spore-ui-theme', theme);
|
||||
} catch (e) {
|
||||
console.warn('Could not save theme preference to localStorage');
|
||||
}
|
||||
}
|
||||
|
||||
applyTheme(theme) {
|
||||
// Update data attribute on html element
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
|
||||
// Update theme toggle icon
|
||||
this.updateThemeIcon(theme);
|
||||
|
||||
// Store the theme preference
|
||||
this.setStoredTheme(theme);
|
||||
|
||||
this.currentTheme = theme;
|
||||
|
||||
// Dispatch custom event for other components
|
||||
window.dispatchEvent(new CustomEvent('themeChanged', {
|
||||
detail: { theme: theme }
|
||||
}));
|
||||
}
|
||||
|
||||
updateThemeIcon(theme) {
|
||||
if (!this.themeToggle) return;
|
||||
|
||||
const svg = this.themeToggle.querySelector('svg');
|
||||
if (!svg) return;
|
||||
|
||||
// Update the SVG content based on theme
|
||||
if (theme === 'light') {
|
||||
// Sun icon for light theme
|
||||
svg.innerHTML = `
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
`;
|
||||
} else {
|
||||
// Moon icon for dark theme
|
||||
svg.innerHTML = `
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
toggleTheme() {
|
||||
const newTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
|
||||
this.applyTheme(newTheme);
|
||||
|
||||
// Add a subtle animation to the toggle button
|
||||
if (this.themeToggle) {
|
||||
this.themeToggle.style.transform = 'scale(0.9)';
|
||||
setTimeout(() => {
|
||||
this.themeToggle.style.transform = 'scale(1)';
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// Method to get current theme (useful for other components)
|
||||
getCurrentTheme() {
|
||||
return this.currentTheme;
|
||||
}
|
||||
|
||||
// Method to set theme programmatically
|
||||
setTheme(theme) {
|
||||
if (['dark', 'light'].includes(theme)) {
|
||||
this.applyTheme(theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize theme manager when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
window.themeManager = new ThemeManager();
|
||||
});
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = ThemeManager;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
3463
public/styles/main.css.backup
Normal file
3463
public/styles/main.css.backup
Normal file
File diff suppressed because it is too large
Load Diff
1106
public/styles/theme.css
Normal file
1106
public/styles/theme.css
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user