mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-03 11:07:51 +02:00
141 lines
4.4 KiB
JavaScript
141 lines
4.4 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
const STORAGE_KEY = 'cyberstrike-theme';
|
|
const THEMES = ['system', 'light', 'dark'];
|
|
const FALLBACK_LABELS = {
|
|
system: '跟随系统',
|
|
light: '浅色',
|
|
dark: '暗色'
|
|
};
|
|
const FALLBACK_TITLES = {
|
|
system: '当前:跟随系统主题。点击切换为浅色。',
|
|
light: '当前:浅色主题。点击切换为暗色。',
|
|
dark: '当前:暗色主题。点击切换为跟随系统。'
|
|
};
|
|
const TITLE_KEYS = {
|
|
system: 'titleSystem',
|
|
light: 'titleLight',
|
|
dark: 'titleDark'
|
|
};
|
|
|
|
const media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
|
|
function themeText(key, fallback) {
|
|
if (typeof window.t === 'function') {
|
|
const value = window.t('theme.' + key);
|
|
if (value && value !== 'theme.' + key) {
|
|
return value;
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
function getLabel(preference) {
|
|
return themeText(preference, FALLBACK_LABELS[preference] || FALLBACK_LABELS.system);
|
|
}
|
|
|
|
function getTitle(preference) {
|
|
const titleKey = TITLE_KEYS[preference] || TITLE_KEYS.system;
|
|
return themeText(titleKey, FALLBACK_TITLES[preference] || FALLBACK_TITLES.system);
|
|
}
|
|
|
|
function normalizePreference(value) {
|
|
return THEMES.includes(value) ? value : 'system';
|
|
}
|
|
|
|
function readPreference() {
|
|
try {
|
|
return normalizePreference(localStorage.getItem(STORAGE_KEY));
|
|
} catch (err) {
|
|
return 'system';
|
|
}
|
|
}
|
|
|
|
function resolveTheme(preference) {
|
|
if (preference === 'dark' || preference === 'light') {
|
|
return preference;
|
|
}
|
|
return media && media.matches ? 'dark' : 'light';
|
|
}
|
|
|
|
function updateButton(preference, resolved) {
|
|
const btn = document.getElementById('theme-toggle-btn');
|
|
const label = document.getElementById('theme-toggle-label');
|
|
if (!btn) {
|
|
return;
|
|
}
|
|
btn.dataset.themePreference = preference;
|
|
btn.dataset.theme = resolved;
|
|
const title = getTitle(preference);
|
|
btn.title = title;
|
|
btn.setAttribute('aria-label', title);
|
|
if (label) {
|
|
label.textContent = getLabel(preference);
|
|
}
|
|
}
|
|
|
|
function applyTheme(preference) {
|
|
const normalized = normalizePreference(preference);
|
|
const resolved = resolveTheme(normalized);
|
|
const root = document.documentElement;
|
|
root.setAttribute('data-theme-preference', normalized);
|
|
root.setAttribute('data-theme', resolved);
|
|
root.style.colorScheme = resolved;
|
|
updateButton(normalized, resolved);
|
|
}
|
|
|
|
function savePreference(preference) {
|
|
const normalized = normalizePreference(preference);
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, normalized);
|
|
} catch (err) {
|
|
// Ignore storage failures; the current page can still apply the theme.
|
|
}
|
|
applyTheme(normalized);
|
|
}
|
|
|
|
window.setThemePreference = savePreference;
|
|
window.getThemePreference = readPreference;
|
|
window.cycleThemePreference = function () {
|
|
const current = readPreference();
|
|
const next = THEMES[(THEMES.indexOf(current) + 1) % THEMES.length];
|
|
savePreference(next);
|
|
};
|
|
window.refreshThemeToggleLabel = function () {
|
|
applyTheme(readPreference());
|
|
};
|
|
|
|
if (media) {
|
|
const onSystemThemeChange = function () {
|
|
if (readPreference() === 'system') {
|
|
applyTheme('system');
|
|
}
|
|
};
|
|
if (typeof media.addEventListener === 'function') {
|
|
media.addEventListener('change', onSystemThemeChange);
|
|
} else if (typeof media.addListener === 'function') {
|
|
media.addListener(onSystemThemeChange);
|
|
}
|
|
}
|
|
|
|
document.addEventListener('languagechange', function () {
|
|
applyTheme(readPreference());
|
|
});
|
|
|
|
function initTheme() {
|
|
applyTheme(readPreference());
|
|
if (window.i18nReady && typeof window.i18nReady.then === 'function') {
|
|
window.i18nReady.then(function () {
|
|
applyTheme(readPreference());
|
|
});
|
|
}
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initTheme);
|
|
} else {
|
|
initTheme();
|
|
}
|
|
})();
|