fix(bulk-edit): a11y + i18n hardening (Leonie blockers 1–4 + quick concerns)
B1 — i18n the archive-box / archive-folder labels and add helper text.
Karton/Mappe were hardcoded German and broke EN/ES locales (WCAG 3.1.2).
B2 — drop the hardcoded German aria-label on the onboarding callout.
role="note" + the visible localised text is self-describing; the redundant
label was overriding the translated content for AT users on EN/ES.
B3 — Escape clears the bulk selection while the bar is visible. Adds an
"Esc: Auswahl aufheben" hint visible at ≥ sm (WCAG 2.1.1).
B4 — /documents and /enrich reserve pb-32 when the bulk-selection bar is
visible so it doesn't occlude the last row or pagination (WCAG 1.4.10).
Folded in three Leonie quick-concerns:
- C5: badge text-[10px] → text-[11px], raw text-gray-600 →
design-token text-ink-2 (dark-mode safe)
- C7: aria-live="polite" on bulk-selection-count
- C11: "Alles aufheben" → "Auswahl aufheben" (DE/EN/ES) — disambiguates
from "discard the operation entirely"
Refs #225, PR #331
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { bulkSelectionStore } from '$lib/stores/bulkSelection.svelte';
|
||||
let { canWrite }: { canWrite: boolean } = $props();
|
||||
|
||||
const count = $derived(bulkSelectionStore.size);
|
||||
const visible = $derived(canWrite && count > 0);
|
||||
|
||||
function openBulkEdit() {
|
||||
goto('/documents/bulk-edit');
|
||||
@@ -14,16 +15,37 @@ function openBulkEdit() {
|
||||
function clearAll() {
|
||||
bulkSelectionStore.clear();
|
||||
}
|
||||
|
||||
// Escape clears the selection — keyboard escape hatch when the user has
|
||||
// drilled into a 50-row selection and wants to bail without Tab-ing through
|
||||
// the whole footer (WCAG 2.1.1).
|
||||
function onEscape(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape' && visible) {
|
||||
clearAll();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if canWrite && count > 0}
|
||||
<svelte:window onkeydown={onEscape} />
|
||||
|
||||
{#if visible}
|
||||
<div
|
||||
data-testid="bulk-selection-bar"
|
||||
class="fixed right-0 bottom-0 left-0 z-30 flex items-center justify-between border-t border-line bg-surface px-4 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] shadow-[0_-2px_8px_rgba(0,0,0,0.06)] sm:px-6"
|
||||
class="fixed right-0 bottom-0 left-0 z-30 flex items-center justify-between gap-3 border-t border-line bg-surface px-4 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] shadow-[0_-2px_8px_rgba(0,0,0,0.06)] sm:px-6"
|
||||
>
|
||||
<span class="font-sans text-sm font-medium text-ink" data-testid="bulk-selection-count">
|
||||
{m.bulk_edit_n_selected({ count })}
|
||||
</span>
|
||||
<div class="flex items-baseline gap-3">
|
||||
<span
|
||||
class="font-sans text-sm font-medium text-ink"
|
||||
data-testid="bulk-selection-count"
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
>
|
||||
{m.bulk_edit_n_selected({ count })}
|
||||
</span>
|
||||
<span class="hidden font-sans text-xs text-ink-3 sm:inline">
|
||||
{m.bulk_edit_clear_hint_keyboard()}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
@@ -31,7 +53,7 @@ function clearAll() {
|
||||
class="inline-flex min-h-[44px] items-center px-4 py-2 font-sans text-sm font-medium text-ink-2 transition-colors hover:text-ink"
|
||||
data-testid="bulk-clear-all"
|
||||
>
|
||||
{m.bulk_edit_clear_all()}
|
||||
{m.bulk_edit_clear_selection()}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user