-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathisaqb-theme.js
More file actions
135 lines (121 loc) · 3.56 KB
/
Copy pathisaqb-theme.js
File metadata and controls
135 lines (121 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
(function () {
const toc = document.getElementById("toc");
if (!toc || typeof IntersectionObserver === "undefined") {
return;
}
const linkFor = new Map();
for (const link of toc.querySelectorAll('a[href^="#"]')) {
const heading = document.getElementById(link.getAttribute("href").slice(1));
if (heading) {
linkFor.set(heading, link);
}
}
if (linkFor.size === 0) {
return;
}
let active = null;
const observer = new IntersectionObserver(
(entries) => {
let top = null;
for (const entry of entries) {
if (
entry.isIntersecting &&
(top === null ||
entry.boundingClientRect.top < top.boundingClientRect.top)
) {
top = entry;
}
}
if (!top || top.target === active) {
return;
}
if (active) {
linkFor.get(active).classList.remove("is-active");
}
linkFor.get(top.target).classList.add("is-active");
active = top.target;
},
{ rootMargin: "0px 0px -70% 0px", threshold: 0 },
);
for (const heading of linkFor.keys()) {
observer.observe(heading);
}
})();
(function () {
const root = document.documentElement;
const KEY = "isaqb-theme";
let saved = null;
try {
saved = localStorage.getItem(KEY);
} catch {
/* storage blocked */
}
if (saved === "dark" || saved === "light") {
root.setAttribute("data-theme", saved);
}
const prefersDark =
window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)");
function effectiveTheme() {
const attr = root.getAttribute("data-theme");
if (attr === "dark" || attr === "light") {
return attr;
}
return prefersDark && prefersDark.matches ? "dark" : "light";
}
/**
* Themed images.
*
* An image opted in with the `theme-swap` role/class loads a "-dark" filename
* variant in dark mode and the original in light mode:
*
* images/logo.svg <-> images/logo-dark.svg
*/
const THEMED_IMAGE_SELECTOR = ".theme-swap img, img.theme-swap";
function darkVariant(src) {
return src.replace(/(\.[^./?#]+)([?#].*)?$/, "-dark$1$2");
}
function applyThemeToImages(theme) {
for (const image of document.querySelectorAll(THEMED_IMAGE_SELECTOR)) {
image.dataset.lightSrc ??= image.getAttribute("src");
const nextSrc =
theme === "dark"
? darkVariant(image.dataset.lightSrc)
: image.dataset.lightSrc;
if (image.getAttribute("src") !== nextSrc) {
image.setAttribute("src", nextSrc);
}
}
}
const de = (navigator.language || "en").toLowerCase().indexOf("de") === 0;
const labels = de
? {
toLight: "Zum hellen Design wechseln",
toDark: "Zum dunklen Design wechseln",
}
: { toLight: "Switch to light theme", toDark: "Switch to dark theme" };
const btn = document.createElement("button");
btn.id = "theme-toggle";
btn.type = "button";
function render() {
const theme = effectiveTheme();
const dark = theme === "dark";
btn.textContent = dark ? "☀" : "☾";
const label = dark ? labels.toLight : labels.toDark;
btn.setAttribute("aria-label", label);
btn.setAttribute("title", label);
applyThemeToImages(theme);
}
btn.addEventListener("click", () => {
const next = effectiveTheme() === "dark" ? "light" : "dark";
root.setAttribute("data-theme", next);
try {
localStorage.setItem(KEY, next);
} catch {
/* storage blocked */
}
render();
});
render();
prefersDark?.addEventListener("change", render);
document.body.appendChild(btn);
})();