Add light/dark theme switch to all pages
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-10-21 01:54:30 +00:00
parent 6ee95c955c
commit 1af842f71a
5 changed files with 73 additions and 1 deletions
+2
View File
@@ -5,9 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Forbidden · druid520</title>
<link rel="stylesheet" href="/style.css">
<script src="/theme.js"></script>
</head>
<body>
<main class="error">
<div class="topbar"><button id="theme-toggle" class="theme-toggle" type="button" hidden>Dark mode</button></div>
<h2>Error 403</h2>
<h1>Forbidden</h1>
<p>You don't have access to this page.</p>
+2
View File
@@ -5,9 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Not found · druid520</title>
<link rel="stylesheet" href="/style.css">
<script src="/theme.js"></script>
</head>
<body>
<main class="error">
<div class="topbar"><button id="theme-toggle" class="theme-toggle" type="button" hidden>Dark mode</button></div>
<h2>Error 404</h2>
<h1>Not found</h1>
<p>There's nothing at this address.</p>
+2
View File
@@ -6,9 +6,11 @@
<title>druid520</title>
<meta name="description" content="Contact details and public keys for druid520.">
<link rel="stylesheet" href="/style.css">
<script src="/theme.js"></script>
</head>
<body>
<main>
<div class="topbar"><button id="theme-toggle" class="theme-toggle" type="button" hidden>Dark mode</button></div>
<h1>druid520</h1>
<h2>Contact</h2>
+32 -1
View File
@@ -8,8 +8,9 @@
color-scheme: light dark;
}
/* Dark palette: follows the OS unless the switch pinned a theme (data-theme on <html>). */
@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;
+35
View File
@@ -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 <head> 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); });
});
})();