From 38efffa9b95cc61cd9d4e964e6e0063f64a712cf Mon Sep 17 00:00:00 2001 From: Jet Date: Fri, 27 Mar 2026 13:15:34 -0700 Subject: [PATCH] feat: fix reduce motion controls --- src/lib/background.ts | 89 ++++++++++++------------------------------ src/lib/site.ts | 3 -- src/styles/globals.css | 4 -- 3 files changed, 26 insertions(+), 70 deletions(-) diff --git a/src/lib/background.ts b/src/lib/background.ts index 6beb9a8..5fbba65 100644 --- a/src/lib/background.ts +++ b/src/lib/background.ts @@ -1,8 +1,6 @@ -const STORAGE_KEY = "background-motion-preference"; const MOTION_QUERY = "(prefers-reduced-motion: reduce)"; const STILL_STEPS = 5; -type MotionPreference = "auto" | "off" | "on"; type BackgroundMode = "animated" | "still" | "failed"; interface BackgroundActions { @@ -11,23 +9,7 @@ interface BackgroundActions { renderStill: (steps: number) => void; } -function readPreference(): MotionPreference { - const stored = window.localStorage.getItem(STORAGE_KEY); - return stored === "off" || stored === "on" || stored === "auto" - ? stored - : "auto"; -} - -function writePreference(preference: MotionPreference) { - window.localStorage.setItem(STORAGE_KEY, preference); -} - -function getMode( - preference: MotionPreference, - reducedMotion: boolean, -): BackgroundMode { - if (preference === "on") return "animated"; - if (preference === "off") return "still"; +function getMode(reducedMotion: boolean): BackgroundMode { return reducedMotion ? "still" : "animated"; } @@ -39,46 +21,22 @@ function applyCanvasState(mode: BackgroundMode) { } } -function updateControls( - preference: MotionPreference, - mode: BackgroundMode, - reducedMotion: boolean, -) { - const button = document.getElementById( - "background-toggle", - ) as HTMLButtonElement | null; - const status = document.getElementById("background-status"); - if (!button || !status) return; - - button.textContent = `motion ${preference}`; - - if (mode === "failed") { - status.textContent = "background unavailable"; - return; - } - - if (mode === "still") { - status.textContent = - preference === "auto" && reducedMotion - ? "still frame" - : "background still"; - return; - } - - status.textContent = "background live"; -} - export function initBackgroundControls(actions: BackgroundActions) { const media = window.matchMedia(MOTION_QUERY); - let preference = readPreference(); - let mode: BackgroundMode = getMode(preference, media.matches); + let mode: BackgroundMode = getMode(media.matches); + let failed = false; - const applyMode = () => { - mode = getMode(preference, media.matches); + const applyMode = (restartAnimation = false) => { + if (failed) return; + + mode = getMode(media.matches); applyCanvasState(mode); - updateControls(preference, mode, media.matches); if (mode === "animated") { + if (restartAnimation) { + actions.stop(); + } + actions.start(); return; } @@ -87,29 +45,34 @@ export function initBackgroundControls(actions: BackgroundActions) { actions.renderStill(STILL_STEPS); }; - const button = document.getElementById( - "background-toggle", - ) as HTMLButtonElement | null; + const restartAnimation = () => { + if (document.visibilityState === "hidden" || media.matches) { + return; + } - button?.addEventListener("click", () => { - preference = - preference === "auto" ? "off" : preference === "off" ? "on" : "auto"; - writePreference(preference); - applyMode(); - }); + applyMode(true); + }; media.addEventListener("change", () => { applyMode(); }); + document.addEventListener("visibilitychange", () => { + restartAnimation(); + }); + + window.addEventListener("pageshow", () => { + restartAnimation(); + }); + return { applyInitialMode() { applyMode(); }, setFailed() { + failed = true; mode = "failed"; applyCanvasState(mode); - updateControls(preference, mode, media.matches); }, }; } diff --git a/src/lib/site.ts b/src/lib/site.ts index a142232..a0f578a 100644 --- a/src/lib/site.ts +++ b/src/lib/site.ts @@ -38,9 +38,6 @@ export function renderFooter() { ssh - - - ${mirror.label} `; diff --git a/src/styles/globals.css b/src/styles/globals.css index 8abbd95..97e0f70 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -352,10 +352,6 @@ a[aria-current="page"] { color: var(--dark-gray); } -#background-status { - margin-top: 0; -} - .sr-only { position: absolute; width: 1px;