- BulkDropZone: link description <p> to drop zone region via aria-describedby - UploadSaveBar: add explicit aria-valuenow/aria-valuemin/aria-valuemax to <progress> element for consistent screen reader support across browsers - FileSwitcherStrip: add non-color error indicator (red !) to error chips so error state is not communicated by color alone (WCAG 1.4.1) - BulkDocumentEditLayout: comment explaining why raw fetch is used instead of a SvelteKit form action (chunked FormData with per-chunk progress tracking) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.1 KiB
Svelte
81 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import { m } from '$lib/paraglide/messages.js';
|
|
|
|
let {
|
|
onFilesAdded
|
|
}: {
|
|
onFilesAdded: (files: File[]) => void;
|
|
} = $props();
|
|
|
|
let isDragging = $state(false);
|
|
</script>
|
|
|
|
<div
|
|
role="region"
|
|
aria-label={m.bulk_drop_zone_label()}
|
|
aria-describedby="bulk-drop-desc"
|
|
data-testid="bulk-drop-zone"
|
|
class="flex flex-1 flex-col items-center justify-center p-6"
|
|
ondragover={(e) => {
|
|
e.preventDefault();
|
|
isDragging = true;
|
|
}}
|
|
ondragleave={() => (isDragging = false)}
|
|
ondrop={(e) => {
|
|
e.preventDefault();
|
|
isDragging = false;
|
|
if (e.dataTransfer && e.dataTransfer.files.length > 0) {
|
|
onFilesAdded(Array.from(e.dataTransfer.files));
|
|
}
|
|
}}
|
|
>
|
|
<div
|
|
class={[
|
|
'flex w-full max-w-xl flex-col items-center gap-5 rounded-md border-2 border-dashed px-12 py-16 text-center transition-colors',
|
|
isDragging ? 'border-accent bg-accent/10' : 'border-accent/50 bg-white/[0.04]'
|
|
].join(' ')}
|
|
>
|
|
<!-- Circular mint icon -->
|
|
<div class="flex h-20 w-20 items-center justify-center rounded-full bg-accent text-primary">
|
|
<svg
|
|
width="32"
|
|
height="32"
|
|
viewBox="0 0 32 32"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
aria-hidden="true"
|
|
>
|
|
<polygon
|
|
fill="currentColor"
|
|
points="6 12.5 16 2 26 12.5 24.5714286 14 16.999 6.049 17 30 15 30 14.999 6.051 7.42857143 14"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
|
|
<!-- Serif title -->
|
|
<p class="font-serif text-base font-bold text-ink">{m.bulk_drop_hint()}</p>
|
|
|
|
<!-- Sub description -->
|
|
<p id="bulk-drop-desc" class="text-sm leading-relaxed text-ink-2">{m.bulk_drop_desc()}</p>
|
|
|
|
<!-- CTA button -->
|
|
<label
|
|
class="flex min-h-[44px] cursor-pointer items-center rounded-sm bg-primary px-6 py-2 text-xs font-bold tracking-widest text-primary-fg uppercase transition-opacity hover:opacity-90"
|
|
>
|
|
{m.bulk_select_files()}
|
|
<input
|
|
type="file"
|
|
multiple
|
|
accept="application/pdf"
|
|
class="sr-only"
|
|
onchange={(e) => {
|
|
const files = Array.from(e.currentTarget.files ?? []);
|
|
if (files.length > 0) onFilesAdded(files);
|
|
}}
|
|
/>
|
|
</label>
|
|
|
|
<!-- Format hint -->
|
|
<p class="text-xs text-ink-3">{m.bulk_drop_sub()}</p>
|
|
</div>
|
|
</div>
|