Persist the theme selector choice across page loads

Save an explicit light/dark choice to localStorage and clear it when
switching back to system. An inline head script applies the saved
colour scheme before first paint to avoid a flash of the system theme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jonny Barnes 2026-10-24 20:20:21 +01:00
commit c3cf597950
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8
2 changed files with 43 additions and 7 deletions

View file

@ -4,7 +4,34 @@ class ThemeSelector {
this.btnLight = this.widget.querySelector('#btn-light');
this.btnDark = this.widget.querySelector('#btn-dark');
this.status = this.widget.querySelector('#theme-status');
this.currentTheme = 'system';
this.currentTheme = ThemeSelector.storedTheme();
this.updateButtons();
}
static storedTheme() {
try {
const theme = localStorage.getItem('theme');
return (theme === 'light' || theme === 'dark') ? theme : 'system';
} catch {
return 'system';
}
}
static storeTheme(theme) {
try {
if (theme === 'system') {
localStorage.removeItem('theme');
} else {
localStorage.setItem('theme', theme);
}
} catch {
/* storage unavailable, the choice just won't persist */
}
}
updateButtons() {
this.btnLight.setAttribute('aria-pressed', String(this.currentTheme === 'light'));
this.btnDark.setAttribute('aria-pressed', String(this.currentTheme === 'dark'));
}
setupEventListeners() {
@ -43,9 +70,9 @@ class ThemeSelector {
const applyChange = () => {
this.currentTheme = theme;
html.style.setProperty('color-scheme', selectedTheme);
ThemeSelector.storeTheme(theme);
this.btnLight.setAttribute('aria-pressed', String(theme === 'light'));
this.btnDark.setAttribute('aria-pressed', String(theme === 'dark'));
this.updateButtons();
this.status.textContent = theme === 'system' ? 'Theme set to system default' : '';
};

View file

@ -25,6 +25,15 @@
<link rel="pgpkey" href="{{ config('app.url')}}/gpg.key">
@endif
@stack('head')
<script>
{{-- Apply a saved theme choice before first paint to avoid a flash of the system theme --}}
try {
const theme = localStorage.getItem('theme');
if (theme === 'light' || theme === 'dark') {
document.documentElement.style.setProperty('color-scheme', theme);
}
} catch {}
</script>
</head>
<body>
<header>