Add third theme mode (system) that follows OS prefers-color-scheme. Theme button cycles dark → light → system with monitor icon. Listens for OS preference changes in real time when in system mode. Fix showToast clearing previous timer so rapid calls don't cause the toast to disappear early.
This commit is contained in:
@@ -279,30 +279,54 @@
|
||||
if (btn) btn.style.opacity = state === 'on' ? '1' : '0.5';
|
||||
}
|
||||
|
||||
// Initialize theme
|
||||
const savedTheme = localStorage.getItem('theme') || 'dark';
|
||||
document.documentElement.setAttribute('data-theme', savedTheme);
|
||||
updateThemeIcon(savedTheme);
|
||||
// Initialize theme (preference can be 'dark', 'light', or 'system')
|
||||
const _systemDarkMq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
function updateThemeIcon(theme) {
|
||||
function _resolveTheme(pref) {
|
||||
if (pref === 'system') return _systemDarkMq.matches ? 'dark' : 'light';
|
||||
return pref;
|
||||
}
|
||||
|
||||
function _applyTheme(resolved) {
|
||||
document.documentElement.setAttribute('data-theme', resolved);
|
||||
if (window._updateBgAnimTheme) window._updateBgAnimTheme(resolved === 'dark');
|
||||
const accent = localStorage.getItem('accentColor');
|
||||
if (accent) applyAccentColor(accent, true);
|
||||
}
|
||||
|
||||
const _themePref = localStorage.getItem('theme') || 'dark';
|
||||
_applyTheme(_resolveTheme(_themePref));
|
||||
updateThemeIcon(_themePref);
|
||||
|
||||
// Listen for OS preference changes when in system mode
|
||||
_systemDarkMq.addEventListener('change', function() {
|
||||
if (localStorage.getItem('theme') === 'system') {
|
||||
_applyTheme(_resolveTheme('system'));
|
||||
}
|
||||
});
|
||||
|
||||
function updateThemeIcon(pref) {
|
||||
const icon = document.getElementById('theme-icon');
|
||||
icon.innerHTML = theme === 'dark'
|
||||
? '<svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>'
|
||||
: '<svg class="icon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>';
|
||||
if (pref === 'system') {
|
||||
icon.innerHTML = '<svg class="icon" viewBox="0 0 24 24"><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></svg>';
|
||||
} else if (pref === 'dark') {
|
||||
icon.innerHTML = '<svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>';
|
||||
} else {
|
||||
icon.innerHTML = '<svg class="icon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>';
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
const current = localStorage.getItem('theme') || 'dark';
|
||||
const order = ['dark', 'light', 'system'];
|
||||
const next = order[(order.indexOf(current) + 1) % order.length];
|
||||
const resolved = _resolveTheme(next);
|
||||
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
updateThemeIcon(newTheme);
|
||||
if (window._updateBgAnimTheme) window._updateBgAnimTheme(newTheme === 'dark');
|
||||
// Re-derive accent text variant for the new theme
|
||||
const accent = localStorage.getItem('accentColor');
|
||||
if (accent) applyAccentColor(accent, true);
|
||||
showToast(window.t ? t(newTheme === 'dark' ? 'theme.switched.dark' : 'theme.switched.light') : `Switched to ${newTheme} theme`, 'info');
|
||||
localStorage.setItem('theme', next);
|
||||
_applyTheme(resolved);
|
||||
updateThemeIcon(next);
|
||||
const toastKeys = { dark: 'theme.switched.dark', light: 'theme.switched.light', system: 'theme.switched.system' };
|
||||
showToast(window.t ? t(toastKeys[next]) : `Switched to ${next} theme`, 'info');
|
||||
}
|
||||
|
||||
// Initialize accent color
|
||||
|
||||
Reference in New Issue
Block a user