Files
gemini-banlancer/frontend/js/components/themeManager.js
2025-11-20 12:24:05 +08:00

106 lines
3.5 KiB
JavaScript

// Filename: frontend/js/components/themeManager.js
/**
* 负责管理应用程序的三态主题(系统、亮色、暗色)。
* 封装了所有与主题切换相关的 DOM 操作、事件监听和 localStorage 交互。
*/
export const themeManager = {
// 用于存储图标的 SVG HTML
icons: {},
init: function() {
this.html = document.documentElement;
this.buttons = document.querySelectorAll('.theme-btn');
this.cyclerBtn = document.getElementById('theme-cycler-btn');
this.cyclerIconContainer = document.getElementById('theme-cycler-icon');
if (!this.html || this.buttons.length === 0 || !this.cyclerBtn || !this.cyclerIconContainer) {
console.warn("ThemeManager init failed: one or more required elements not found.");
return;
}
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
// 初始化时,从三按钮组中提取 SVG 并存储起来
this.storeIcons();
// 绑定宽屏按钮组的点击事件
this.buttons.forEach(btn => {
btn.addEventListener('click', () => this.setTheme(btn.dataset.theme));
});
// 绑定移动端循环按钮的点击事件
this.cyclerBtn.addEventListener('click', () => this.cycleTheme());
this.mediaQuery.addEventListener('change', () => this.applyTheme());
this.applyTheme();
},
// 从现有按钮中提取并存储 SVG 图标
storeIcons: function() {
this.buttons.forEach(btn => {
const theme = btn.dataset.theme;
const svg = btn.querySelector('svg');
if (theme && svg) {
this.icons[theme] = svg.outerHTML;
}
});
},
// 循环切换主题的核心逻辑
cycleTheme: function() {
const themes = ['system', 'light', 'dark'];
const currentTheme = this.getTheme();
const currentIndex = themes.indexOf(currentTheme);
const nextIndex = (currentIndex + 1) % themes.length; // brilliantly simple cycling logic
this.setTheme(themes[nextIndex]);
},
applyTheme: function() {
let theme = this.getTheme();
if (theme === 'system') {
theme = this.mediaQuery.matches ? 'dark' : 'light';
}
if (theme === 'dark') {
this.html.classList.add('dark');
} else {
this.html.classList.remove('dark');
}
this.updateButtons();
this.updateCyclerIcon();
},
setTheme: function(theme) {
localStorage.setItem('theme', theme);
this.applyTheme();
},
getTheme: function() {
return localStorage.getItem('theme') || 'system';
},
updateButtons: function() {
const currentTheme = this.getTheme();
this.buttons.forEach(btn => {
if (btn.dataset.theme === currentTheme) {
btn.classList.add('bg-white', 'dark:bg-zinc-700');
} else {
btn.classList.remove('bg-white', 'dark:bg-zinc-700');
}
});
},
// 更新移动端循环按钮的图标
updateCyclerIcon: function() {
if (this.cyclerIconContainer) {
const currentTheme = this.getTheme();
// 从我们存储的 icons 对象中找到对应的 SVG 并注入
if (this.icons[currentTheme]) {
this.cyclerIconContainer.innerHTML = this.icons[currentTheme];
}
}
}
};