From 1c6d9cce0f27d71c1af5df759272b4b2296df8b4 Mon Sep 17 00:00:00 2001 From: rehlert Date: Mon, 15 Jun 2026 20:52:57 +0200 Subject: [PATCH] adds buttons to export and delete all zips --- src/routes/+page.svelte | 126 ++++++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 31 deletions(-) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 4af9325..d60f7a7 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -3,7 +3,7 @@ import Card from "$lib/components/Card.svelte"; import ProcessedZipArchiveEditor from "$lib/components/ProcessedZipArchiveEditor.svelte"; import ZipDropzone from "$lib/components/ZipDropzone.svelte"; - import {extractZipArchives, type ProcessedZipArchive} from "$lib/zip-processing"; + import {extractZipArchives, mergeProcessedZipArchive, type ProcessedZipArchive} from "$lib/zip-processing"; const THUMBNAIL_WIDTH_STORAGE_KEY = "thumbnailWidth"; @@ -12,6 +12,7 @@ let pendingZipCount = $state(0); let thumbnailWidth = $state(200); let thumbnailWidthHydrated = $state(false); + let archiveGeneration = 0; const clampThumbnailWidth = (value: number) => Math.min(400, Math.max(100, value)); @@ -37,24 +38,49 @@ localStorage.setItem(THUMBNAIL_WIDTH_STORAGE_KEY, String(thumbnailWidth)); }); + const toArrayBuffer = (bytes: Uint8Array) => { + const copy = new Uint8Array(bytes.byteLength); + copy.set(bytes); + return copy.buffer; + }; + + const downloadPdfBytes = (bytes: Uint8Array, fileName: string) => { + const pdfBlob = new Blob([toArrayBuffer(bytes)], {type: "application/pdf"}); + const objectUrl = URL.createObjectURL(pdfBlob); + const downloadLink = document.createElement("a"); + + downloadLink.href = objectUrl; + downloadLink.download = fileName.toLowerCase().endsWith(".pdf") ? fileName : `${fileName}.pdf`; + downloadLink.rel = "noopener"; + downloadLink.click(); + window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1000); + }; + const handleFilesSelected = (files: File[]) => { selectedZipFiles = [...selectedZipFiles, ...files]; for (const file of files) { - void processZipFile(file); + void processZipFile(file, archiveGeneration); } }; - const processZipFile = async (file: File) => { + const processZipFile = async (file: File, generation: number) => { pendingZipCount += 1; try { const processedZipArchives = await extractZipArchives(file); + + if (generation !== archiveGeneration) { + return; + } + processedZipFiles = [...processedZipFiles, ...processedZipArchives]; } catch (error) { console.error(`Failed to process ${file.name}`, error); } finally { - pendingZipCount -= 1; + if (generation === archiveGeneration) { + pendingZipCount -= 1; + } } }; @@ -63,12 +89,77 @@ existingIndex === index ? archive : existingArchive, ); }; + + const exportAllZipArchivesAsPdf = async () => { + for (const archive of processedZipFiles) { + try { + const mergedBytes = await mergeProcessedZipArchive(archive); + downloadPdfBytes(mergedBytes, archive.name); + } catch (error) { + console.error(`Failed to export archive ${archive.name}`, error); + } + } + }; + + const deleteAllZipArchives = () => { + archiveGeneration += 1; + selectedZipFiles = []; + processedZipFiles = []; + pendingZipCount = 0; + }; {#snippet content()} {#if selectedZipFiles.length === 0} {:else} +
+ + Settings + ⚙️ + + +
+
+
+ + + +
+ + +
+
+
{#if pendingZipCount > 0} @@ -96,33 +187,6 @@

beA-Edit

- -
- - Settings - ⚙️ - - -
- -
-
-