diff --git a/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte b/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte index 8a280226..2c9b8511 100644 --- a/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte +++ b/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte @@ -1,7 +1,8 @@ -{#if files.size === 0} - -
- -
-{:else} -
+
+ +
+ + + {m.btn_back_to_overview()} + + + + {isMulti ? 'Neue Dokumente' : 'Neues Dokument'} + {#if isMulti} - (activeId = id)} - onRemove={removeFile} - /> + + + {m.bulk_count_pill({ count: files.size })} + + + {/if} +
-
- - - - -
+ +
+ +
+ {#if files.size === 0} + + + {:else} + +
+ {#if activeFile} + + {/if} +
{#if isMulti} - - + + (activeId = id)} + onRemove={removeFile} + /> + {/if} + {/if} +
+ + +
+ +
+ {#if isMulti} + + {#if activeFile} {/if} - - + {:else} - - {#if activeFile} -
-
- { - files.clear(); - activeId = null; - chunkProgress = undefined; - }} - /> + + +
-{/if} +
diff --git a/frontend/src/lib/components/document/BulkDropZone.svelte b/frontend/src/lib/components/document/BulkDropZone.svelte index 065159e3..a279ffc5 100644 --- a/frontend/src/lib/components/document/BulkDropZone.svelte +++ b/frontend/src/lib/components/document/BulkDropZone.svelte @@ -1,4 +1,6 @@ -
+
{ + 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)); + } + }} +>
{ - 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)); - } - }} + class={[ + 'flex w-full max-w-sm flex-col items-center gap-3 rounded-md border-2 border-dashed px-6 py-9 text-center transition-colors', + isDragging ? 'border-accent bg-accent/10' : 'border-accent/50 bg-white/[0.04]' + ].join(' ')} > -
+ +
-

PDF-Dateien hier ablegen

-

oder

+ + +

{m.bulk_drop_hint()}

+ + +

+ Für jede Datei wird ein eigenes Dokument erstellt.
+ Der Titel wird aus dem Dateinamen vorausgefüllt — + alle anderen Felder gelten für alle gemeinsam. +

+ + + + +

{m.bulk_drop_sub()}

diff --git a/frontend/src/lib/components/document/FileSwitcherStrip.svelte b/frontend/src/lib/components/document/FileSwitcherStrip.svelte index e7badb4d..eef08b87 100644 --- a/frontend/src/lib/components/document/FileSwitcherStrip.svelte +++ b/frontend/src/lib/components/document/FileSwitcherStrip.svelte @@ -1,9 +1,12 @@ -
    - {#each files as entry (entry.id)} -
  • - - -
  • - {/each} -
+ + +
+
    + {#each files as entry, i (entry.id)} +
  • + + +
  • + {/each} +
+
+ + +
diff --git a/frontend/src/lib/components/document/FileSwitcherStrip.svelte.spec.ts b/frontend/src/lib/components/document/FileSwitcherStrip.svelte.spec.ts index 86968e24..56fe281a 100644 --- a/frontend/src/lib/components/document/FileSwitcherStrip.svelte.spec.ts +++ b/frontend/src/lib/components/document/FileSwitcherStrip.svelte.spec.ts @@ -10,6 +10,7 @@ export interface FileEntry { file: File; title: string; status: 'idle' | 'error'; + previewUrl: string; } function makeFiles(n: number): FileEntry[] { @@ -17,7 +18,8 @@ function makeFiles(n: number): FileEntry[] { id: `id-${i}`, file: new File([''], `file${i}.pdf`), title: `File ${i}`, - status: 'idle' as const + status: 'idle' as const, + previewUrl: '' })); } @@ -65,7 +67,13 @@ describe('FileSwitcherStrip', () => { it('error chip has aria-label containing warning indicator', async () => { const files: FileEntry[] = [ - { id: 'e1', file: new File([''], 'bad.pdf'), title: 'Bad file', status: 'error' } + { + id: 'e1', + file: new File([''], 'bad.pdf'), + title: 'Bad file', + status: 'error', + previewUrl: '' + } ]; const { container } = render(FileSwitcherStrip, { files, @@ -85,7 +93,7 @@ describe('FileSwitcherStrip', () => { onSelect: vi.fn(), onRemove: vi.fn() }); - const firstBtn = container.querySelectorAll('[role="button"]')[0] as HTMLElement; + const firstBtn = container.querySelectorAll('[data-chip-id]')[0] as HTMLElement; firstBtn.focus(); await userEvent.keyboard('{ArrowRight}'); const focused = document.activeElement; diff --git a/frontend/src/lib/components/document/ScopeCard.svelte b/frontend/src/lib/components/document/ScopeCard.svelte index ebdbe82a..7eb6002d 100644 --- a/frontend/src/lib/components/document/ScopeCard.svelte +++ b/frontend/src/lib/components/document/ScopeCard.svelte @@ -1,4 +1,6 @@ -
+
{#if chunkProgress} {/if} -
+
diff --git a/frontend/src/routes/documents/new/+page.svelte b/frontend/src/routes/documents/new/+page.svelte index 753233b1..c4cb69f8 100644 --- a/frontend/src/routes/documents/new/+page.svelte +++ b/frontend/src/routes/documents/new/+page.svelte @@ -1,37 +1,11 @@ -
-
- - - - - {m.btn_back_to_overview()} - -

{m.doc_new_heading()}

-
- - -
+ diff --git a/frontend/src/routes/documents/new/page.svelte.spec.ts b/frontend/src/routes/documents/new/page.svelte.spec.ts index dcdfbdef..b22028bf 100644 --- a/frontend/src/routes/documents/new/page.svelte.spec.ts +++ b/frontend/src/routes/documents/new/page.svelte.spec.ts @@ -21,15 +21,14 @@ const baseData = { describe('New document page – sender prefill', () => { it('shows an empty sender input when no senderId is in the URL', async () => { - render(Page, { data: baseData, form: null }); + render(Page, { data: baseData }); const input = document.querySelector('#senderId-search'); expect(input?.value).toBe(''); }); it('shows the sender name in the typeahead input when initialSenderName is set', async () => { render(Page, { - data: { ...baseData, initialSenderId: 'p1', initialSenderName: 'Hans Müller' }, - form: null + data: { ...baseData, initialSenderId: 'p1', initialSenderName: 'Hans Müller' } }); const input = document.querySelector('#senderId-search'); expect(input?.value).toBe('Hans Müller'); @@ -37,8 +36,7 @@ describe('New document page – sender prefill', () => { it('sets the hidden senderId input to the prefilled ID', async () => { render(Page, { - data: { ...baseData, initialSenderId: 'p1', initialSenderName: 'Hans Müller' }, - form: null + data: { ...baseData, initialSenderId: 'p1', initialSenderName: 'Hans Müller' } }); const hidden = document.querySelector( 'input[type="hidden"][name="senderId"]' @@ -51,7 +49,7 @@ describe('New document page – sender prefill', () => { describe('New document page – receiver prefill', () => { it('shows no receiver chips when initialReceivers is empty', async () => { - render(Page, { data: baseData, form: null }); + render(Page, { data: baseData }); await expect.element(page.getByText('Anna Schmidt')).not.toBeInTheDocument(); }); @@ -62,7 +60,7 @@ describe('New document page – receiver prefill', () => { { id: 'p2', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' } ] }; - render(Page, { data, form: null }); + render(Page, { data }); await expect.element(page.getByText('Anna Schmidt')).toBeInTheDocument(); }); @@ -73,7 +71,7 @@ describe('New document page – receiver prefill', () => { { id: 'p2', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' } ] }; - render(Page, { data, form: null }); + render(Page, { data }); const hidden = document.querySelector('input[name="receiverIds"]'); expect(hidden?.value).toBe('p2'); });