1/** 2 * Theme Toggle - Dark/Light Mode Support 3 * RAI Theme - Responsible AI Initiative 4 * 5 * Handles theme switching with: 6 * - localStorage persistence 7 * - System preference detection 8 * - Smooth transitions 9 * - Button icon updates 10 */ 11 12(function() { 13 'use strict'; 14 15 const STORAGE_KEY = 'rai-theme'; 16 const DARK_CLASS = 'dark'; 17 18 /** 19 * Get the current theme preference 20 * Priority: localStorage > system preference > light (default) 21 */ 22 function getThemePreference() { 23 const stored = localStorage.getItem(STORAGE_KEY); 24 if (stored) { 25 return stored; 26 } 27 28 // Check system preference 29 if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { 30 return 'dark'; 31 } 32 33 return 'light'; 34 } 35 36 /** 37 * Apply the theme to the document 38 */ 39 function applyTheme(theme) { 40 const html = document.documentElement; 41 42 if (theme === 'dark') { 43 html.classList.add(DARK_CLASS); 44 } else { 45 html.classList.remove(DARK_CLASS); 46 } 47 48 // Update all toggle buttons 49 updateToggleButtons(theme); 50 } 51 52 /** 53 * Update all theme toggle button icons 54 */ 55 function updateToggleButtons(theme) { 56 const buttons = document.querySelectorAll('[data-theme-toggle]'); 57 58 buttons.forEach(button => { 59 const moonIcon = button.querySelector('.theme-icon-moon'); 60 const sunIcon = button.querySelector('.theme-icon-sun'); 61 62 if (moonIcon && sunIcon) { 63 if (theme === 'dark') { 64 moonIcon.classList.add('hidden'); 65 sunIcon.classList.remove('hidden'); 66 } else { 67 moonIcon.classList.remove('hidden'); 68 sunIcon.classList.add('hidden'); 69 } 70 } 71 }); 72 } 73 74 /** 75 * Toggle between light and dark themes 76 */ 77 function toggleTheme() { 78 const html = document.documentElement; 79 const isDark = html.classList.contains(DARK_CLASS); 80 const newTheme = isDark ? 'light' : 'dark'; 81 82 localStorage.setItem(STORAGE_KEY, newTheme); 83 applyTheme(newTheme); 84 } 85 86 /** 87 * Set a specific theme 88 */ 89 function setTheme(theme) { 90 localStorage.setItem(STORAGE_KEY, theme); 91 applyTheme(theme); 92 } 93 94 /** 95 * Initialize theme on page load 96 */ 97 function init() { 98 // Apply theme immediately to prevent flash 99 const theme = getThemePreference(); 100 applyTheme(theme); 101 102 // Listen for system preference changes 103 if (window.matchMedia) { 104 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { 105 // Only auto-switch if user hasn't set a preference 106 if (!localStorage.getItem(STORAGE_KEY)) { 107 applyTheme(e.matches ? 'dark' : 'light'); 108 } 109 }); 110 } 111 112 // Set up toggle button click handlers 113 document.addEventListener('click', (e) => { 114 const toggleButton = e.target.closest('[data-theme-toggle]'); 115 if (toggleButton) { 116 e.preventDefault(); 117 toggleTheme(); 118 } 119 }); 120 } 121 122 // Apply theme immediately (before DOMContentLoaded) to prevent flash 123 const initialTheme = getThemePreference(); 124 document.documentElement.classList.toggle(DARK_CLASS, initialTheme === 'dark'); 125 126 // Initialize when DOM is ready 127 if (document.readyState === 'loading') { 128 document.addEventListener('DOMContentLoaded', init); 129 } else { 130 init(); 131 } 132 133 // Expose functions globally for external use 134 window.RAITheme = { 135 toggle: toggleTheme, 136 set: setTheme, 137 get: getThemePreference 138 }; 139})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.