PageSourceSearch

https://csvtodashboard.com/theme-toggle.js

js csvtodashboard.com collected 2026-09-25 20:04:59 UTC 2,996 bytes, 67 lines download raw bytes

1// Vanilla theme toggle for static pages — matches the React-rendered version on the home page.
2// Apply persisted theme synchronously (before paint) to avoid a light/dark flash.
3(function () {
4  try {
5    var stored = localStorage.getItem("csvtd-theme");
6    var prefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
7    var theme = stored || (prefersDark ? "dark" : "light");
8    document.documentElement.setAttribute("data-theme", theme);
9  } catch (e) { /* localStorage may be blocked */ }
10
11  function moonSvg() {
12    return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
13  }
14  function sunSvg() {
15    return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>';
16  }
17
18  function attach() {
19    // Static pages carry TWO hooks (desktop nav-links + the mobile nav-menu
20    // panel) — wire every slot and keep their icons/labels in sync.
21    var slots = document.querySelectorAll("[data-theme-toggle]");
22    if (!slots.length) return;
23    var buttons = [];
24
25    function render() {
26      var theme = document.documentElement.getAttribute("data-theme") || "light";
27      for (var i = 0; i < buttons.length; i++) {
28        buttons[i].innerHTML = theme === "dark" ? sunSvg() : moonSvg();
29        buttons[i].setAttribute("aria-label", "Switch to " + (theme === "dark" ? "light" : "dark") + " mode");
30        buttons[i].setAttribute("title", "Switch to " + (theme === "dark" ? "light" : "dark") + " mode");
31      }
32    }
33
34    function toggle() {
35      var current = document.documentElement.getAttribute("data-theme") || "light";
36      var next = current === "dark" ? "light" : "dark";
37      document.documentElement.setAttribute("data-theme", next);
38      try { localStorage.setItem("csvtd-theme", next); } catch (e) {}
39      render();
40    }
41
42    for (var i = 0; i < slots.length; i++) {
43      var btn = document.createElement("button");
44      btn.className = "theme-toggle";
45      btn.addEventListener("click", toggle);
46      buttons.push(btn);
47      slots[i].appendChild(btn);
48    }
49
50    render();
51  }
52
53  if (document.readyState === "loading") {
54    document.addEventListener("DOMContentLoaded", attach);
55  } else {
56    attach();
57  }
58
59  // Tapping a link inside the mobile <details> menu closes it (matters for
60  // same-page # anchors, which don't navigate and would leave it open).
61  document.addEventListener("click", function (e) {
62    var a = e.target && e.target.closest && e.target.closest(".nav-menu-panel a");
63    if (!a) return;
64    var d = a.closest("details.nav-menu");
65    if (d) d.open = false;
66  });
67})();

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.