a11y: localized aria-label + focus-visible on the 3 merge file-row buttons

The merge tab's per-file action buttons (▲ ▼ x — move up, move down, remove from list) were three icon-only buttons whose only visible content was the unicode glyph. No aria-label, no title, no focus-visible ring:

- Screen readers had nothing to announce — a keyboard user navigating the merge file list would tab through three unnamed buttons in a row.
- Sighted keyboard users had no visible focus indicator on .file-btn.

Three new locale keys (DE+EN) — merge.moveUpAria / moveDownAria / removeAria — give each button a translated aria-label and matching title tooltip. CSS adds .file-btn:focus-visible with the purple ring and a red variant for .file-btn.remove to match its red-on-hover colour family.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-05-11 08:42:10 +02:00
parent 85cc4957d8
commit f6f266e3d4
4 changed files with 23 additions and 5 deletions

View File

@ -457,7 +457,10 @@ const UI_TEXT_DE = {
merging: 'Zusammenfugen...', merging: 'Zusammenfugen...',
merge: 'Zusammenfugen', merge: 'Zusammenfugen',
success: 'Videos erfolgreich zusammengefugt!', success: 'Videos erfolgreich zusammengefugt!',
failed: 'Fehler beim Zusammenfugen der Videos.' failed: 'Fehler beim Zusammenfugen der Videos.',
moveUpAria: 'Nach oben verschieben',
moveDownAria: 'Nach unten verschieben',
removeAria: 'Aus Liste entfernen'
}, },
mergeGroup: { mergeGroup: {
btn: 'Zusammenfugen & Splitten', btn: 'Zusammenfugen & Splitten',

View File

@ -457,7 +457,10 @@ const UI_TEXT_EN = {
merging: 'Merging...', merging: 'Merging...',
merge: 'Merge', merge: 'Merge',
success: 'Videos merged successfully!', success: 'Videos merged successfully!',
failed: 'Failed to merge videos.' failed: 'Failed to merge videos.',
moveUpAria: 'Move up',
moveDownAria: 'Move down',
removeAria: 'Remove from list'
}, },
mergeGroup: { mergeGroup: {
btn: 'Merge & Split', btn: 'Merge & Split',

View File

@ -1639,9 +1639,9 @@ function renderMergeFiles(): void {
<div class="file-order">${index + 1}</div> <div class="file-order">${index + 1}</div>
<div class="file-name" title="${file}">${name}</div> <div class="file-name" title="${file}">${name}</div>
<div class="file-actions"> <div class="file-actions">
<button type="button" class="file-btn" onclick="moveMergeFile(${index}, -1)" ${index === 0 ? 'disabled' : ''}>&#9650;</button> <button type="button" class="file-btn" aria-label="${escapeHtml(UI_TEXT.merge.moveUpAria)}" title="${escapeHtml(UI_TEXT.merge.moveUpAria)}" onclick="moveMergeFile(${index}, -1)" ${index === 0 ? 'disabled' : ''}>&#9650;</button>
<button type="button" class="file-btn" onclick="moveMergeFile(${index}, 1)" ${index === mergeFiles.length - 1 ? 'disabled' : ''}>&#9660;</button> <button type="button" class="file-btn" aria-label="${escapeHtml(UI_TEXT.merge.moveDownAria)}" title="${escapeHtml(UI_TEXT.merge.moveDownAria)}" onclick="moveMergeFile(${index}, 1)" ${index === mergeFiles.length - 1 ? 'disabled' : ''}>&#9660;</button>
<button type="button" class="file-btn remove" onclick="removeMergeFile(${index})">x</button> <button type="button" class="file-btn remove" aria-label="${escapeHtml(UI_TEXT.merge.removeAria)}" title="${escapeHtml(UI_TEXT.merge.removeAria)}" onclick="removeMergeFile(${index})">x</button>
</div> </div>
</div> </div>
`; `;

View File

@ -3083,10 +3083,22 @@ select option {
color: var(--text); color: var(--text);
} }
.file-item .file-btn:focus-visible {
outline: none;
border-radius: 4px;
box-shadow: 0 0 0 2px rgba(145, 70, 255, 0.65);
color: var(--text);
}
.file-item .file-btn.remove:hover { .file-item .file-btn.remove:hover {
color: var(--error); color: var(--error);
} }
.file-item .file-btn.remove:focus-visible {
box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.65);
color: var(--error);
}
.merge-actions { .merge-actions {
display: flex; display: flex;
gap: 10px; gap: 10px;