Implement visual accommodations and Full Keyboard Access
Full relative text scaling per DESIGN/10: BoardMetrics is the board strip's geometry as a pure function of the body point size (CardWindowMetrics' twin) — lane plate/header/band, card corner/stripe/padding, masonry spacing, the drop model's nominal card height, resize-handle geometry, trash hatch pitch, and both window floors all derive from an em; CardFaceMetrics folded in. The two fixed font sizes (welcome brand/glyph) went relative; the toolbar search field is 17 ems like the transient bar's. The no-horizontal-scroll invariant is pinned by test at six text sizes by twelve lane counts. Accommodations is Motion's sibling for the visual settings: Increase Contrast adds a flat point to strokes (monotone, hierarchy-preserving), gives borderless card/lane plates a resting separator hairline, and takes faded accents to full alpha; Reduce Transparency turns the transient search bar's glass solid and does the same for the alpha washes that composite over a user-chosen board background (trash plate, hatched header, drag shadow). Reduce Motion audited — every animated surface already routes through Motion with a reduced variant; no gaps. Full Keyboard Access: the template chooser's tiles were pointer-only — now focusable, arrow-navigable (clamped, StyleWellGrid's rule), Space picks, Return stays the sheet's default action, focus names the selection one-way. The board's single tab stop shows its focus ring under FKA (focusEffectDisabled inverts). Style editor verified already conformant. Edge accents verified text-free; trash hatch pitch now font-derived so it still reads as hatching at large text. 1549 unit tests green, both schemes build. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -48,7 +48,7 @@ Lanework is in early development. This list tracks what has actually shipped and
|
||||
|
||||
- **The agent guide** — every board root carries a `CLAUDE.md` the app writes and keeps current: a condensed, agent-facing rendition of the schema — the folder layout, ordering arithmetic, creating and moving cards, the `.trash/` convention, `attachments/`, `modified-by` self-stamping, the colour and icon palettes, and the git etiquette — so any file-capable agent dropped into the folder already knows how to work the board. It is app-owned and version-gated by a marker in its first line: rewritten when missing or older, left byte-for-byte alone when current or newer, and re-checked on every reload, so a guide deleted or rolled back from outside heals by itself. A `CLAUDE.md` that isn't the app's is never clobbered — it moves to `CLAUDE.user.md` (the user's own extension point, which the app otherwise never touches), and if that name is taken the app simply doesn't write a guide. A symlink or folder wearing the name is left alone, and a board on a read-only volume is skipped in silence: the guide is a courtesy and never an interruption.
|
||||
|
||||
- **Accessibility** — the board is a real VoiceOver surface, not a grid of unlabelled rectangles: lanes are containers read as "⟨title⟩, lane, N cards" (the count is the filter's, like the visible badge), each card is one flattened element carrying its title, its attachment count and its cut-pending state, and traversal follows card `order` rather than masonry column position. VO-Space toggles selection through the same funnel a ⌘-click uses, context-menu rows double as custom actions, lane titles are headings for the rotor, and the trash column pins last. A **live board announces itself**: a foreign edit lands as one polite, non-interrupting digest per reload — "Board changed: 2 cards edited, 1 card added" — while the app's own writes stay silent, and a card that disappears under the cursor is named rather than merely lost ("Card 'Fix login' was deleted externally"), with focus recovering to its lane; when the lane went too, the announcement names the *lane* and its count and focus walks up then sideways to whatever now holds its position. Bracketed operations say one thing at completion and never their internal churn, and the banner strip is an announced element in its own right — the read-only lock and reload breakage speak when they appear and when they clear.
|
||||
- **Accessibility** — the board is a real VoiceOver surface, not a grid of unlabelled rectangles: lanes are containers read as "⟨title⟩, lane, N cards" (the count is the filter's, like the visible badge), each card is one flattened element carrying its title, its attachment count and its cut-pending state, and traversal follows card `order` rather than masonry column position. VO-Space toggles selection through the same funnel a ⌘-click uses, context-menu rows double as custom actions, lane titles are headings for the rotor, and the trash column pins last. A **live board announces itself**: a foreign edit lands as one polite, non-interrupting digest per reload — "Board changed: 2 cards edited, 1 card added" — while the app's own writes stay silent, and a card that disappears under the cursor is named rather than merely lost ("Card 'Fix login' was deleted externally"), with focus recovering to its lane; when the lane went too, the announcement names the *lane* and its count and focus walks up then sideways to whatever now holds its position. Bracketed operations say one thing at completion and never their internal churn, and the banner strip is an announced element in its own right — the read-only lock and reload breakage speak when they appear and when they clear. **Every size in the app is relative**: there is not one hard-coded point size left — the card face, the lane header, the masonry, the style editor's wells and every window's floor derive from the system body font, so the whole board grows with the system text size while the no-horizontal-scroll rule holds (the lanes compress, the strip never scrolls) and titles keep truncating gracefully. The system's visual accommodations are wired throughout: **Increase Contrast** thickens every border and selection ring and gives card and lane plates an outline they don't otherwise have, **Reduce Transparency** turns the transient search bar's glass and the trash column's washes solid, and **Reduce Motion** has a variant for every animated surface in the app — movement goes instant, appear/disappear goes crossfade, uniformly, the live-reload seam included. Nothing is ever said by colour alone (selection is a ring plus a trait, a cut card is dimmed plus "cut, pending paste", the trash header is hatched plus labelled, a mixed batch reads "mixed"), and under **Full Keyboard Access** the board is a single visible tab stop with the arrow grammar inside it while every control around it — lane buttons, popovers, the style grids, welcome rows, template tiles — is Tab-reachable, arrow-navigable and labelled.
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
Reference in New Issue
Block a user