theme.js (1737B)
1 // Run before styles/paint, independently of playground/compiler initialization. 2 (() => { 3 const key = 'arboricx-theme'; 4 const system = matchMedia('(prefers-color-scheme: dark)'); 5 const root = document.documentElement; 6 let preference; 7 try { preference = localStorage.getItem(key); } catch { /* Storage may be blocked. */ } 8 if (preference !== 'light' && preference !== 'dark') preference = null; 9 function apply() { 10 const dark = (preference || (system.matches ? 'dark' : 'light')) === 'dark'; 11 root.dataset.theme = dark ? 'dark' : 'light'; 12 for (const meta of document.querySelectorAll('meta[name="theme-color"]')) { 13 meta.content = dark ? '#141e1a' : '#f5f2ea'; 14 } 15 const button = document.getElementById('theme-toggle'); 16 if (button) { 17 button.hidden = false; 18 document.getElementById('theme-separator').hidden = false; 19 button.setAttribute('aria-label', dark ? 'Switch to light mode' : 'Switch to dark mode'); 20 button.title = button.getAttribute('aria-label'); 21 button.querySelector('[data-theme-icon]').textContent = dark ? '☀' : '☾'; 22 } 23 } 24 apply(); 25 system.addEventListener('change', apply); 26 window.addEventListener('storage', event => { 27 if (event.key !== key && event.key !== null) return; 28 preference = event.newValue === 'light' || event.newValue === 'dark' ? event.newValue : null; 29 apply(); 30 }); 31 document.addEventListener('DOMContentLoaded', () => { 32 apply(); 33 document.getElementById('theme-toggle').addEventListener('click', () => { 34 preference = root.dataset.theme === 'dark' ? 'light' : 'dark'; 35 try { localStorage.setItem(key, preference); } catch { /* Still works for this page. */ } 36 apply(); 37 }); 38 }); 39 })();