a11y: VOD cards keyboard-activatable — opens VOD on Twitch via Enter/Space
Following the chip + row + nav a11y passes, the VOD cards in the
main grid were the last big mouse-only surface in the sidebar +
main panel flow. Each card already delegated click via a single
vodGrid handler — but the card div itself was unfocusable, so a
keyboard user could only reach the +Queue / Trim VOD buttons
inside, never the card thumbnail click that opens the VOD page on
Twitch.
Added on each .vod-card:
- role="button" + tabindex="0"
- aria-label set to the VOD title so AT announces it correctly
("32h37m9s VOD: Cyborg Watchparty button") instead of reading
the whole card content row by row
Added to the existing delegated vodGrid handler:
- A keydown branch that opens the VOD on Twitch when Enter / Space
fires on a focused .vod-card and the event target is the card
itself (not a child action button or checkbox — those have
their own native button / checkbox semantics that handle Enter
/ Space correctly already)
CSS adds a 3px purple focus-visible ring + accent-coloured border
on the focused card, mirroring the hover state's purple glow.
Tab order through the VOD grid now goes: VOD card -> checkbox -> Trim
button -> +Queue button -> next VOD card. Predictable enough for
keyboard navigation through a 38-VOD streamer profile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0b99014de3
commit
76be8d3949
@ -248,6 +248,9 @@ function buildVodCardHtml(vod: VOD, streamer: string, downloadedIds?: Set<string
|
||||
// titles containing backslashes / HTML entities like '.
|
||||
return `
|
||||
<div class="vod-card${isChecked ? ' selected' : ''}${isAlreadyDownloaded ? ' already-downloaded' : ''}"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="${safeTitleAttr}"
|
||||
data-vod-id="${safeIdAttr}"
|
||||
data-vod-url="${safeUrlAttr}"
|
||||
data-vod-title="${safeTitleAttr}"
|
||||
@ -892,6 +895,22 @@ function initVodGridSelectionDelegation(): void {
|
||||
e.preventDefault();
|
||||
showVodContextMenu(e.clientX, e.clientY, ctx);
|
||||
});
|
||||
|
||||
// Enter / Space on a focused VOD card opens the VOD on Twitch — same
|
||||
// outcome as a mouse click on the thumbnail. Skip when focus is on a
|
||||
// child (action button, checkbox) because those have their own
|
||||
// keyboard handlers (native button + checkbox semantics).
|
||||
grid.addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'Enter' && e.key !== ' ') return;
|
||||
const target = e.target as HTMLElement | null;
|
||||
if (!target) return;
|
||||
const card = target.closest('.vod-card') as HTMLElement | null;
|
||||
if (!card || card !== target) return;
|
||||
const ctx = readVodCardContext(card);
|
||||
if (!ctx) return;
|
||||
e.preventDefault();
|
||||
void window.api.openExternal(ctx.url);
|
||||
});
|
||||
}
|
||||
|
||||
let activeVodContextMenu: HTMLElement | null = null;
|
||||
|
||||
@ -1288,6 +1288,12 @@ select option {
|
||||
border-color: rgba(145, 70, 255, 0.35);
|
||||
}
|
||||
|
||||
.vod-card:focus-visible {
|
||||
outline: none;
|
||||
border-color: rgba(145, 70, 255, 0.7);
|
||||
box-shadow: 0 0 0 3px rgba(145, 70, 255, 0.35);
|
||||
}
|
||||
|
||||
.vod-card.selected {
|
||||
box-shadow: 0 0 0 2px #9146FF, 0 8px 25px rgba(145, 70, 255, 0.25);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user