Now I remember the theme
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled

This commit is contained in:
2026-02-10 20:38:38 -05:00
parent 70710239c7
commit f50a828535
19 changed files with 321 additions and 304 deletions

View File

@@ -343,12 +343,14 @@ textarea:focus-visible {
justify-content: center;
width: 100%;
height: 100%;
font-weight: 900;
letter-spacing: -0.02em;
font-size: 13px;
line-height: 1;
}
.theme-notch-glyph svg {
width: 18px;
height: 18px;
}
.theme-notch-panel {
position: absolute;
right: 60px;

View File

@@ -49,10 +49,11 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
/>
<link rel="stylesheet" href="/styles/global.css" />
<script is:inline>
(() => {
const THEME_KEY = "site.theme";
const COOKIE_KEY = "site_theme";
const validate = (v) => (v === "dark" || v === "light" || v === "high-contrast" ? v : null);
@@ -64,6 +65,26 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
}
};
const readCookie = () => {
try {
const parts = document.cookie ? document.cookie.split(";") : [];
for (let i = 0; i < parts.length; i++) {
const p = parts[i].trim();
if (!p) continue;
if (!p.startsWith(COOKIE_KEY + "=")) continue;
const raw = p.slice((COOKIE_KEY + "=").length);
try {
return validate(decodeURIComponent(raw));
} catch {
return validate(raw);
}
}
return null;
} catch {
return null;
}
};
const forcedColors = () => {
try {
return window.matchMedia && window.matchMedia("(forced-colors: active)").matches;
@@ -80,7 +101,7 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
}
};
const stored = readStored();
const stored = readStored() || readCookie();
const theme = stored || (forcedColors() ? "high-contrast" : prefersLight() ? "light" : "dark");
document.documentElement.dataset.theme = theme;
})();
@@ -203,7 +224,25 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
aria-expanded="false"
data-theme-notch-handle
>
<span class="theme-notch-glyph" aria-hidden="true">Theme</span>
<span class="theme-notch-glyph" aria-hidden="true">
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="4" y1="6" x2="20" y2="6"></line>
<line x1="4" y1="12" x2="20" y2="12"></line>
<line x1="4" y1="18" x2="20" y2="18"></line>
<circle cx="9" cy="6" r="2"></circle>
<circle cx="15" cy="12" r="2"></circle>
<circle cx="11" cy="18" r="2"></circle>
</svg>
</span>
</button>
</aside>
@@ -285,13 +324,26 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
<script is:inline>
(() => {
const THEME_KEY = "site.theme";
const COOKIE_KEY = "site_theme";
const ONE_YEAR_SECONDS = 31536000;
const validate = (v) => (v === "dark" || v === "light" || v === "high-contrast" ? v : null);
const setCookieTheme = (theme) => {
const v = validate(theme);
if (!v) return;
const secure = window.location && window.location.protocol === "https:" ? "; Secure" : "";
const cookie = `${COOKIE_KEY}=${encodeURIComponent(v)}; Max-Age=${ONE_YEAR_SECONDS}; Path=/; SameSite=Lax${secure}`;
document.cookie = cookie;
};
const setTheme = (next, opts) => {
const theme = validate(next);
if (!theme) return;
const prevTheme = validate(document.documentElement.dataset.theme);
if (prevTheme === theme) return;
if (opts && opts.withTransition) {
document.documentElement.dataset.themeTransition = "on";
}
@@ -304,6 +356,26 @@ const canonicalUrl = `${siteUrl}${canonicalPath.startsWith("/") ? canonicalPath
// ignore
}
try {
setCookieTheme(theme);
} catch {
// ignore
}
try {
if (typeof window.umami !== "undefined") {
const payload = {
target_id: `theme.switch.${theme}`,
placement: "theme_notch",
theme,
};
if (prevTheme) payload.prev_theme = prevTheme;
window.umami.track("theme_switch", payload);
}
} catch {
// ignore
}
if (opts && opts.withTransition) {
window.setTimeout(() => {
delete document.documentElement.dataset.themeTransition;