Commit Graph
3 Commits
Author SHA1 Message Date
logan 254646da5e fix(a11y): mark the playing row with a shape, not only a colour
Build & publish Arch package / arch-package (push) Successful in 2m2s
CI / check (push) Successful in 2m18s
Search index maintenance / maintain-index (push) Successful in 7s
CI / e2e (push) Canceled after 3m51s
a11y.22, WCAG 1.4.1: `.track-row.active` was a background tint and a
text colour, and the row markup carried no aria-current either — so a
colour-blind user could not find the playing row and AT had no signal
at all. The queue panel had aria-current from Phase 1 and the same
colour-only visual.

A triangle drawn in each row's own left padding by `::before`. It is a
shape that is present or absent, and it costs no layout: track-list's
grid columns are computed from the host width, so a marker in the flow
would move every cell on the playing row and nothing else.

Both directions are asserted in both tiers. A marker that renders on
every row satisfies "the playing row has one" for free, which is this
plan's oldest rule.

And one thing the reproduction found: a track started from the *list*
leaves the queue's currentIndex at -1, so the panel has no current row
in that flow at all. Pre-existing, and the reason this looked broken
the first time it was checked in the running app.
2026-08-13 02:14:55 -04:00
logan 2b41c27616 fix(a11y): let a clipped value be read, and name a row's own buttons
Build & publish Arch package / arch-package (push) Successful in 1m55s
CI / check (push) Successful in 2m33s
Search index maintenance / maintain-index (push) Successful in 7s
CI / e2e (push) Successful in 5m23s
a11y.24: `text-overflow: ellipsis` in 40+ places, and the four
highest-density lists were the ones with no `title` — the queue panel
(whose width is user-resizable down to MIN_WIDTH), track-info, every
track-list cell, and the playlist sidebar.

In track-list the attribute is on the *cell*, not on what is inside it:
the value may be a link, a highlighted search match or plain text, and
a tooltip is inherited by descendants either way. One binding rather
than three, and the same value the accessor already computed.

a11y.32: every queue row's remove button was named "Remove from queue",
so a list whose entire purpose is which track is where had four
identically named controls.
2026-08-13 01:55:17 -04:00
logan 8af26fee94 feat(a11y): reorder the queue with Alt+Arrow
a11y.11: the queue's order could not be changed without a mouse.
Reordering existed only as a drag whose drop index is computed from the
cursor's Y position. Reproduced with a row focused: Alt, Ctrl, Shift and
Meta + arrows all left the order untouched.

Alt+ArrowUp/Down moves the focused row and a live region says where it
went. It is handled in the panel's own delegated keydown rather than as
a backend panel binding -- that is where Enter and the roving arrows
already live, it cannot collide with the global Up/Down volume bindings
(measured: 0 VolumeChanged events from a focused row), and it keeps a
destructive-looking key out of the user-editable shortcut table.

Two things the finding did not contain. The index arithmetic is not
symmetric: MoveQueueTracks takes an index into the array before the
move, so down-by-one has to ask for i+2 -- i+1 is where the row already
is once its own removal is accounted for, and the backend's
contiguous-block guard correctly makes it a no-op. Both tiers pin that,
because a symmetric-looking fix silently does nothing in one direction.

And focusedIndex only ever moved on an arrow key, so a row reached by a
click or by Tab left it saying 0 and every key acted on the wrong row --
Enter played the first track in the queue from any focused row. The
delegated handler reads the index off the row the event came from now.
Pre-existing; visible only once a key moved something.
2026-08-12 23:34:00 -04:00