PageSourceSearch

https://lukeschaeffer.com/assets/js/theme.js?9a0c749ec5240d9cda97bc72359a72c0

js lukeschaeffer.com collected 2026-09-24 12:43:45 UTC 8,013 bytes, 252 lines download raw bytes

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.