a11y: aria-hidden on the 6 decorative SVG icons rendered from TS

Continuing the SVG aria-hidden pass from 4.6.110 (which covered index.html). The renderer modules build six more decorative SVG icons into their template strings:

- renderer-profile.ts: followers icon, vods icon, last-stream clock, live-viewers eye
- renderer-queue.ts: merge-group icon next to merge-bundled queue rows
- renderer-streamers.ts: empty-state VOD icon shown when a streamer has no VODs

All 6 are pure decoration — each sits next to a textual label or value (e.g. "1.2K followers", "5 VODs", a viewer count, etc.). Screen readers were either announcing them as "image/graphic" or silently traversing — adding aria-hidden="true" cleanly skips them so the assistive-tech read-out is just the meaningful text.

The data-URL SVG fallback in renderer-streamers.ts:257 (used as an onerror src for VOD thumbnails) is intentionally not touched — it's an image fallback inside a URL-encoded string, not an actual SVG element in the DOM.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-05-11 08:17:05 +02:00
parent aed770a56c
commit 632f348349
3 changed files with 6 additions and 6 deletions

View File

@ -96,17 +96,17 @@ function renderStreamerProfileCard(p: StreamerProfile): void {
const followersStat = `
<div class="streamer-profile-stat" title="${escapeProfileHtml(UI_TEXT.profile.followers)}">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
<strong>${escapeProfileHtml(formatProfileFollowers(p.followerCount))}</strong> ${escapeProfileHtml(UI_TEXT.profile.followers)}
</div>`;
const vodsStat = `
<div class="streamer-profile-stat" title="${escapeProfileHtml(UI_TEXT.profile.vodsTooltip)}">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4h-4z"/></svg>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4h-4z"/></svg>
<strong>${p.vodCount}</strong> ${escapeProfileHtml(UI_TEXT.profile.vods)}
</div>`;
const lastStreamStat = `
<div class="streamer-profile-stat" title="${p.lastStreamAt ? escapeProfileHtml(new Date(p.lastStreamAt).toLocaleString()) : ''}">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>
${escapeProfileHtml(UI_TEXT.profile.lastStream)}: <strong>${escapeProfileHtml(formatLastStreamAgo(p.lastStreamAt))}</strong>
</div>`;
@ -128,7 +128,7 @@ function renderStreamerProfileCard(p: StreamerProfile): void {
<div class="streamer-profile-live-body">
<div class="streamer-profile-live-badge-row">
<span class="streamer-profile-badge live">${escapeProfileHtml(UI_TEXT.profile.liveBadge)}</span>
${typeof p.currentStreamViewers === 'number' ? `<span class="streamer-profile-live-viewers"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg> ${escapeProfileHtml(formatProfileFollowers(p.currentStreamViewers))}</span>` : ''}
${typeof p.currentStreamViewers === 'number' ? `<span class="streamer-profile-live-viewers"><svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg> ${escapeProfileHtml(formatProfileFollowers(p.currentStreamViewers))}</span>` : ''}
</div>
${p.currentTitle ? `<div class="streamer-profile-live-title">${escapeProfileHtml(p.currentTitle)}</div>` : ''}
${p.currentGame ? `<div class="streamer-profile-live-game">${escapeProfileHtml(p.currentGame)}</div>` : ''}

View File

@ -536,7 +536,7 @@ function renderQueue(): void {
const selectionIndex = selectedQueueIds.indexOf(item.id);
const isSelected = selectionIndex >= 0;
const mergeIcon = isMergeGroup
? '<svg class="merge-group-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></svg> '
? '<svg class="merge-group-icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></svg> '
: '';
const liveBadge = item.isLive
? `<span class="queue-live-badge" title="${escapeHtml(UI_TEXT.queue.liveRecordingTitle)}">REC</span> `

View File

@ -725,7 +725,7 @@ async function removeStreamer(name: string): Promise<void> {
if (typeof hide === 'function') hide();
byId('vodGrid').innerHTML = `
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9 14l-5-4 5-4v8zm2-8l5 4-5 4V9z"/></svg>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9 14l-5-4 5-4v8zm2-8l5 4-5 4V9z"/></svg>
<h3>${UI_TEXT.vods.noneTitle}</h3>
<p>${UI_TEXT.vods.noneText}</p>
</div>