fix(bulk-upload): spec-compliant split-panel layout with local PDF preview

Rewrites BulkDocumentEditLayout to match the spec exactly:
- Fixed viewport layout (same as DocumentEditLayout) filling viewport below nav
- Split panel visible in all states (N=0/1/≥2) — was fullscreen dark drop zone
- N=0: centered drop-zone-box in left panel; shared form visible but greyed out
- N≥1: real PDF preview via URL.createObjectURL (no server upload required)
- N≥2: FileSwitcherStrip at bottom of left panel; count pill + discard in topbar
- FileEntry gains previewUrl; blob URLs created on add, revoked on remove/destroy
- save() checks response.ok and marks failed files with status: 'error'
- BulkDropZone redesigned: spec-accurate box with circular mint icon, serif title
- FileSwitcherStrip: number badges, arrows, keyboard nav via data-chip-id selector
- ScopeCard, UploadSaveBar: hardcoded German replaced with Paraglide i18n keys
- +page.svelte simplified to bare component render (layout is self-contained)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-24 19:17:36 +02:00
committed by marcel
parent ef7a51fe30
commit 539842e849
8 changed files with 311 additions and 187 deletions

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
let {
variant,
count = 0,
@@ -13,24 +15,26 @@ let {
<div
data-testid="scope-card"
data-variant={variant}
class="rounded-sm border p-4
class="mb-3 rounded-sm border p-4
{variant === 'per-file'
? 'border-brand-mint bg-brand-mint/10'
: 'border-brand-sand bg-white'}"
? 'border-accent bg-accent-bg'
: 'border-line bg-surface'}"
>
{#if variant === 'shared'}
<div class="mb-3 flex items-center justify-between">
<span class="text-xs font-bold tracking-widest text-gray-400 uppercase">
Gilt für alle Dateien
<span class="text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.bulk_scope_shared_label({ count })}
</span>
<span
class="bg-brand-sand inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-xs font-bold text-brand-navy"
class="inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-accent px-1.5 text-xs font-bold text-primary"
>
{count}
</span>
</div>
{:else}
<p class="mb-3 text-xs font-bold tracking-widest text-brand-mint uppercase">Diese Datei</p>
<p class="mb-3 text-xs font-bold tracking-widest text-accent uppercase">
{m.bulk_scope_per_file_label()}
</p>
{/if}
{@render children?.()}
</div>