diff --git a/frontend/e2e/a11y.spec.ts b/frontend/e2e/a11y.spec.ts index d62b31e1..42830509 100644 --- a/frontend/e2e/a11y.spec.ts +++ b/frontend/e2e/a11y.spec.ts @@ -13,11 +13,10 @@ import { gotoPage, openApp, openFirstVideo } from "./helpers"; // Chromium only (playwright.config.ts leaves it out of the other projects). const TAGS = ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"]; -/** Wait until nothing is loading: no QueryState spinner and no skeleton bone left. */ +/** Wait until nothing is loading: no QueryState spinner and no skeleton bone left. A bone says it is + * one (`data-skeleton`): a pulse alone is not loading — a running job's dot pulses as long as it runs. */ async function settled(page: Page): Promise { - await expect( - page.locator('[role="status"] .animate-spin, [aria-hidden="true"].animate-pulse'), - ).toHaveCount(0); + await expect(page.locator('[role="status"] .animate-spin, [data-skeleton]')).toHaveCount(0); } async function violations(page: Page): Promise { diff --git a/frontend/src/components/Channels.tsx b/frontend/src/components/Channels.tsx index 125709fe..fc1e6c85 100644 --- a/frontend/src/components/Channels.tsx +++ b/frontend/src/components/Channels.tsx @@ -515,7 +515,9 @@ export default function Channels() { id: "backfill", label: t("channels.backfillEverything"), title: t("channels.backfillEverythingHint"), - icon: , + icon: ( + + ), onSelect: () => deepAll.mutate(), disabled: deepAll.isPending, }, diff --git a/frontend/src/components/DownloadButton.tsx b/frontend/src/components/DownloadButton.tsx index e12c2f84..f68d5f38 100644 --- a/frontend/src/components/DownloadButton.tsx +++ b/frontend/src/components/DownloadButton.tsx @@ -54,7 +54,10 @@ export default function DownloadButton({ > {/* The state is in the glyph: downloaded or queued is the accent, a running one pulses. */} {open && ( diff --git a/frontend/src/components/DownloadTray.tsx b/frontend/src/components/DownloadTray.tsx index 9937cfca..bee55acc 100644 --- a/frontend/src/components/DownloadTray.tsx +++ b/frontend/src/components/DownloadTray.tsx @@ -98,7 +98,7 @@ function Progress({ job }: { job: QueueJob }) { style={{ width: `${job.progress}%` }} /> ) : ( - + )} {bytes && {job.progress}%} diff --git a/frontend/src/components/RunStatusDot.tsx b/frontend/src/components/RunStatusDot.tsx index cb3ba7f5..a1657c38 100644 --- a/frontend/src/components/RunStatusDot.tsx +++ b/frontend/src/components/RunStatusDot.tsx @@ -4,7 +4,7 @@ // Interrupted is a ring, not a fill: the job did not fail, but its work did not finish either — set // apart from a skipped run (the same colour, filled) and from a failure. const DOT_CLASS = { - running: "bg-accent animate-pulse", + running: "bg-accent motion-safe:animate-pulse", ok: "bg-success", error: "bg-danger", skipped: "bg-warn", diff --git a/frontend/src/components/Scheduler.tsx b/frontend/src/components/Scheduler.tsx index 1b1cd714..e4d501cf 100644 --- a/frontend/src/components/Scheduler.tsx +++ b/frontend/src/components/Scheduler.tsx @@ -238,7 +238,7 @@ function JobProgress({ p }: { p: SchedulerJob["progress"] }) { /> ) : ( // Indeterminate: total unknown, so a slim moving sliver instead of a fill. -
+
)}
diff --git a/frontend/src/components/SetupWizard.tsx b/frontend/src/components/SetupWizard.tsx index 6989b7f2..03f01ba8 100644 --- a/frontend/src/components/SetupWizard.tsx +++ b/frontend/src/components/SetupWizard.tsx @@ -259,7 +259,9 @@ export default function SetupWizard() { onClick={sendTest} disabled={testState === "sending" || !testTo.trim()} > - + {t("setup.smtp.test")} diff --git a/frontend/src/components/ui/Skeleton.tsx b/frontend/src/components/ui/Skeleton.tsx index 5c1576ff..115fef2c 100644 --- a/frontend/src/components/ui/Skeleton.tsx +++ b/frontend/src/components/ui/Skeleton.tsx @@ -13,6 +13,7 @@ function Skeleton({ className, inline = false }: { className?: string; inline?: return (