1// Has to be in the head tag, otherwise a flicker effect will occur. 2 3// Toggle through light, dark, and system theme settings. 4let toggleThemeSetting = () => { 5 let themeSetting = determineThemeSetting(); 6 if (themeSetting == "system") { 7 setThemeSetting("light"); 8 } else if (themeSetting == "light") { 9 setThemeSetting("dark"); 10 } else { 11 setThemeSetting("system"); 12 } 13}; 14 15// Change the theme setting and apply the theme. 16let setThemeSetting = (themeSetting) => { 17 localStorage.setItem("theme", themeSetting); 18 19 document.documentElement.setAttribute("data-theme-setting", themeSetting); 20 21 applyTheme(); 22}; 23 24// Apply the computed dark or light theme to the website. 25let applyTheme = () => { 26 let theme = determineComputedTheme(); 27 28 transTheme(); 29 setHighlight(theme); 30 setGiscusTheme(theme); 31 setSearchTheme(theme); 32 33 // if mermaid is not defined, do nothing 34 if (typeof mermaid !== "undefined") { 35 setMermaidTheme(theme); 36 } 37 38 // if diff2html is not defined, do nothing 39 if (typeof Diff2HtmlUI !== "undefined") { 40 setDiff2htmlTheme(theme); 41 } 42 43 // if echarts is not defined, do nothing 44 if (typeof echarts !== "undefined") { 45 setEchartsTheme(theme); 46 } 47 48 // if vegaEmbed is not defined, do nothing 49 if (typeof vegaEmbed !== "undefined") { 50 setVegaLiteTheme(theme); 51 } 52 53 document.documentElement.setAttribute("data-theme", theme); 54 55 // Add class to tables. 56 let tables = document.getElementsByTagName("table"); 57 for (let i = 0; i < tables.length; i++) { 58 if (theme == "dark") { 59 tables[i].classList.add("table-dark"); 60 } else { 61 tables[i].classList.remove("table-dark"); 62 } 63 } 64 65 // Set jupyter notebooks themes. 66 let jupyterNotebooks = document.getElementsByClassName("jupyter-notebook-iframe-container"); 67 for (let i = 0; i < jupyterNotebooks.length; i++) { 68 let bodyElement = jupyterNotebooks[i].getElementsByTagName("iframe")[0].contentWindow.document.body; 69 if (theme == "dark") { 70 bodyElement.setAttribute("data-jp-theme-light", "false"); 71 bodyElement.setAttribute("data-jp-theme-name", "JupyterLab Dark"); 72 } else { 73 bodyElement.setAttribute("data-jp-theme-light", "true"); 74 bodyElement.setAttribute("data-jp-theme-name", "JupyterLab Light"); 75 } 76 } 77 78 // Updates the background of medium-zoom overlay. 79 if (typeof medium_zoom !== "undefined") { 80 medium_zoom.update({ 81 background: getComputedStyle(document.documentElement).getPropertyValue("--global-bg-color") + "ee", // + 'ee' for trasparency. 82 }); 83 } 84}; 85 86let setHighlight = (theme) => { 87 if (theme == "dark") { 88 document.getElementById("highlight_theme_light").media = "none"; 89 document.getElementById("highlight_theme_dark").media = ""; 90 } else { 91 document.getElementById("highlight_theme_dark").media = "none"; 92 document.getElementById("highlight_theme_light").media = ""; 93 } 94}; 95 96let setGiscusTheme = (theme) => { 97 function sendMessage(message) { 98 const iframe = document.querySelector("iframe.giscus-frame"); 99 if (!iframe) return; 100 iframe.contentWindow.postMessage({ giscus: message }, "https://giscus.app"); 101 } 102 103 sendMessage({ 104 setConfig: { 105 theme: theme, 106 }, 107 }); 108}; 109 110let addMermaidZoom = (records, observer) => { 111 var svgs = d3.selectAll(".mermaid svg"); 112 svgs.each(function () { 113 var svg = d3.select(this); 114 svg.html("<g>" + svg.html() + "</g>"); 115 var inner = svg.select("g"); 116 var zoom = d3.zoom().on("zoom", function (event) { 117 inner.attr("transform", event.transform); 118 }); 119 svg.call(zoom); 120 }); 121 observer.disconnect(); 122}; 123 124let setMermaidTheme = (theme) => { 125 if (theme == "light") { 126 // light theme name in mermaid is 'default' 127 // https://mermaid.js.org/config/theming.html#available-themes 128 theme = "default"; 129 } 130 131 /* Re-render the SVG, based on https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/_includes/mermaid.html */ 132 document.querySelectorAll(".mermaid").forEach((elem) => { 133 // Get the code block content from previous element, since it is the mermaid code itself as defined in Markdown, but it is hidden 134 let svgCode = elem.previousSibling.childNodes[0].innerHTML; 135 elem.removeAttribute("data-processed"); 136 elem.innerHTML = svgCode; 137 }); 138 139 mermaid.initialize({ theme: theme }); 140 window.mermaid.init(undefined, document.querySelectorAll(".mermaid")); 141 142 const observable = document.querySelector(".mermaid svg"); 143 if (observable !== null) { 144 var observer = new MutationObserver(addMermaidZoom); 145 const observerOptions = { childList: true }; 146 observer.observe(observable, observerOptions); 147 } 148}; 149 150let setDiff2htmlTheme = (theme) => { 151 document.querySelectorAll(".diff2html").forEach((elem) => { 152 // Get the code block content from previous element, since it is the diff code itself as defined in Markdown, but it is hidden 153 let textData = elem.previousSibling.childNodes[0].innerHTML; 154 elem.innerHTML = ""; 155 const configuration = { colorScheme: theme, drawFileList: true, highlight: true, matching: "lines" }; 156 const diff2htmlUi = new Diff2HtmlUI(elem, textData, configuration); 157 diff2htmlUi.draw(); 158 }); 159}; 160 161let setEchartsTheme = (theme) => { 162 document.querySelectorAll(".echarts").forEach((elem) => { 163 // Get the code block content from previous element, since it is the echarts code itself as defined in Markdown, but it is hidden 164 let jsonData = elem.previousSibling.childNodes[0].innerHTML; 165 echarts.dispose(elem); 166 167 if (theme === "dark") { 168 var chart = echarts.init(elem, "dark-fresh-cut"); 169 } else { 170 var chart = echarts.init(elem); 171 } 172 173 chart.setOption(JSON.parse(jsonData)); 174 }); 175}; 176 177let setVegaLiteTheme = (theme) => { 178 document.querySelectorAll(".vega-lite").forEach((elem) => { 179 // Get the code block content from previous element, since it is the vega lite code itself as defined in Markdown, but it is hidden 180 let jsonData = elem.previousSibling.childNodes[0].innerHTML; 181 elem.innerHTML = ""; 182 if (theme === "dark") { 183 vegaEmbed(elem, JSON.parse(jsonData), { theme: "dark" }); 184 } else { 185 vegaEmbed(elem, JSON.parse(jsonData)); 186 } 187 }); 188}; 189 190let setSearchTheme = (theme) => { 191 const ninjaKeys = document.querySelector("ninja-keys"); 192 if (!ninjaKeys) return; 193 194 if (theme === "dark") { 195 ninjaKeys.classList.add("dark"); 196 } else { 197 ninjaKeys.classList.remove("dark"); 198 } 199}; 200 201let transTheme = () => { 202 document.documentElement.classList.add("transition"); 203 window.setTimeout(() => { 204 document.documentElement.classList.remove("transition"); 205 }, 500); 206}; 207 208// Determine the expected state of the theme toggle, which can be "dark", "light", or
209// "system". Default is "system". 210let determineThemeSetting = () => { 211 let themeSetting = localStorage.getItem("theme"); 212 if (themeSetting != "dark" && themeSetting != "light" && themeSetting != "system") { 213 themeSetting = "system"; 214 } 215 return themeSetting; 216}; 217 218// Determine the computed theme, which can be "dark" or "light". If the theme setting is 219// "system", the computed theme is determined based on the user's system preference. 220let determineComputedTheme = () => { 221 let themeSetting = determineThemeSetting(); 222 if (themeSetting == "system") { 223 const userPref = window.matchMedia; 224 if (userPref && userPref("(prefers-color-scheme: dark)").matches) { 225 return "dark"; 226 } else { 227 return "light"; 228 } 229 } else { 230 return themeSetting; 231 } 232}; 233 234let initTheme = () => { 235 let themeSetting = determineThemeSetting(); 236 237 setThemeSetting(themeSetting); 238 239 // Add event listener to the theme toggle button. 240 document.addEventListener("DOMContentLoaded", function () { 241 const mode_toggle = document.getElementById("light-toggle"); 242 243 mode_toggle.addEventListener("click", function () { 244 toggleThemeSetting(); 245 }); 246 }); 247 248 // Add event listener to the system theme preference change. 249 window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches }) => { 250 applyTheme(); 251 }); 252};
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.