Add a dark and light mode toggle to the header

A sun and moon button at the end of the nav (and the Store's nav) swaps
the mode and remembers the choice in the browser. Until it is pressed the
site follows the device setting. A head script sets html[data-theme]
before first paint, so light styles now key off data-theme instead of a
media query, and motifs render both images with CSS showing one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
Claude
2026-10-18 19:57:05 +00:00
parent 7aa2910b12
commit 4614cd25a0
15 changed files with 200 additions and 106 deletions
+25 -2
View File
@@ -36,8 +36,31 @@ const fullTitle = title === "Greg Kilmer" ? title : `${title} · Greg Kilmer`;
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="color-scheme" content="dark light" />
<meta name="theme-color" content="#0E1522" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#F4F2ED" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0E1522" />
<!-- Before first paint: the visitor's saved mode, else the device's. Without script the site stays dark. -->
<script is:inline>
(() => {
const root = document.documentElement;
const device = matchMedia("(prefers-color-scheme: light)");
const saved = () => {
try {
const t = localStorage.getItem("gk-theme");
return t === "light" || t === "dark" ? t : null;
} catch {
return null;
}
};
const apply = () => {
const t = saved() ?? (device.matches ? "light" : "dark");
root.dataset.theme = t;
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", t === "light" ? "#F4F2ED" : "#0E1522");
};
apply();
device.addEventListener("change", apply);
window.addEventListener("storage", apply);
window.gkApplyTheme = apply;
})();
</script>
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />