fix(dashboard): a11y basics — skip link, toast live region, combobox palette, keyboard-reachable workbench cards; restore canonical link tokens (design audit P3) - #3182
Conversation
…palette, keyboard-reachable workbench cards; restore canonical link tokens (design audit P3)
Strix Security ReviewNo security issues found. Updated for Reviewed by Strix |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
Reviewed all five changed files in this accessibility-focused PR. The changes are limited to ARIA attributes, keyboard reachability, toast dismissal timer management, a skip link, and CSS color tokens. No untrusted data reaches any dangerous sink: interpolated values (toast messages, recipe names, palette indices) are rendered through React's automatic output/attribute escaping, and no user-controlled URL, HTML, SQL, file path, or exec sink is introduced. No security issues found.
Reviewed by Strix
Configure security review settings
Preserve the design decision record (design-notes, claude-pure picks, palettes, standing rules, playground) from the preserve-design-lab-1763 branch so it lives on main: clickable cards not links, no lazy-loading, skeleton-first rendering, one page width, SPA feel.
|
This workspace has reached the limit of 50 included PR reviews during your trial. Upgrade to continue receiving PR security reviews. So far, Strix has reviewed 36 pull requests and surfaced 2 security issues across this workspace. |
docs/design-lab/ is the 2026-08-17 design-lab record restored byte-identical from preserve-design-lab-1763. playground/compare.html is a local-only harness (127.0.0.1 iframe frames), never shipped or served; same exclusion class as the ghost vendor entry.
|
CodeQL failure root-caused: Round-2 attempted Now: real CI re-running — expected CodeQL green. |
49ef2b1 to
90a66eb
Compare
|
Removed stray Co-Authored-By trailer from the ci(codeql) commit; content unchanged. CI re-running. |
#3437) The design lab was tracked twice. `branding/design-lab/` (12 files, #1827 + #1935) is the real one: `branding/` is the visual spec, `pages.yml` builds and publishes it, and `quality.yml` runs `lab.test.mjs` out of it in both the self-hosted and the GitHub-hosted lane. `docs/design-lab/` (10 files) was the #1763 snapshot re-added incidentally by the #3182 a11y PR (526eaf5) and had drifted, so anyone editing it was editing a dead fork. It was not a pure duplicate, which is why this is a fold and not just a delete. The `docs/` copy had been maintained after the fact: the 2026-09-27 markdown reconciliation (b2b230c) gave it the redaction notice and the design-notes staleness banner, it carried the redaction of one captured attacker IP (85.14.245.122 -> RFC 5737 203.0.113.122) that `branding/` never received, and it held a colour-research section the canonical README had never had. All of it moves to `branding/`, which is the tree that gets published, so the redaction now lives where it is read. Two files keep the canonical version on purpose. `playground/compare.html`: both copies added a `safePath` guard, the canonical one whitelists the path character by character and keeps the `|| '/'` fallback at every call site, the other resolves against an origin and drops it, so the duplicate had nothing the canonical tree lacked. `README.md`: the canonical one documents `lab.mjs`, `lab.test.mjs` and the read-only gate; the duplicate's last section said it "does not carry the harness itself", which is no longer true of either tree. Ten files removed, none dropped: every one of the duplicate's filenames exists in `branding/design-lab/`, and the ten byte-identical ones plus the two redacted files are asserted in the new gate. The one change of substance is that the redaction moved rather than disappeared, so `branding/` no longer carries the address the `docs/` copy had already replaced. Gate: tests/docs/test_3310_design_lab_dedupe.py, picked up by the existing `pytest tests/docs/` row. Three of its six tests name no path -- they key off basenames that exist nowhere but the lab, so a copy reappearing at `docs/design-lab/`, `branding/docs/` or a new `lab/` fails, not just the one path this issue does. References repointed: the CodeQL `paths-ignore` entry moves to the tree that exists (its reasoning is a property of the lab, not the directory, so dropping it would have broken the CodeQL job and keeping it would have exempted nothing while blessing a re-added fork), the `docs/` record-tree exemption goes with the tree it named, and docs/README.md links the canonical README. No workflow, no action pin and no openapi.json change.
Summary
<div>design (per docs/design-lab/README.md), but are now keyboard-reachable:role="button",tabIndex={0},aria-label,aria-expanded, Enter/Space viaonKeyDown.LiveToasts.tsx) getsrole="status" aria-live="polite" aria-atomic="false", a per-toast dismiss button, and hover/focus pauses the 12s auto-dismiss timer (resumes on leave/blur).AppShell, targeting a newid="main"on<main>; reuses the vendored.sr-onlyclass with an inline focus-reveal style (theme.css is vendored, not hand-edited).role="combobox",aria-expanded,aria-controls,aria-activedescendant; result rows aretabIndex={-1}so the input remains the single tab stop.branding/templates/web/apiary-theme.css--apiary-linkrestored to the canonical tokens (dark#de866b, light#9b4f3a) perbranding/tokens.json, replacing the AA-failing blues.Checked
docs/design-lab/README.md(clickable cards not links, no lazy-load, skeleton-first ES panels, one page width, SPA feel) — none of these fixes conflict with it.Found one more instance of the unfixed clickable-div pattern (
Investigate.tsxCardTag, non-href branch) outside this task's scope — filing a separate issue rather than expanding this PR.Test plan
npm ci+npm run typecheck(tsc --noEmit) — clean, no errorsgit diff --statreviewed — only the 5 intended files touched, no lockfile drift