UniformFlow/public/js/theme.js

41 lines
1.8 KiB
JavaScript

(() => {
const root = document.documentElement;
const preferredTheme = () => localStorage.getItem('uniformflow-theme')
|| (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
const applyTheme = theme => {
root.dataset.theme = theme;
localStorage.setItem('uniformflow-theme', theme);
document.querySelectorAll('[data-theme-toggle]').forEach(button => {
const nextTheme = theme === 'dark' ? 'light' : 'dark';
button.setAttribute('aria-label', `Switch to ${nextTheme} theme`);
button.setAttribute('title', `Switch to ${nextTheme} theme`);
button.setAttribute('aria-pressed', theme === 'dark' ? 'true' : 'false');
});
};
applyTheme(root.dataset.theme || preferredTheme());
document.addEventListener('DOMContentLoaded', () => {
applyTheme(root.dataset.theme || preferredTheme());
document.querySelectorAll('[data-theme-toggle]').forEach(button => button.addEventListener('click', () => {
const nextTheme = root.dataset.theme === 'dark' ? 'light' : 'dark';
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reducedMotion) {
applyTheme(nextTheme);
return;
}
root.classList.add('theme-changing');
if (document.startViewTransition) {
document.startViewTransition(() => applyTheme(nextTheme)).finished.finally(() => {
window.setTimeout(() => root.classList.remove('theme-changing'), 120);
});
} else {
requestAnimationFrame(() => applyTheme(nextTheme));
window.setTimeout(() => root.classList.remove('theme-changing'), 420);
}
}));
});
})();