From 96113dc267e3063c1b72d659b7da967e8b65bfb0 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Mon, 11 May 2026 03:41:21 +0200 Subject: [PATCH] =?UTF-8?q?a11y:=20streamer-profile=20header=20=E2=80=94?= =?UTF-8?q?=20avatar=20wrap=20+=20live=20card=20keyboard-activatable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two click-only divs in the new profile header (4.6.17+) had no keyboard equivalent: - .streamer-profile-avatar-wrap (clicking the avatar opens the channel on twitch.tv) — the only way to trigger that action besides the "Open on Twitch" button in the action column, so keyboard users were missing a primary affordance - .streamer-profile-live-card (clicking anywhere on the live preview card starts a live recording) — the embedded Record-now button inside the card already covered keyboard activation, so this one is more about completeness than necessity Both got: - role="button" + tabindex="0" - aria-label = the existing tooltip locale string (so AT reads the same text shown to sighted users on hover) - An inline onkeydown that re-fires the same onclick handler on Enter / Space. The live-card additionally checks event.target === event.currentTarget so a focused inner button pressing Enter doesn't double-fire the wrapper handler CSS adds focus-visible rings: - Purple ring on the avatar wrap (matching the existing avatar's purple border) - Red ring + glow on the live card (matching the existing card border colour) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/renderer-profile.ts | 4 ++-- src/styles.css | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/renderer-profile.ts b/src/renderer-profile.ts index 38ec6a0..940beb2 100644 --- a/src/renderer-profile.ts +++ b/src/renderer-profile.ts @@ -121,7 +121,7 @@ function renderStreamerProfileCard(p: StreamerProfile): void { // current preview frame + viewer count + title + game + record CTA. const liveCard = p.isLive ? ` -
+
${p.currentStreamPreviewUrl ? `Live preview` : `
`} @@ -140,7 +140,7 @@ function renderStreamerProfileCard(p: StreamerProfile): void { applyProfileHtml(el, ` ${bannerStyle ? `
` : ''}
-
+
${avatarBlock}
diff --git a/src/styles.css b/src/styles.css index e3261e9..f8f6dee 100644 --- a/src/styles.css +++ b/src/styles.css @@ -3340,6 +3340,17 @@ input[type="number"]::-webkit-outer-spin-button { transform: scale(1.04); } +.streamer-profile-avatar-wrap:focus-visible { + outline: none; + border-radius: 50%; + box-shadow: 0 0 0 3px rgba(145, 70, 255, 0.55); +} + +.streamer-profile-live-card:focus-visible { + outline: none; + box-shadow: 0 0 0 3px rgba(233, 25, 22, 0.55), 0 6px 22px rgba(233, 25, 22, 0.20); +} + .streamer-profile-avatar { width: 88px; height: 88px;