feat: improve accessibility across the app

- add useDialogA11y hook: focus trap, Escape handling, and focus restore
  for all custom modal dialogs (Modal, ThemeSelector, Admin modals)
- add skip link, per-route document titles, and focus shift to main on
  SPA route changes
- make notification list items real buttons (keyboard operable) and show
  hover-only controls on keyboard focus
- close sidebar, dropdowns, and context menus with Escape, returning
  focus to their triggers; mark closed mobile sidebar inert
- associate missing form labels (2FA code, DateTimePicker), add missing
  aria-labels on icon-only buttons, aria-expanded/controls on toggles,
  aria-pressed on theme tiles, scope=col on table headers
- announce loading states via role=status
- respect prefers-reduced-motion
- new i18n keys: common.skipToContent/previous/next, admin.userActions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 22:31:43 +02:00
co-authored by Claude Fable 5
parent 6a312ba055
commit 762d6c54c8
21 changed files with 328 additions and 105 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ export default function Dashboard() {
if (loading) {
return (
<div className="flex items-center justify-center py-20">
<div className="flex items-center justify-center py-20" role="status" aria-label={t('common.loading')}>
<Loader2 size={32} className="animate-spin text-th-accent" />
</div>
);