feat: fix reduce motion controls
This commit is contained in:
parent
3f74df0b3a
commit
38efffa9b9
3 changed files with 26 additions and 70 deletions
|
|
@ -1,8 +1,6 @@
|
||||||
const STORAGE_KEY = "background-motion-preference";
|
|
||||||
const MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
const MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
||||||
const STILL_STEPS = 5;
|
const STILL_STEPS = 5;
|
||||||
|
|
||||||
type MotionPreference = "auto" | "off" | "on";
|
|
||||||
type BackgroundMode = "animated" | "still" | "failed";
|
type BackgroundMode = "animated" | "still" | "failed";
|
||||||
|
|
||||||
interface BackgroundActions {
|
interface BackgroundActions {
|
||||||
|
|
@ -11,23 +9,7 @@ interface BackgroundActions {
|
||||||
renderStill: (steps: number) => void;
|
renderStill: (steps: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readPreference(): MotionPreference {
|
function getMode(reducedMotion: boolean): BackgroundMode {
|
||||||
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";
|
|
||||||
return reducedMotion ? "still" : "animated";
|
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) {
|
export function initBackgroundControls(actions: BackgroundActions) {
|
||||||
const media = window.matchMedia(MOTION_QUERY);
|
const media = window.matchMedia(MOTION_QUERY);
|
||||||
let preference = readPreference();
|
let mode: BackgroundMode = getMode(media.matches);
|
||||||
let mode: BackgroundMode = getMode(preference, media.matches);
|
let failed = false;
|
||||||
|
|
||||||
const applyMode = () => {
|
const applyMode = (restartAnimation = false) => {
|
||||||
mode = getMode(preference, media.matches);
|
if (failed) return;
|
||||||
|
|
||||||
|
mode = getMode(media.matches);
|
||||||
applyCanvasState(mode);
|
applyCanvasState(mode);
|
||||||
updateControls(preference, mode, media.matches);
|
|
||||||
|
|
||||||
if (mode === "animated") {
|
if (mode === "animated") {
|
||||||
|
if (restartAnimation) {
|
||||||
|
actions.stop();
|
||||||
|
}
|
||||||
|
|
||||||
actions.start();
|
actions.start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -87,29 +45,34 @@ export function initBackgroundControls(actions: BackgroundActions) {
|
||||||
actions.renderStill(STILL_STEPS);
|
actions.renderStill(STILL_STEPS);
|
||||||
};
|
};
|
||||||
|
|
||||||
const button = document.getElementById(
|
const restartAnimation = () => {
|
||||||
"background-toggle",
|
if (document.visibilityState === "hidden" || media.matches) {
|
||||||
) as HTMLButtonElement | null;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
button?.addEventListener("click", () => {
|
applyMode(true);
|
||||||
preference =
|
};
|
||||||
preference === "auto" ? "off" : preference === "off" ? "on" : "auto";
|
|
||||||
writePreference(preference);
|
|
||||||
applyMode();
|
|
||||||
});
|
|
||||||
|
|
||||||
media.addEventListener("change", () => {
|
media.addEventListener("change", () => {
|
||||||
applyMode();
|
applyMode();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener("visibilitychange", () => {
|
||||||
|
restartAnimation();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("pageshow", () => {
|
||||||
|
restartAnimation();
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
applyInitialMode() {
|
applyInitialMode() {
|
||||||
applyMode();
|
applyMode();
|
||||||
},
|
},
|
||||||
setFailed() {
|
setFailed() {
|
||||||
|
failed = true;
|
||||||
mode = "failed";
|
mode = "failed";
|
||||||
applyCanvasState(mode);
|
applyCanvasState(mode);
|
||||||
updateControls(preference, mode, media.matches);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,6 @@ export function renderFooter() {
|
||||||
<span aria-hidden="true">|</span>
|
<span aria-hidden="true">|</span>
|
||||||
<a href="/ssh.txt" data-native-link>ssh</a>
|
<a href="/ssh.txt" data-native-link>ssh</a>
|
||||||
<span aria-hidden="true">|</span>
|
<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>
|
<a href="${mirror.href}">${mirror.label}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
|
||||||
|
|
@ -352,10 +352,6 @@ a[aria-current="page"] {
|
||||||
color: var(--dark-gray);
|
color: var(--dark-gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
#background-status {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sr-only {
|
.sr-only {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue