Skip to content

fix: a11y names, 390 px layout, and the audit's copy gaps (stacked on #40) - #44

Draft
prodelt wants to merge 3 commits into
mainfrom
fix/a11y-mobile
Draft

prodelt wants to merge 3 commits into
mainfrom
fix/a11y-mobile

Conversation

@prodelt

@prodelt prodelt commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Stacked on #40 (feat/modes-row): this branch starts from it, so the diff against main includes #40 until that merges. Main is frozen for judging; do not merge.

Why

A jury-style audit (D2, D3, B3) and CI on 80d8375 found focus stops without a name, a cut-off /about on a phone, a half-width dock, a first-run language switch that lagged, mismatched mode labels, a wrong "mechanics" marker, a result headline that disagreed with «Далі», low-contrast locked badges, and stale coach-line e2e.

What

  1. Focus stops have a role and a name (D2). Status bar Level, Streak and Race Rating, the rail's Season card, Home's weak chips and Profile badges are named groups/items whose name says the value (e.g. group "Рівень 1: 10 з 160 XP"). The tooltip stays as the description. The stage scroll area is region "Вміст екрана". New expectFocusablesNamed (e2e harness) reads Chromium's accessibility tree over CDP and fails on any focusable node without a role or a name. viewport-1024 and viewport-390 run it on every screen.
  2. 390×844 (D3). /about gets a phone layout: one column, type sized to the screen, nothing cut. The method cells also stopped stacking on one spot at every width, because the shell's .stage grid placement had leaked onto them. The dock now spans 0–390 with five even tabs. Sprint, Daily and Own text show the "physical keyboard" notice on a phone like other training routes (Sprint's header overlapped at 390). New e2e/viewport-390.spec.ts (modelled on viewport-1024) covers 14 routes: no sideways scroll, nothing cut at the edge, axe, named focus stops, plus the dock's even spacing.
  3. First run language. Picking ENG switches the status bar's УКР/ENG at once. Clicking the switch also picks in the flow. Past step 1, a switch returns to the level step for the new layout.
  4. Mode labels. One pair in both states and both languages: «Тренувальна спроба / Залікова спроба» ("Practice attempt / Test attempt"). The current one is shown by pressed state and ring.
  5. Academy mechanics. Decided per exercise rather than per module kind. An exercise counts as mechanics when its lines hold letter groups that are not words. «the · you», «her · and» and the organiser word lists no longer say «Рядки не є словами»; «th · he», «ing · hat» and «-ість · -ння» still do. Unit-tested on both real courses.
  6. Result vs «Далі». New practiceAdvice, used by both the headline and nextStartMode. The headline asks for the test only when «Далі» opens it. When the coach points elsewhere (the next key) it says «Точність 98,0%, поріг 95% взято.» and the card names the destination. Unit-tested, including a check that the two never disagree.
  7. Profile badges contrast. A locked badge is shown by a dashed edge, a lock glyph and muted text (≥ 4.5:1), with no opacity. axe passes in light, dark and low vision.
  8. Coach-line e2e. The product copy names both fingers in full: «Потренуйте ф → в (10%): лівий мізинець і лівий середній палець.» It wraps and is not cut on screen (checked at 1024×768); the «се…» came from the CI log. The assertions follow the shortened copy, and the weak-transition test now also checks that both fingers are named in full and the line does not overflow.

scrollWidth at 390×844 (before → after)

route before after
/about 462 390
/, /map, /races, /groups, /profile, /settings, /licences, /privacy, /formulas, /about/project, /own, /sprint, /daily 390 390

/formulas keeps its level table in its own focusable scroll area, which is intentional. /sprint showed a broken header at 390 and now shows the keyboard notice.

Tests

  • pnpm check: green (809 unit tests).
  • pnpm build: initial JS 149.6 KB gzip (149.3 on feat(home): Modes row (Daily, Sprint, Own text, Mistakes) + Esc closes every tooltip #40).
  • Chromium e2e (CI=1):
    • viewport-390 15/15, viewport-1024 14/14, home, academy, exercise -g mechanics: 41 passed.
    • result, path-progress, stage1-moves, stage2: 39/39.
    • shell, meta-screens: 20/20.
    • settings -g "Profile|first run" (all three themes) and meta-screens:137: passed.
  • Checked running at 390×844 and 1280×800: /about, the dock, Profile badges in light and dark, the first-run switch, the pre-start mode pair, the result coach line, and the Academy marker.

🤖 Generated with Claude Code

prodelt and others added 3 commits October 6, 2026 00:39
… closes every tooltip

Testers could not find the new modes: Sprint sat behind /review, Own text behind a Map key,
Daily was a small link. Home now has a sixth, quiet row of four cards (glyph, name, one line).
Sprint is dimmed until Stage 2 opens and Mistakes until there are weak spots; their Tip says
how they open. Daily shows a "готово" chip once cleared today. The row is a lazy chunk so the
initial JS stays under 150 KB, and a coach-mark step points at it.

On screens up to 900 px tall the session steps become one line of chips and the vertical
rhythm tightens, so Continue's Start button is never clipped (it already was at 1024x768).

The status bar's stats, the layout switch and Home's weak-spot chips now use the shared Tip,
so Esc hides their bubble. Daily's "Днів поспіль" becomes "Викликів поспіль" so it no longer
reads as the Streak. CoachMarks' keydown listener joins the seam exemptions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ground note

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and the audit's copy gaps

Accessibility (D2):
- The status bar's Level, Streak and Race Rating, the rail's Season card, Home's weak chips and
  Profile's badges are named groups/items whose name says the value; the stage's scroll area is a
  named region ("Вміст екрана").
- e2e: expectFocusablesNamed reads Chromium's accessibility tree and fails on any focusable node
  without a role or a name; viewport-1024 and the new viewport-390 run it on every screen.

Phone, 390x844 (D3):
- /about gets a phone layout: one column, type sized to the screen, the hero card and lede no
  longer cut (scrollWidth 462 -> 390). The method cells no longer stack on top of each other:
  the shell's .stage grid placement leaked onto them at every width.
- The bottom dock spans the full width with five even tabs; the rail's side tooltips are hidden
  on a phone.
- Sprint, Daily and Own text ask for a physical keyboard on a phone like every training route
  (Sprint's header overlapped itself at 390).
- e2e/viewport-390.spec.ts: 14 routes, no sideways scroll, nothing cut, axe, named focus stops,
  and the dock's even spacing.

Copy and logic:
- First run: picking a language switches the status bar's УКР/ENG at once, and the switch picks
  in the flow (past step 1 it returns to the level step for the new layout).
- The attempt-type buttons keep one pair of names in both states: «Тренувальна спроба» /
  «Залікова спроба».
- Academy: "mechanics" is decided per exercise, from whether its lines hold letter groups that
  are not words; «the · you» and other word drills no longer say «Рядки не є словами».
- Result: after a cleared practice attempt the headline asks for the test only when «Далі»
  opens it (practiceAdvice); otherwise it says the floor is cleared. Unit-tested.
- Profile badges: locked is a dashed edge, a lock glyph and muted text at >= 4.5:1, never
  opacity, so axe passes in light, dark and low vision.
- e2e: the coach-line assertions follow the shortened result copy; the weak-transition line is
  checked to name both fingers in full and not to overflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
typing-race Ready Ready Preview Oct 6, 2026 5:33am UTC

This branch was successfully deployed

1 active deployment
Preview — 0dd8391b Deployed Oct 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant