Compare commits

...

2 Commits

Author SHA1 Message Date
xRangerDE
01acbcc47f release: 4.6.65 cut + merge progress bars a11y role=progressbar
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 04:31:42 +02:00
xRangerDE
fa440951d2 a11y: cut + merge progress bars role=progressbar + aria-valuenow
Following 4.6.64 for the queue progress bars, the cut + merge
progress containers in their respective tabs had the same gap:
a plain <div class="progress-bar"> wrapping a <div class="progress-
bar-fill"> with no semantic role. JS poked the bar's style.width
on every percent update; AT had no way to read out the running
value.

Promoted both .progress-bar wrappers to role="progressbar" with
aria-valuemin / max / now, plus aria-label sourced from new
locale strings (cutProgressAria / mergeProgressAria) so EN/DE
both work.

The progress event handlers in renderer.ts now also stamp
aria-valuenow on each tick, so AT live regions pick up the
percentage as the cut / merge advances. setAttribute is cheap
relative to the FFmpeg progress event rate (~1/s), no perf
concern.

renderer-texts.applyText sets the localized aria-label on both
gauges at boot + language switch — text contents already get
re-applied through the same path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 04:31:41 +02:00
7 changed files with 19 additions and 9 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.6.64", "version": "4.6.65",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "4.6.64", "version": "4.6.65",
"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.64", "version": "4.6.65",
"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

@ -372,7 +372,7 @@
</div> </div>
<div class="progress-container" id="cutProgress"> <div class="progress-container" id="cutProgress">
<div class="progress-bar"> <div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-label="Cut progress" id="cutProgressGauge">
<div class="progress-bar-fill" id="cutProgressBar"></div> <div class="progress-bar-fill" id="cutProgressBar"></div>
</div> </div>
<div class="progress-text" id="cutProgressText">0%</div> <div class="progress-text" id="cutProgressText">0%</div>
@ -404,7 +404,7 @@
</div> </div>
<div class="progress-container" id="mergeProgress"> <div class="progress-container" id="mergeProgress">
<div class="progress-bar"> <div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-label="Merge progress" id="mergeProgressGauge">
<div class="progress-bar-fill" id="mergeProgressBar"></div> <div class="progress-bar-fill" id="mergeProgressBar"></div>
</div> </div>
<div class="progress-text" id="mergeProgressText">0%</div> <div class="progress-text" id="mergeProgressText">0%</div>

View File

@ -357,7 +357,9 @@ const UI_TEXT_DE = {
liveNowTooltip: 'Aktuell live auf Twitch', liveNowTooltip: 'Aktuell live auf Twitch',
modalCloseAria: 'Dialog schliessen', modalCloseAria: 'Dialog schliessen',
sidebarEmpty: 'Noch keine Streamer. Fuege oben rechts einen hinzu.', sidebarEmpty: 'Noch keine Streamer. Fuege oben rechts einen hinzu.',
removeAria: 'Entfernen' removeAria: 'Entfernen',
cutProgressAria: 'Schnitt-Fortschritt',
mergeProgressAria: 'Merge-Fortschritt'
}, },
vods: { vods: {
noneTitle: 'Keine VODs', noneTitle: 'Keine VODs',

View File

@ -357,7 +357,9 @@ const UI_TEXT_EN = {
liveNowTooltip: 'Currently live on Twitch', liveNowTooltip: 'Currently live on Twitch',
modalCloseAria: 'Close dialog', modalCloseAria: 'Close dialog',
sidebarEmpty: 'No streamers yet. Add one via the input at the top right.', sidebarEmpty: 'No streamers yet. Add one via the input at the top right.',
removeAria: 'Remove' removeAria: 'Remove',
cutProgressAria: 'Cut progress',
mergeProgressAria: 'Merge progress'
}, },
vods: { vods: {
noneTitle: 'No VODs', noneTitle: 'No VODs',

View File

@ -253,6 +253,8 @@ function applyLanguageToStaticUI(): void {
// Localize the modal close-button aria-label. The buttons share a // Localize the modal close-button aria-label. The buttons share a
// .modal-close-localizable class so one call updates all five. // .modal-close-localizable class so one call updates all five.
setAriaLabelAll('.modal-close-localizable', UI_TEXT.streamers.modalCloseAria); setAriaLabelAll('.modal-close-localizable', UI_TEXT.streamers.modalCloseAria);
document.getElementById('cutProgressGauge')?.setAttribute('aria-label', UI_TEXT.streamers.cutProgressAria);
document.getElementById('mergeProgressGauge')?.setAttribute('aria-label', UI_TEXT.streamers.mergeProgressAria);
setText('backupCardTitle', UI_TEXT.static.backupCardTitle); setText('backupCardTitle', UI_TEXT.static.backupCardTitle);
setText('backupCardIntro', UI_TEXT.static.backupCardIntro); setText('backupCardIntro', UI_TEXT.static.backupCardIntro);
setText('btnExportConfig', UI_TEXT.static.exportConfig); setText('btnExportConfig', UI_TEXT.static.exportConfig);

View File

@ -168,13 +168,17 @@ async function init(): Promise<void> {
}); });
window.api.onCutProgress((percent: number) => { window.api.onCutProgress((percent: number) => {
const rounded = Math.round(percent);
byId('cutProgressBar').style.width = percent + '%'; byId('cutProgressBar').style.width = percent + '%';
byId('cutProgressText').textContent = Math.round(percent) + '%'; byId('cutProgressText').textContent = rounded + '%';
byId('cutProgressGauge').setAttribute('aria-valuenow', String(rounded));
}); });
window.api.onMergeProgress((percent: number) => { window.api.onMergeProgress((percent: number) => {
const rounded = Math.round(percent);
byId('mergeProgressBar').style.width = percent + '%'; byId('mergeProgressBar').style.width = percent + '%';
byId('mergeProgressText').textContent = Math.round(percent) + '%'; byId('mergeProgressText').textContent = rounded + '%';
byId('mergeProgressGauge').setAttribute('aria-valuenow', String(rounded));
}); });
// Update stats bar — paused while the window is hidden so we don't // Update stats bar — paused while the window is hidden so we don't