feat: fix reduce motion controls

This commit is contained in:
Jet 2026-03-27 13:15:34 -07:00
parent 3f74df0b3a
commit 38efffa9b9
No known key found for this signature in database
3 changed files with 26 additions and 70 deletions

View file

@ -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);
},
};
}

View file

@ -38,9 +38,6 @@ export function renderFooter() {
<span aria-hidden="true">|</span>
<a href="/ssh.txt" data-native-link>ssh</a>
<span aria-hidden="true">|</span>
<button type="button" id="background-toggle" class="qa-inline-action">motion auto</button>
<span id="background-status" class="qa-meta" aria-live="polite"></span>
<span aria-hidden="true">|</span>
<a href="${mirror.href}">${mirror.label}</a>
</div>
</div>`;

View file

@ -352,10 +352,6 @@ a[aria-current="page"] {
color: var(--dark-gray);
}
#background-status {
margin-top: 0;
}
.sr-only {
position: absolute;
width: 1px;