mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-11 19:21:33 -07:00
fix(stats): respect prefers-reduced-motion in the delete indicator
The delete indicator's sweeping bar and spinner loop forever, which is exactly the motion prefers-reduced-motion exists to suppress. Shortening the duration the way the overlay does for its one-shot notification animations would speed a looping animation up instead of removing it, so the looping rules stop outright and hold a static busy state: the bar fills its track rather than sitting off-screen at its start transform, and the toast text carries the meaning.
This commit is contained in:
@@ -108,3 +108,23 @@ body.overlay-mode #root {
|
|||||||
.animate-indeterminate {
|
.animate-indeterminate {
|
||||||
animation: indeterminate-sweep 1.1s ease-in-out infinite;
|
animation: indeterminate-sweep 1.1s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.animate-fade-in {
|
||||||
|
animation-duration: 1ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Looping motion can't just be shortened the way a one-shot entrance can —
|
||||||
|
that speeds it up rather than removing it. The delete indicator holds a
|
||||||
|
static busy state instead: the bar fills its track and the spinner stops,
|
||||||
|
leaving the toast text to carry the meaning. */
|
||||||
|
.animate-indeterminate {
|
||||||
|
animation: none;
|
||||||
|
width: 100%;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-spin {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,3 +14,25 @@ test('stats overlay mode paints an opaque full-viewport background', () => {
|
|||||||
/body\.overlay-mode #root\s*\{[^}]*background-color:\s*var\(--color-ctp-base\);/s,
|
/body\.overlay-mode #root\s*\{[^}]*background-color:\s*var\(--color-ctp-base\);/s,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('reduced motion stops the looping delete indicator rather than speeding it up', () => {
|
||||||
|
const reducedMotion = /@media \(prefers-reduced-motion: reduce\)\s*\{(?<body>.*)\n\}/s.exec(css)
|
||||||
|
?.groups?.body;
|
||||||
|
assert.ok(reducedMotion, 'expected a prefers-reduced-motion block');
|
||||||
|
|
||||||
|
// Shortening an infinite animation makes it run faster, so the looping rules
|
||||||
|
// have to switch it off outright and hold a static state instead.
|
||||||
|
assert.match(reducedMotion, /\.animate-indeterminate\s*\{[^}]*animation:\s*none;/s);
|
||||||
|
assert.match(reducedMotion, /\.animate-indeterminate\s*\{[^}]*width:\s*100%;/s);
|
||||||
|
assert.match(reducedMotion, /\.animate-spin\s*\{[^}]*animation:\s*none;/s);
|
||||||
|
assert.doesNotMatch(reducedMotion, /\.animate-indeterminate\s*\{[^}]*animation-duration:/s);
|
||||||
|
assert.doesNotMatch(reducedMotion, /\.animate-spin\s*\{[^}]*animation-duration:/s);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the looping delete indicator keeps its animation for everyone else', () => {
|
||||||
|
const beforeMediaQuery = css.slice(0, css.indexOf('@media (prefers-reduced-motion'));
|
||||||
|
assert.match(
|
||||||
|
beforeMediaQuery,
|
||||||
|
/\.animate-indeterminate\s*\{\s*animation:\s*indeterminate-sweep/s,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user