Merge pull request #80 from quoije/2026

Fix theme flash on player navigation
This commit was merged in pull request #80.
This commit is contained in:
Mathieu Moran
2026-01-26 02:48:34 -05:00
committed by GitHub
4 changed files with 24 additions and 8 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ Little nodejs + mongodb app that I hack together with ChatGPT and Cursor to keep
**Disclaimer:** This was a fun, experimental project built with “AI slop” (Cursor), so it may have security issues. For example, `python_video_server` uses the default token‑in‑URL approach to serve video files, which can leave user tokens in logs or browser history. There are ways to improve this, but at this point I’m blinder than Ray Charles. **Disclaimer:** This was a fun, experimental project built with “AI slop” (Cursor), so it may have security issues. For example, `python_video_server` uses the default token‑in‑URL approach to serve video files, which can leave user tokens in logs or browser history. There are ways to improve this, but at this point I’m blinder than Ray Charles.
![Oscars Pool 2026](img/preview.gif) ![Oscars Pool 2026](img/preview.png)
## Features ## Features
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 446 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

+23 -7
View File
@@ -1,6 +1,7 @@
// Theme toggle with system preference fallback. // Theme toggle with system preference fallback.
(function () { (function () {
const STORAGE_KEY = 'theme_preference'; const STORAGE_KEY = 'theme_preference';
const LAST_KEY = 'theme_last_applied';
const THEME_ATTR = 'data-theme'; const THEME_ATTR = 'data-theme';
const SOURCE_ATTR = 'data-theme-source'; const SOURCE_ATTR = 'data-theme-source';
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
@@ -17,6 +18,11 @@
function setTheme(theme, source) { function setTheme(theme, source) {
document.documentElement.setAttribute(THEME_ATTR, theme); document.documentElement.setAttribute(THEME_ATTR, theme);
document.documentElement.setAttribute(SOURCE_ATTR, source); document.documentElement.setAttribute(SOURCE_ATTR, source);
try {
sessionStorage.setItem(LAST_KEY, theme);
} catch (_) {
// Ignore storage errors.
}
updateToggleUi(theme, source); updateToggleUi(theme, source);
} }
@@ -56,12 +62,16 @@
if (!res.ok) return; if (!res.ok) return;
const data = await res.json(); const data = await res.json();
const pref = normalizeTheme(data?.themePreference); const pref = normalizeTheme(data?.themePreference);
if (pref) { const currentPref = normalizeTheme(localStorage.getItem(STORAGE_KEY));
localStorage.setItem(STORAGE_KEY, pref); const changed = pref !== currentPref;
} else { if (changed) {
localStorage.removeItem(STORAGE_KEY); if (pref) {
localStorage.setItem(STORAGE_KEY, pref);
} else {
localStorage.removeItem(STORAGE_KEY);
}
applyStoredOrSystem();
} }
applyStoredOrSystem();
} catch (_) { } catch (_) {
// Ignore fetch errors. // Ignore fetch errors.
} }
@@ -69,8 +79,14 @@
function applyStoredOrSystem() { function applyStoredOrSystem() {
const stored = normalizeTheme(localStorage.getItem(STORAGE_KEY)); const stored = normalizeTheme(localStorage.getItem(STORAGE_KEY));
const theme = stored || getSystemTheme(); let last = null;
const source = stored ? 'user' : 'system'; try {
last = normalizeTheme(sessionStorage.getItem(LAST_KEY));
} catch (_) {
last = null;
}
const theme = stored || last || getSystemTheme();
const source = stored ? 'user' : (last ? 'session' : 'system');
setTheme(theme, source); setTheme(theme, source);
} }