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>
156 lines
4.9 KiB
Svelte
156 lines
4.9 KiB
Svelte
<script lang="ts">
|
|
import { untrack } from 'svelte';
|
|
import TagInput, { type Tag } from '$lib/components/TagInput.svelte';
|
|
import FieldLabelBadge from './FieldLabelBadge.svelte';
|
|
import { m } from '$lib/paraglide/messages.js';
|
|
|
|
let {
|
|
tags = $bindable<Tag[]>([]),
|
|
currentTitle = $bindable(''),
|
|
documentLocation = $bindable(''),
|
|
archiveBox = $bindable(''),
|
|
archiveFolder = $bindable(''),
|
|
initialTitle = '',
|
|
initialSummary = '',
|
|
titleRequired = false,
|
|
suggestedTitle = '',
|
|
hideTitle = false,
|
|
editMode = false
|
|
}: {
|
|
tags?: Tag[];
|
|
currentTitle?: string;
|
|
documentLocation?: string;
|
|
archiveBox?: string;
|
|
archiveFolder?: string;
|
|
initialTitle?: string;
|
|
initialSummary?: string;
|
|
titleRequired?: boolean;
|
|
suggestedTitle?: string;
|
|
hideTitle?: boolean;
|
|
editMode?: boolean;
|
|
} = $props();
|
|
|
|
// currentTitle seeds from initialTitle once at mount; subsequent edits flow
|
|
// through the oninput handler that flips titleDirty.
|
|
let titleDirty = $state(false);
|
|
currentTitle = untrack(() => initialTitle);
|
|
const titleValue = $derived(titleDirty ? currentTitle : suggestedTitle || currentTitle);
|
|
</script>
|
|
|
|
<div class="rounded-sm border border-line bg-surface p-6 shadow-sm">
|
|
<h2 class="mb-5 text-xs font-bold tracking-widest text-ink-3 uppercase">
|
|
{m.doc_section_description()}
|
|
</h2>
|
|
|
|
<div class="space-y-5">
|
|
{#if !hideTitle}
|
|
<!-- Titel (required) -->
|
|
<div>
|
|
<label for="title" class="mb-1 block text-sm font-medium text-ink-2"
|
|
>{m.form_label_title()}{#if titleRequired}
|
|
*{/if}</label
|
|
>
|
|
<input
|
|
id="title"
|
|
type="text"
|
|
name="title"
|
|
value={titleValue}
|
|
oninput={(e) => {
|
|
currentTitle = (e.target as HTMLInputElement).value;
|
|
titleDirty = true;
|
|
}}
|
|
required={titleRequired}
|
|
class="block w-full rounded border border-line p-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
/>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Optional divider -->
|
|
<div class="my-3 flex items-center gap-2">
|
|
<div class="flex-1 border-t border-line"></div>
|
|
<span class="text-xs font-bold tracking-widest text-ink-3 uppercase"
|
|
>{m.label_optional()}</span
|
|
>
|
|
<div class="flex-1 border-t border-line"></div>
|
|
</div>
|
|
|
|
<!-- Schlagworte (optional) -->
|
|
<div>
|
|
<p class="mb-1 block text-sm font-medium text-ink-2">
|
|
{m.form_label_tags()}
|
|
{#if editMode}<FieldLabelBadge variant="additive" />{/if}
|
|
</p>
|
|
<TagInput bind:tags={tags} />
|
|
<input type="hidden" name="tags" value={tags.map((t) => t.name).join(',')} />
|
|
</div>
|
|
|
|
{#if !editMode}
|
|
<!-- Inhalt (optional) — not bulk-editable. -->
|
|
<div>
|
|
<label for="summary" class="mb-1 block text-sm font-medium text-ink-2"
|
|
>{m.form_label_content()}</label
|
|
>
|
|
<textarea
|
|
id="summary"
|
|
name="summary"
|
|
rows="5"
|
|
placeholder={m.form_placeholder_content()}
|
|
class="block w-full rounded border border-line p-2 font-serif text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
>{initialSummary}</textarea
|
|
>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Aufbewahrungsort (optional) -->
|
|
<div data-testid="description-document-location">
|
|
<label for="documentLocation" class="mb-1 block text-sm font-medium text-ink-2"
|
|
>{m.form_label_archive_location()}
|
|
{#if editMode}<FieldLabelBadge variant="replace" />{/if}
|
|
</label>
|
|
<input
|
|
id="documentLocation"
|
|
type="text"
|
|
name="documentLocation"
|
|
bind:value={documentLocation}
|
|
placeholder={m.form_placeholder_archive_location()}
|
|
class="block w-full rounded border border-line p-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
/>
|
|
<p class="mt-1 text-xs text-ink-3">{m.form_helper_archive_location()}</p>
|
|
</div>
|
|
|
|
{#if editMode}
|
|
<!-- Karton (only in editMode — bulk-editable replace) -->
|
|
<div data-testid="description-archive-box">
|
|
<label for="archiveBox" class="mb-1 block text-sm font-medium text-ink-2">
|
|
{m.form_label_archive_box()}
|
|
<FieldLabelBadge variant="replace" />
|
|
</label>
|
|
<input
|
|
id="archiveBox"
|
|
type="text"
|
|
name="archiveBox"
|
|
bind:value={archiveBox}
|
|
class="block w-full rounded border border-line p-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
/>
|
|
<p class="mt-1 text-xs text-ink-3">{m.form_helper_archive_box()}</p>
|
|
</div>
|
|
|
|
<!-- Mappe (only in editMode — bulk-editable replace) -->
|
|
<div data-testid="description-archive-folder">
|
|
<label for="archiveFolder" class="mb-1 block text-sm font-medium text-ink-2">
|
|
{m.form_label_archive_folder()}
|
|
<FieldLabelBadge variant="replace" />
|
|
</label>
|
|
<input
|
|
id="archiveFolder"
|
|
type="text"
|
|
name="archiveFolder"
|
|
bind:value={archiveFolder}
|
|
class="block w-full rounded border border-line p-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
/>
|
|
<p class="mt-1 text-xs text-ink-3">{m.form_helper_archive_folder()}</p>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</div>
|