1/* 2 * Dark-mode switch for the restored Chronicles site. 3 * 4 * Added during restoration; not part of the original theme. 5 * 6 * Behaviour: 7 * - With no stored choice, the system setting decides, and the page follows 8 * it live if the visitor changes it. 9 * - Clicking the switch stores an explicit choice, which then wins over the 10 * system setting until it is cleared. 11 * 12 * The attribute itself is set by a small inline script in <head>, so the theme 13 * is correct before first paint. This file only draws the control and keeps it 14 * in sync. 15 */ 16(function () { 17 "use strict"; 18 19 var KEY = "chronicles-theme"; 20 var root = document.documentElement; 21 22 var SUN = 23 '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4.2"/>' + 24 '<path d="M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2' + 25 'M5.4 5.4l1.6 1.6M17 17l1.6 1.6M18.6 5.4L17 7M7 17l-1.6 1.6"/></svg>'; 26 27 var MOON = 28 '<svg viewBox="0 0 24 24" aria-hidden="true">' + 29 '<path d="M20.5 14.2A8.4 8.4 0 1 1 9.8 3.5a6.6 6.6 0 0 0 10.7 10.7z"/></svg>'; 30 31 function stored() { 32 try { 33 var v = localStorage.getItem(KEY); 34 return v === "dark" || v === "light" ? v : null; 35 } catch (e) { 36 return null; // private mode, or storage disabled 37 } 38 } 39 40 function systemPrefersDark() { 41 return ( 42 window.matchMedia && 43 window.matchMedia("(prefers-color-scheme: dark)").matches 44 ); 45 } 46 47 function current() { 48 return root.getAttribute("data-theme") === "dark" ? "dark" : "light"; 49 } 50 51 function apply(theme) { 52 root.setAttribute("data-theme", theme); 53 render(theme); 54 } 55 56 var button = null; 57 58 function render(theme) { 59 if (!button) return; 60 var dark = theme === "dark"; 61 // Label what the click will do, not what is showing. 62 var label = dark ? "ÐклÑÑиÑÑ ÑвеÑлÑÑ ÑемÑ" : "ÐклÑÑиÑÑ ÑÑмнÑÑ ÑемÑ"; 63 button.innerHTML = dark ? SUN : MOON; 64 button.setAttribute("aria-label", label); 65 button.setAttribute("title", label); 66 button.setAttribute("aria-pressed", dark ? "true" : "false"); 67 } 68 69 function build() { 70 button = document.createElement("button"); 71 button.id = "theme-toggle"; 72 button.type = "button"; 73 button.addEventListener("click", function () { 74 var next = current() === "dark" ? "light" : "dark"; 75 try { 76 localStorage.setItem(KEY, next); 77 } catch (e) { 78 /* choice simply will not persist */ 79 } 80 apply(next); 81 }); 82 document.body.appendChild(button); 83 render(current()); 84 } 85 86 // Follow the system setting for as long as no explicit choice is stored. 87 if (window.matchMedia) { 88 var mq = window.matchMedia("(prefers-color-scheme: dark)"); 89 var onChange = function (e) { 90 if (!stored()) apply(e.matches ? "dark" : "light"); 91 }; 92 if (mq.addEventListener) mq.addEventListener("change", onChange); 93 else if (mq.addListener) mq.addListener(onChange); // older browsers 94 } 95 96 if (document.readyState === "loading") { 97 document.addEventListener("DOMContentLoaded", build); 98 } else { 99 build(); 100 } 101 102 // Exposed so the stored choice can be cleared from the console: 103 // chroniclesTheme.reset() 104 window.chroniclesTheme = { 105 reset: function () { 106 try { 107 localStorage.removeItem(KEY); 108 } catch (e) {} 109 apply(systemPrefersDark() ? "dark" : "light"); 110 } 111 }; 112})();
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.