/** * WP Bootstrap Dark Mode Toggle * * Handles dark mode switching using Bootstrap 5.3's data-bs-theme attribute. * Respects prefers-color-scheme media query and persists choice in localStorage. * * @package WPBootstrap * @since 0.1.0 */ (function () { 'use strict'; var STORAGE_KEY = 'wp-bootstrap-theme'; var ATTR = 'data-bs-theme'; /** * Get the user's stored preference, or fall back to system preference. * * @return {string} 'dark' or 'light' */ function getPreferredTheme() { var stored = localStorage.getItem(STORAGE_KEY); if (stored) { return stored; } return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } /** * Apply the theme to the document and update all toggle buttons. * * @param {string} theme - 'dark' or 'light' */ function setTheme(theme) { document.documentElement.setAttribute(ATTR, theme); document.querySelectorAll('[data-bs-theme-toggle]').forEach(function (toggle) { var isDark = theme === 'dark'; toggle.setAttribute('aria-label', isDark ? (toggle.dataset.labelLight || 'Switch to light mode') : (toggle.dataset.labelDark || 'Switch to dark mode')); toggle.setAttribute('aria-pressed', String(isDark)); var sunIcon = toggle.querySelector('.wp-bootstrap-sun-icon'); var moonIcon = toggle.querySelector('.wp-bootstrap-moon-icon'); if (sunIcon) sunIcon.style.display = isDark ? 'inline-block' : 'none'; if (moonIcon) moonIcon.style.display = isDark ? 'none' : 'inline-block'; }); } // Apply theme immediately to prevent flash. setTheme(getPreferredTheme()); // When DOM is ready, re-apply for toggle buttons and attach event listeners. document.addEventListener('DOMContentLoaded', function () { setTheme(getPreferredTheme()); document.querySelectorAll('[data-bs-theme-toggle]').forEach(function (toggle) { toggle.addEventListener('click', function () { var currentTheme = document.documentElement.getAttribute(ATTR); var newTheme = currentTheme === 'dark' ? 'light' : 'dark'; localStorage.setItem(STORAGE_KEY, newTheme); setTheme(newTheme); announceTheme(newTheme); }); }); }); // Listen for system preference changes when no stored preference exists. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) { if (!localStorage.getItem(STORAGE_KEY)) { setTheme(e.matches ? 'dark' : 'light'); } }); /** * Announce theme change to screen readers via a live region. * * @param {string} theme - 'dark' or 'light' */ function announceTheme(theme) { var msg = theme === 'dark' ? 'Dark mode enabled' : 'Light mode enabled'; var el = document.getElementById('wp-bootstrap-theme-status'); if (!el) { el = document.createElement('div'); el.id = 'wp-bootstrap-theme-status'; el.setAttribute('role', 'status'); el.setAttribute('aria-live', 'polite'); el.className = 'visually-hidden'; document.body.appendChild(el); } el.textContent = msg; } })();