From 1af842f71a1fd7926ef32b749c8c9efa9c7c9c96 Mon Sep 17 00:00:00 2001 From: druid520 Date: Wed, 21 Oct 2026 01:54:30 +0000 Subject: [PATCH] Add light/dark theme switch to all pages --- 403.html | 2 ++ 404.html | 2 ++ index.html | 2 ++ style.css | 33 ++++++++++++++++++++++++++++++++- theme.js | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 theme.js diff --git a/403.html b/403.html index 41fab77..5f28ab6 100644 --- a/403.html +++ b/403.html @@ -5,9 +5,11 @@ Forbidden · druid520 +
+

Error 403

Forbidden

You don't have access to this page.

diff --git a/404.html b/404.html index 177e017..38f7a19 100644 --- a/404.html +++ b/404.html @@ -5,9 +5,11 @@ Not found · druid520 +
+

Error 404

Not found

There's nothing at this address.

diff --git a/index.html b/index.html index 966043d..203d1c6 100644 --- a/index.html +++ b/index.html @@ -6,9 +6,11 @@ druid520 +
+

druid520

Contact

diff --git a/style.css b/style.css index fe78d48..5dc56bd 100644 --- a/style.css +++ b/style.css @@ -8,8 +8,9 @@ color-scheme: light dark; } +/* Dark palette: follows the OS unless the switch pinned a theme (data-theme on ). */ @media (prefers-color-scheme: dark) { - :root { + :root:not([data-theme="light"]) { --bg: #111; --fg: #e6e6e6; --muted: #999; @@ -19,6 +20,20 @@ } } +:root[data-theme="dark"] { + --bg: #111; + --fg: #e6e6e6; + --muted: #999; + --line: #333; + --code-bg: #1c1c1c; + --link: #7ab7ff; + color-scheme: dark; +} + +:root[data-theme="light"] { color-scheme: light; } + +[hidden] { display: none !important; } + * { box-sizing: border-box; } body { @@ -47,6 +62,22 @@ h2 { a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; } +/* Theme switch */ +.topbar { display: flex; justify-content: flex-end; margin: -1.5rem 0 1.5rem; } +.theme-toggle { + padding: .25rem .7rem; + background: transparent; + color: var(--fg); + border: 1px solid var(--line); + border-radius: 6px; + font-family: inherit; + font-size: .85rem; + line-height: 1.4; + cursor: pointer; +} +.theme-toggle:hover { border-color: var(--muted); } +.theme-toggle:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; } + /* Contact list */ dl { display: grid; diff --git a/theme.js b/theme.js new file mode 100644 index 0000000..f7d2aea --- /dev/null +++ b/theme.js @@ -0,0 +1,35 @@ +// Light/dark switch. The page follows the OS theme until the button is used; +// the choice is then remembered in localStorage. Loaded in so a saved +// theme is applied before the page paints. +(function () { + var root = document.documentElement; + var media = window.matchMedia('(prefers-color-scheme: dark)'); + + try { + var saved = localStorage.getItem('theme'); + if (saved === 'light' || saved === 'dark') root.dataset.theme = saved; + } catch (e) {} + + function current() { + return root.dataset.theme || (media.matches ? 'dark' : 'light'); + } + + function label(btn) { + var next = current() === 'dark' ? 'light' : 'dark'; + btn.textContent = next === 'dark' ? 'Dark mode' : 'Light mode'; + btn.setAttribute('aria-label', 'Switch to ' + next + ' mode'); + } + + document.addEventListener('DOMContentLoaded', function () { + var btn = document.getElementById('theme-toggle'); + if (!btn) return; + label(btn); + btn.hidden = false; + btn.addEventListener('click', function () { + root.dataset.theme = current() === 'dark' ? 'light' : 'dark'; + try { localStorage.setItem('theme', root.dataset.theme); } catch (e) {} + label(btn); + }); + media.addEventListener('change', function () { label(btn); }); + }); +})();