113 lines
3.2 KiB
JavaScript
113 lines
3.2 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
|
|
const STORAGE_KEY = 'rdoc-theme';
|
|
const THEME_LIGHT = 'light';
|
|
const THEME_DARK = 'dark';
|
|
|
|
/**
|
|
* Get the user's theme preference
|
|
* Priority: localStorage > system preference > light (default)
|
|
*/
|
|
function getThemePreference() {
|
|
// Check localStorage first
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored === THEME_LIGHT || stored === THEME_DARK) {
|
|
return stored;
|
|
}
|
|
|
|
// Check system preference
|
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
return THEME_DARK;
|
|
}
|
|
|
|
return THEME_LIGHT;
|
|
}
|
|
|
|
/**
|
|
* Apply theme to document
|
|
*/
|
|
function applyTheme(theme) {
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
|
|
// Update toggle button icon
|
|
const toggleBtn = document.getElementById('theme-toggle');
|
|
if (toggleBtn) {
|
|
const icon = toggleBtn.querySelector('.theme-toggle-icon');
|
|
if (icon) {
|
|
icon.textContent = theme === THEME_DARK ? '☀️' : '🌙';
|
|
}
|
|
toggleBtn.setAttribute('aria-label',
|
|
theme === THEME_DARK ? 'Switch to light mode' : 'Switch to dark mode'
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle between light and dark themes
|
|
*/
|
|
function toggleTheme() {
|
|
const currentTheme = document.documentElement.getAttribute('data-theme') || THEME_LIGHT;
|
|
const newTheme = currentTheme === THEME_LIGHT ? THEME_DARK : THEME_LIGHT;
|
|
applyTheme(newTheme);
|
|
|
|
// Announce to screen readers
|
|
announceThemeChange(newTheme);
|
|
}
|
|
|
|
/**
|
|
* Announce theme change to screen readers
|
|
*/
|
|
function announceThemeChange(theme) {
|
|
const announcement = document.createElement('div');
|
|
announcement.setAttribute('role', 'status');
|
|
announcement.setAttribute('aria-live', 'polite');
|
|
announcement.className = 'sr-only';
|
|
announcement.textContent = `Switched to ${theme} mode`;
|
|
document.body.appendChild(announcement);
|
|
|
|
// Remove after announcement
|
|
setTimeout(() => {
|
|
document.body.removeChild(announcement);
|
|
}, 1000);
|
|
}
|
|
|
|
/**
|
|
* Initialize theme on page load
|
|
*/
|
|
function initTheme() {
|
|
// Apply theme immediately to prevent flash
|
|
const theme = getThemePreference();
|
|
applyTheme(theme);
|
|
|
|
// Set up toggle button listener
|
|
const toggleBtn = document.getElementById('theme-toggle');
|
|
if (toggleBtn) {
|
|
toggleBtn.addEventListener('click', toggleTheme);
|
|
}
|
|
|
|
// Listen for system theme changes
|
|
if (window.matchMedia) {
|
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
|
// Only auto-switch if user hasn't manually set a preference
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (!stored) {
|
|
applyTheme(e.matches ? THEME_DARK : THEME_LIGHT);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Initialize immediately (before DOMContentLoaded to prevent flash)
|
|
if (document.readyState === 'loading') {
|
|
// Apply theme as early as possible
|
|
const theme = getThemePreference();
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
|
|
document.addEventListener('DOMContentLoaded', initTheme);
|
|
} else {
|
|
initTheme();
|
|
}
|
|
})();
|