ui: theme tokens split into light.css/dark.css linked via prefers-color-scheme; dark favicon variant; fix missing dark-mode tokens

This commit is contained in:
2026-08-01 04:12:09 +02:00
parent 1f3e058484
commit 4d71433a6a
11 changed files with 115 additions and 73 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 KiB

After

Width:  |  Height:  |  Size: 535 KiB

+30 -5
View File
@@ -4,12 +4,31 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Status Page</title>
<link
rel="icon"
type="image/svg+xml"
href="/favicon.svg"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
type="image/svg+xml"
href="/favicon-dark.svg"
media="(prefers-color-scheme: dark)"
/>
<link
id="theme-light"
rel="stylesheet"
media="(prefers-color-scheme: light)"
href="./src/light.css"
/>
<link
id="theme-dark"
rel="stylesheet"
media="(prefers-color-scheme: dark)"
href="/dark.css"
href="./src/dark.css"
/>
<link rel="stylesheet" href="./src/styles.css" />
<script>
(function () {
try {
@@ -18,10 +37,16 @@
localStorage.setItem('statuspage-theme', q)
}
var t = localStorage.getItem('statuspage-theme')
var link = document.getElementById('theme-dark')
if (!link) return
if (t === 'dark') link.media = 'all'
else if (t === 'light') link.media = 'not all'
var light = document.getElementById('theme-light')
var dark = document.getElementById('theme-dark')
if (!light || !dark) return
if (t === 'dark') {
light.media = 'not all'
dark.media = 'all'
} else if (t === 'light') {
light.media = 'all'
dark.media = 'not all'
}
} catch (e) {}
})()
</script>
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="8" fill="#171b17" stroke="#666" stroke-width="2.5" />
<text x="16" y="15" font-family="Inria Sans, 'Segoe UI', Roboto, sans-serif" font-weight="700" font-size="21" fill="#e8ece7" text-anchor="middle" dominant-baseline="central">S</text>
</svg>

After

Width:  |  Height:  |  Size: 354 B

+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="8" fill="#fafafa" stroke="#111" stroke-width="2.5" />
<text x="16" y="15" font-family="Inria Sans, 'Segoe UI', Roboto, sans-serif" font-weight="700" font-size="21" fill="#111" text-anchor="middle" dominant-baseline="central">S</text>
</svg>

After

Width:  |  Height:  |  Size: 351 B

+13 -8
View File
@@ -68,14 +68,19 @@ const THEME_ICONS: Record<Theme, string> = {
const STORAGE_KEY = 'statuspage-theme'
function applyTheme(theme: Theme) {
const link = document.getElementById('theme-dark') as HTMLLinkElement | null
if (!link) return
link.media =
theme === 'dark'
? 'all'
: theme === 'light'
? 'not all'
: '(prefers-color-scheme: dark)'
const light = document.getElementById('theme-light') as HTMLLinkElement | null
const dark = document.getElementById('theme-dark') as HTMLLinkElement | null
if (!light || !dark) return
if (theme === 'dark') {
light.media = 'not all'
dark.media = 'all'
} else if (theme === 'light') {
light.media = 'all'
dark.media = 'not all'
} else {
light.media = '(prefers-color-scheme: light)'
dark.media = '(prefers-color-scheme: dark)'
}
}
function readTheme(): Theme {
+7 -1
View File
@@ -1,4 +1,4 @@
:root:root {
:root {
color-scheme: dark;
--bg: #0f1210;
@@ -39,11 +39,17 @@
--err: #ff6b70;
--border-ink: #3a403a;
--border: 2px solid var(--border-ink);
--border-muted: #3a403a;
--shadow-color: #000;
--shadow: 0.35rem 0.35rem 0 var(--shadow-color);
--shadow-lg: 0.55rem 0.55rem 0 var(--shadow-color);
--overlay: rgba(0, 0, 0, 0.6);
--sheen: rgba(255, 255, 255, 0.07);
--sheen-strong: rgba(255, 255, 255, 0.12);
--on-accent: #111;
--incidents-ink: #e8e8e8;
--radius: 0.5rem;
--mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Menlo, monospace;
}
+57
View File
@@ -0,0 +1,57 @@
:root {
color-scheme: light;
/* accents */
--green: #1aad4b;
--green-glow: rgba(26, 173, 75, 0.7);
--yellow: #e5b400;
--red: #e5484d;
--ok-soft: #c7ecd3;
--ok-ink: #0a5c22;
--fail-soft: #ffd6d6;
--fail-ink: #9c0000;
--err: #a00;
/* surfaces */
--bg: #f2f2f2;
--card: #fafafa;
--surface: #fff;
--surface-muted: #e5e5e5;
--status-up-bg: #d9f2e0;
--status-degraded-bg: #fff3b8;
--status-down-bg: #2b2b2b;
--status-unknown-bg: #e4e4e4;
--down-chip-bg: #2a2a2a;
--down-chip-ink: #eee;
--down-chip-border: #555;
--dark-surface: #111;
--code-bg: #1a1d1a;
--code-ink: #e9f7ea;
--code-border: #2a2e2a;
/* text */
--ink: #111;
--ink-invert: #f2f2f2;
--muted: #777;
--muted-2: #888;
--muted-3: #999;
--muted-4: #555;
--muted-5: #bbb;
--muted-dot: #ccc;
--white: #fff;
--on-accent: #111;
/* lines & shadows */
--border-ink: #111;
--border: 2px solid var(--border-ink);
--border-muted: #bbb;
--shadow-color: #888;
--shadow: 0.35rem 0.35rem 0 var(--shadow-color);
--shadow-lg: 0.55rem 0.55rem 0 var(--shadow-color);
--overlay: rgba(0, 0, 0, 0.35);
--sheen: rgba(255, 255, 255, 0.75);
--sheen-strong: rgba(255, 255, 255, 0.9);
--radius: 0.5rem;
--mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Menlo, monospace;
}
-1
View File
@@ -5,6 +5,5 @@ import '@fontsource/inria-sans/700.css'
import '@fontsource/inria-sans/400-italic.css'
import '@fontsource/jetbrains-mono/400.css'
import '@fontsource/jetbrains-mono/600.css'
import './styles.css'
render(<App />, document.getElementById('app')!)
-58
View File
@@ -1,61 +1,3 @@
:root {
color-scheme: light;
/* accents */
--green: #1aad4b;
--green-glow: rgba(26, 173, 75, 0.7);
--yellow: #e5b400;
--red: #e5484d;
--ok-soft: #c7ecd3;
--ok-ink: #0a5c22;
--fail-soft: #ffd6d6;
--fail-ink: #9c0000;
--err: #a00;
/* surfaces */
--bg: #f2f2f2;
--card: #fafafa;
--surface: #fff;
--surface-muted: #e5e5e5;
--status-up-bg: #d9f2e0;
--status-degraded-bg: #fff3b8;
--status-down-bg: #2b2b2b;
--status-unknown-bg: #e4e4e4;
--down-chip-bg: #2a2a2a;
--down-chip-ink: #eee;
--down-chip-border: #555;
--dark-surface: #111;
--code-bg: #1a1d1a;
--code-ink: #e9f7ea;
--code-border: #2a2e2a;
/* text */
--ink: #111;
--ink-invert: #f2f2f2;
--muted: #777;
--muted-2: #888;
--muted-3: #999;
--muted-4: #555;
--muted-5: #bbb;
--muted-dot: #ccc;
--white: #fff;
--on-accent: #111;
/* lines & shadows */
--border-ink: #111;
--border: 2px solid var(--border-ink);
--border-muted: #bbb;
--shadow-color: #888;
--shadow: 0.35rem 0.35rem 0 var(--shadow-color);
--shadow-lg: 0.55rem 0.55rem 0 var(--shadow-color);
--overlay: rgba(0, 0, 0, 0.35);
--sheen: rgba(255, 255, 255, 0.75);
--sheen-strong: rgba(255, 255, 255, 0.9);
--radius: 0.5rem;
--mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Menlo, monospace;
}
* {
box-sizing: border-box;
}