wordeck/apps/web/src/lib/components/ToastStack.svelte
Till JS fd86d968a4 Phase 9h: A11y-Pass
Globaler :focus-visible-Outline (var(--color-primary), 2px) — Tailwind 4
strippt die Browser-Defaults, ohne Fokus-Ring sind Tastatur-Nutzer blind.
.sr-only-Utility (Standard-Rezept) und .skip-link in app.css. prefers-
reduced-motion: schaltet alle Transitions/Animationen auf 0.01ms.

Layout: Skip-Link "Zum Inhalt springen" → #main, main bekommt tabindex="-1"
und id, html-lang wird via $effect reaktiv mit i18n.current synchronisiert
(Initial-SSR rendert "de", Browser zieht nach).

Header: nav-aria-label aus i18n (common.main_nav), Locale-Switcher-Label
aus common.language_switcher. ToastStack: role=region + aria-live=polite,
einzelne Toasts role=alert (error) bzw. status (success/warning), Schließen-
Button-Label i18n-konform.

Hover-only Delete-Buttons (Decks-Liste, Deck-Detail-Karten) bekommen
focus-visible:opacity-100 — bisher waren sie für Tastatur-Nutzer
unsichtbar. opacity-0 statt hidden, damit Tab-Order intakt bleibt.

svelte-check 379 files 0 errors, prod-Build sauber.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:24:33 +02:00

34 lines
1.1 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts">
import { toasts } from '$lib/stores/toasts.svelte.ts';
import { i18n, t } from '$lib/i18n/index.svelte.ts';
const closeLabel = $derived(i18n.current === 'en' ? 'Close' : 'Schließen');
</script>
{#if toasts.items.length > 0}
<div
class="fixed bottom-4 right-4 z-50 flex flex-col gap-2"
role="region"
aria-live="polite"
aria-label={t('common.notifications')}
>
{#each toasts.items as t (t.id)}
<div
class="flex items-start gap-3 rounded-lg px-4 py-3 shadow-lg max-w-sm border bg-[var(--color-card)] border-[var(--color-border)]"
class:text-[var(--color-success)]={t.kind === 'success'}
class:text-[var(--color-warning)]={t.kind === 'warning'}
class:text-[var(--color-danger)]={t.kind === 'error'}
role={t.kind === 'error' ? 'alert' : 'status'}
>
<span class="flex-1 text-sm">{t.message}</span>
<button
class="text-[var(--color-muted)] hover:text-[var(--color-fg)] text-lg leading-none"
onclick={() => toasts.dismiss(t.id)}
aria-label={closeLabel}
>
×
</button>
</div>
{/each}
</div>
{/if}