qbit_manage/web-ui/js/utils/theme-manager.js
bobokun 3fa5fcee3b
v4.5.0 (#862)
# Requirements Updated
- fastapi==0.116.0
- retrying==1.4.0
- uvicorn==0.35.0

# New Features
- **Web UI**: Introduced a new Web UI for configuring and managing qBit
Manage.
  - Visual Configuration Editor for YAML files.
  - Command Execution directly from the UI.
  - Undo/Redo History for changes.
  - Theme Support (light/dark mode).
  - Responsive Design for desktop and mobile.
  - Real-time YAML Preview.
- Pass skip qbitorrent check as optional parameter to the API (Adds
#860)\


**Full Changelog**:
https://github.com/StuffAnThings/qbit_manage/compare/v4.4.0...v4.5.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ineednewpajamas <73252768+ineednewpajamas@users.noreply.github.com>
2025-07-11 19:13:41 -04:00

114 lines
2.8 KiB
JavaScript

/**
* Theme Manager - Handles dark/light theme switching
*/
class ThemeManager {
constructor() {
this.currentTheme = this.getStoredTheme() || 'light';
this.init();
}
init() {
// Apply the current theme
this.applyTheme(this.currentTheme);
// Set up theme toggle button
this.setupThemeToggle();
// Listen for system theme changes
this.setupSystemThemeListener();
}
getSystemTheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
getStoredTheme() {
return localStorage.getItem('qbit-manage-theme');
}
storeTheme(theme) {
localStorage.setItem('qbit-manage-theme', theme);
}
applyTheme(theme) {
const root = document.documentElement;
// Remove existing theme attributes
root.removeAttribute('data-theme');
if (theme === 'dark') {
root.setAttribute('data-theme', 'dark');
} else if (theme === 'light') {
root.setAttribute('data-theme', 'light');
}
// If theme is 'auto' or not set, let CSS handle it via prefers-color-scheme
this.currentTheme = theme;
this.updateThemeToggleIcon();
}
toggleTheme() {
const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
this.applyTheme(newTheme);
this.storeTheme(newTheme);
}
setupThemeToggle() {
const themeToggle = document.getElementById('theme-toggle');
if (themeToggle) {
themeToggle.addEventListener('click', () => {
this.toggleTheme();
});
}
}
updateThemeToggleIcon() {
const themeToggle = document.getElementById('theme-toggle');
if (!themeToggle) return;
const sunIcon = themeToggle.querySelector('.icon-sun');
const moonIcon = themeToggle.querySelector('.icon-moon');
if (!sunIcon || !moonIcon) return;
// Update title based on current theme
const title = this.currentTheme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode';
themeToggle.setAttribute('title', title);
// The CSS handles showing/hiding icons based on data-theme attribute
// No need to manually toggle visibility here
}
setupSystemThemeListener() {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', () => {
// Only react to system changes if we're in auto mode
if (!this.getStoredTheme()) {
this.updateThemeToggleIcon();
}
});
}
// Public API
setTheme(theme) {
if (['light', 'dark'].includes(theme)) {
this.applyTheme(theme);
this.storeTheme(theme);
}
}
getCurrentTheme() {
return this.currentTheme;
}
getEffectiveTheme() {
return this.currentTheme;
}
}
// Create and export theme manager instance
export const themeManager = new ThemeManager();
// Also export the class for potential custom usage
export { ThemeManager };