This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<script lang="ts">
|
||||
import FileDropzone from '$lib/components/FileDropzone.svelte';
|
||||
import Button from '$lib/components/ui/button.svelte';
|
||||
import { downloadBlob } from '$lib/download';
|
||||
import { mergePdfFiles } from '$lib/pdf-processing';
|
||||
import { Trash2 } from '@lucide/svelte';
|
||||
|
||||
let pdfFiles: File[] = $state([]);
|
||||
let isProcessing = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
const handleFilesSelected = (files: File[]) => {
|
||||
pdfFiles = [...pdfFiles, ...files];
|
||||
error = null;
|
||||
};
|
||||
|
||||
const removeFile = (index: number) => {
|
||||
pdfFiles = pdfFiles.filter((_, i) => i !== index);
|
||||
};
|
||||
|
||||
const moveFile = (fromIndex: number, toIndex: number) => {
|
||||
if (toIndex < 0 || toIndex >= pdfFiles.length) return;
|
||||
const newFiles = [...pdfFiles];
|
||||
const [moved] = newFiles.splice(fromIndex, 1);
|
||||
newFiles.splice(toIndex, 0, moved);
|
||||
pdfFiles = newFiles;
|
||||
};
|
||||
|
||||
const mergePdfs = async () => {
|
||||
if (pdfFiles.length < 2) return;
|
||||
|
||||
isProcessing = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
downloadBlob(await mergePdfFiles(pdfFiles), 'zusammengefuegt.pdf');
|
||||
} catch (err) {
|
||||
console.error('Merge failed:', err);
|
||||
error = 'Fehler beim Zusammenfügen der PDFs.';
|
||||
} finally {
|
||||
isProcessing = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-4xl space-y-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-primary-900">PDFs zusammenfügen</h1>
|
||||
<p class="mt-2 text-sm text-primary-700">
|
||||
Fügen Sie mehrere PDF-Dateien zu einem einzigen Dokument zusammen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<FileDropzone onFilesSelected={handleFilesSelected} multiple={true} />
|
||||
|
||||
{#if pdfFiles.length > 0}
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold text-primary-900">
|
||||
{pdfFiles.length} Datei{pdfFiles.length === 1 ? '' : 'en'} ausgewählt
|
||||
</h2>
|
||||
<Button onclick={mergePdfs} disabled={isProcessing || pdfFiles.length < 2}>
|
||||
{isProcessing ? 'Wird zusammengefügt...' : 'PDFs zusammenfügen'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-800">
|
||||
{error}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="space-y-2">
|
||||
{#each pdfFiles as file, index}
|
||||
<div class="flex items-center gap-3 rounded-lg border border-primary-200 bg-white p-3">
|
||||
<span
|
||||
class="flex h-8 w-8 items-center justify-center rounded-full bg-primary/10 text-sm font-semibold text-primary"
|
||||
>
|
||||
{index + 1}
|
||||
</span>
|
||||
<span class="flex-1 truncate text-sm text-primary-900">{file.name}</span>
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
variant="tertiary"
|
||||
class="min-w-0 px-3"
|
||||
onclick={() => moveFile(index, index - 1)}
|
||||
disabled={index === 0}
|
||||
>
|
||||
↑
|
||||
</Button>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
class="min-w-0 px-3"
|
||||
onclick={() => moveFile(index, index + 1)}
|
||||
disabled={index === pdfFiles.length - 1}
|
||||
>
|
||||
↓
|
||||
</Button>
|
||||
<Button variant="tertiary" class="min-w-0 px-3" onclick={() => removeFile(index)}>
|
||||
<Trash2 class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user