Compare commits

..

2 Commits

Author SHA1 Message Date
xRangerDE
32decb4c01 release: 4.6.31 modal a11y — dialog roles + aria-labels
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 01:50:27 +02:00
xRangerDE
afef213b45 a11y: dialog roles + aria-labelledby + aria-label on modal closes
All five modal-overlay containers (update, clip-cutter, events-viewer,
chat-viewer, template-guide) were rendering as plain divs from an
accessibility perspective. Screen readers would announce nothing
distinguishing when one of them opened, and the close-X buttons would
read as "x button" with no semantic meaning.

Added on each .modal-overlay:
- role="dialog" — tells assistive tech this is a modal region
- aria-modal="true" — instructs the reader to ignore content outside
  the dialog while it is open (matches the keyboard escape + click-
  outside-to-dismiss behavior the renderer already implements)
- aria-labelledby="<existingTitleId>" — every modal already had a
  uniquely-IDd h2; pointed each dialog at its own title so the reader
  announces e.g. "Stream events dialog" on open

Added on each .modal-close button:
- aria-label="Close" — gives the X button a real semantic label
  independent of the visual character

Zero visual change, zero behavior change. Just makes the app actually
usable for someone running NVDA/JAWS/Orca/VoiceOver. WCAG 4.1.2 +
2.1.1 + 1.3.1 alignment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 01:50:26 +02:00
3 changed files with 13 additions and 13 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.6.30", "version": "4.6.31",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.6.30", "version": "4.6.31",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"axios": "^1.6.0", "axios": "^1.6.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.6.30", "version": "4.6.31",
"description": "Twitch VOD Manager - Download Twitch VODs easily", "description": "Twitch VOD Manager - Download Twitch VODs easily",
"main": "dist/main.js", "main": "dist/main.js",
"author": "xRangerDE", "author": "xRangerDE",

View File

@ -18,9 +18,9 @@
<button id="updateButton" onclick="downloadUpdate()">Jetzt herunterladen</button> <button id="updateButton" onclick="downloadUpdate()">Jetzt herunterladen</button>
</div> </div>
<div class="modal-overlay" id="updateModal" onclick="handleUpdateModalOverlayClick(event)"> <div class="modal-overlay" id="updateModal" role="dialog" aria-modal="true" aria-labelledby="updateModalTitle" onclick="handleUpdateModalOverlayClick(event)">
<div class="modal update-modal"> <div class="modal update-modal">
<button class="modal-close" onclick="dismissUpdateModal()">x</button> <button class="modal-close" aria-label="Close" onclick="dismissUpdateModal()">x</button>
<div class="update-modal-eyebrow" id="updateModalEyebrow">Updates</div> <div class="update-modal-eyebrow" id="updateModalEyebrow">Updates</div>
<h2 id="updateModalTitle">Update verfugbar</h2> <h2 id="updateModalTitle">Update verfugbar</h2>
<p class="update-modal-message" id="updateModalMessage">Version 0.0.0 ist verfugbar. Jetzt herunterladen?</p> <p class="update-modal-message" id="updateModalMessage">Version 0.0.0 ist verfugbar. Jetzt herunterladen?</p>
@ -46,9 +46,9 @@
</div> </div>
<!-- Clip Dialog Modal --> <!-- Clip Dialog Modal -->
<div class="modal-overlay" id="clipModal"> <div class="modal-overlay" id="clipModal" role="dialog" aria-modal="true" aria-labelledby="clipDialogTitle">
<div class="modal" style="background: #2b2b2b; max-width: 500px;"> <div class="modal" style="background: #2b2b2b; max-width: 500px;">
<button class="modal-close" onclick="closeClipDialog()">x</button> <button class="modal-close" aria-label="Close" onclick="closeClipDialog()">x</button>
<h2 style="color: #E5A00D; text-align: center; margin-bottom: 20px;" id="clipDialogTitle">VOD zuschneiden</h2> <h2 style="color: #E5A00D; text-align: center; margin-bottom: 20px;" id="clipDialogTitle">VOD zuschneiden</h2>
<!-- Start Zeit mit Slider --> <!-- Start Zeit mit Slider -->
@ -137,9 +137,9 @@
</div> </div>
<!-- Events Viewer Modal --> <!-- Events Viewer Modal -->
<div class="modal-overlay" id="eventsViewerModal"> <div class="modal-overlay" id="eventsViewerModal" role="dialog" aria-modal="true" aria-labelledby="eventsViewerTitle">
<div class="modal" style="max-width: 700px; max-height: 80vh; display:flex; flex-direction:column;"> <div class="modal" style="max-width: 700px; max-height: 80vh; display:flex; flex-direction:column;">
<button class="modal-close" onclick="closeEventsViewer()">x</button> <button class="modal-close" aria-label="Close" onclick="closeEventsViewer()">x</button>
<h2 id="eventsViewerTitle" style="margin-top:0;">Stream events</h2> <h2 id="eventsViewerTitle" style="margin-top:0;">Stream events</h2>
<div id="eventsViewerStatus" style="color:var(--text-secondary); font-size:12px; margin-bottom:8px;"></div> <div id="eventsViewerStatus" style="color:var(--text-secondary); font-size:12px; margin-bottom:8px;"></div>
<div id="eventsViewerList" style="flex:1; overflow-y:auto; background: var(--bg-main); border:1px solid var(--border-soft); border-radius:6px; padding:8px;"></div> <div id="eventsViewerList" style="flex:1; overflow-y:auto; background: var(--bg-main); border:1px solid var(--border-soft); border-radius:6px; padding:8px;"></div>
@ -147,9 +147,9 @@
</div> </div>
<!-- Chat Replay Viewer Modal --> <!-- Chat Replay Viewer Modal -->
<div class="modal-overlay" id="chatViewerModal"> <div class="modal-overlay" id="chatViewerModal" role="dialog" aria-modal="true" aria-labelledby="chatViewerTitle">
<div class="modal" style="max-width: 800px; height: 80vh; display:flex; flex-direction:column;"> <div class="modal" style="max-width: 800px; height: 80vh; display:flex; flex-direction:column;">
<button class="modal-close" onclick="closeChatViewer()">x</button> <button class="modal-close" aria-label="Close" onclick="closeChatViewer()">x</button>
<h2 id="chatViewerTitle" style="margin-top:0;">Chat replay</h2> <h2 id="chatViewerTitle" style="margin-top:0;">Chat replay</h2>
<div class="form-row" style="margin-bottom:8px; gap:8px; flex-wrap:wrap; align-items:center;"> <div class="form-row" style="margin-bottom:8px; gap:8px; flex-wrap:wrap; align-items:center;">
<input type="text" id="chatViewerFilter" placeholder="Filter..." oninput="onChatViewerFilterChange()" style="flex:1; min-width:160px; background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:6px 10px; color:var(--text); font-size:13px;"> <input type="text" id="chatViewerFilter" placeholder="Filter..." oninput="onChatViewerFilterChange()" style="flex:1; min-width:160px; background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:6px 10px; color:var(--text); font-size:13px;">
@ -160,9 +160,9 @@
</div> </div>
<!-- Template Guide Modal --> <!-- Template Guide Modal -->
<div class="modal-overlay" id="templateGuideModal"> <div class="modal-overlay" id="templateGuideModal" role="dialog" aria-modal="true" aria-labelledby="templateGuideTitle">
<div class="modal template-guide-modal"> <div class="modal template-guide-modal">
<button class="modal-close" onclick="closeTemplateGuide()">x</button> <button class="modal-close" aria-label="Close" onclick="closeTemplateGuide()">x</button>
<h2 id="templateGuideTitle">Template Guide</h2> <h2 id="templateGuideTitle">Template Guide</h2>
<p id="templateGuideIntro" class="template-guide-intro">Nutze Variablen fur Dateinamen und prufe das Ergebnis als Live-Vorschau.</p> <p id="templateGuideIntro" class="template-guide-intro">Nutze Variablen fur Dateinamen und prufe das Ergebnis als Live-Vorschau.</p>