feat: add ARIA labels, roles, and live regions across all views (A11Y-01)

Systematic accessibility pass: aria-label on icon-only buttons, role=dialog
and aria-modal on modals, role=tab/tablist on tab switchers, role=switch
on toggles, aria-live on dynamic status/error regions, aria-hidden on
decorative SVGs, aria-label on search inputs, and nav landmarks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-11 13:04:31 +00:00
parent 7fc170f50e
commit c273ec758f
8 changed files with 557 additions and 176 deletions

View File

@@ -580,6 +580,9 @@
<div class="flex items-center gap-3">
<button
@click="toggleWebhookEnabled"
role="switch"
:aria-checked="webhookConfig.enabled"
:aria-label="webhookConfig.enabled ? 'Disable webhooks' : 'Enable webhooks'"
class="w-10 h-6 rounded-full shrink-0 transition-colors relative"
:class="webhookConfig.enabled ? 'bg-orange-500' : 'bg-white/15'"
:title="webhookConfig.enabled ? 'Disable webhooks' : 'Enable webhooks'"
@@ -623,6 +626,9 @@
v-for="evt in webhookEventTypes"
:key="evt.id"
@click="toggleWebhookEvent(evt.id)"
role="checkbox"
:aria-checked="webhookConfig.events.includes(evt.id)"
:aria-label="evt.label"
class="flex items-center gap-3 p-3 rounded-lg border transition-colors text-left"
:class="webhookConfig.events.includes(evt.id)
? 'bg-orange-500/10 border-orange-500/30'
@@ -666,7 +672,7 @@
</div>
<!-- Webhook status message -->
<div v-if="webhookStatusMsg" class="mt-3 text-xs px-3 py-2 rounded-lg" :class="webhookStatusType === 'error' ? 'bg-red-500/15 text-red-300' : 'bg-green-500/15 text-green-300'">
<div v-if="webhookStatusMsg" role="status" aria-live="polite" class="mt-3 text-xs px-3 py-2 rounded-lg" :class="webhookStatusType === 'error' ? 'bg-red-500/15 text-red-300' : 'bg-green-500/15 text-green-300'">
{{ webhookStatusMsg }}
</div>
</div>
@@ -705,7 +711,7 @@
<button @click="confirmRestoreBackup(b.id)" class="glass-button glass-button-sm px-3 py-1.5 rounded text-xs text-orange-400" title="Restore">
Restore
</button>
<button @click="deleteBackup(b.id)" :disabled="deletingBackupId === b.id" class="glass-button glass-button-sm px-3 py-1.5 rounded text-xs text-red-400 disabled:opacity-50" title="Delete">
<button @click="deleteBackup(b.id)" :disabled="deletingBackupId === b.id" aria-label="Delete backup" class="glass-button glass-button-sm px-3 py-1.5 rounded text-xs text-red-400 disabled:opacity-50" title="Delete">
&times;
</button>
</div>
@@ -713,7 +719,7 @@
</div>
<!-- Backup status message -->
<div v-if="backupStatusMsg" class="mt-3 text-xs px-3 py-2 rounded-lg" :class="backupStatusType === 'error' ? 'bg-red-500/15 text-red-300' : 'bg-green-500/15 text-green-300'">
<div v-if="backupStatusMsg" role="status" aria-live="polite" class="mt-3 text-xs px-3 py-2 rounded-lg" :class="backupStatusType === 'error' ? 'bg-red-500/15 text-red-300' : 'bg-green-500/15 text-green-300'">
{{ backupStatusMsg }}
</div>
</div>
@@ -721,8 +727,8 @@
<!-- Create Backup Modal -->
<Teleport to="body">
<div v-if="showCreateBackupModal" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm" @click.self="showCreateBackupModal = false">
<div class="glass-card p-6 w-full max-w-md">
<h3 class="text-lg font-semibold text-white mb-4">Create Encrypted Backup</h3>
<div class="glass-card p-6 w-full max-w-md" role="dialog" aria-modal="true" aria-labelledby="create-backup-title">
<h3 id="create-backup-title" class="text-lg font-semibold text-white mb-4">Create Encrypted Backup</h3>
<div class="space-y-3">
<div>
<label class="text-xs text-white/50 block mb-1">Encryption Passphrase</label>
@@ -746,8 +752,8 @@
<!-- Restore Backup Modal -->
<Teleport to="body">
<div v-if="showRestoreModal" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm" @click.self="showRestoreModal = false">
<div class="glass-card p-6 w-full max-w-md">
<h3 class="text-lg font-semibold text-white mb-2">Restore Backup</h3>
<div class="glass-card p-6 w-full max-w-md" role="dialog" aria-modal="true" aria-labelledby="restore-backup-title">
<h3 id="restore-backup-title" class="text-lg font-semibold text-white mb-2">Restore Backup</h3>
<p class="text-sm text-red-400/80 mb-4">This will overwrite current node data. Make sure you have the correct passphrase.</p>
<div>
<label class="text-xs text-white/50 block mb-1">Encryption Passphrase</label>