Files
2026-07-22 21:28:50 +02:00

94 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Project notes for agents
## Project snapshot
- **Repo name:** `juri-merger`
- **App name/branding:** `beA-Edit`, published by Nominandum GmbH.
- **Tech stack:** SvelteKit + Svelte 5 (runes) + TypeScript + Vite + Tailwind v4 (CSS-first).
- **UI system:** shadcn-svelte (style `nova`, lucide icons) layered on a custom "nom" theme via CSS variables in `src/routes/layout.css`.
- **Core purpose:** upload one or more ZIP files, extract relevant PDFs/images, preview them, optionally reorder attachments, and download a merged PDF.
- **Active branch:** `features/shadcn` (shadcn-svelte integration in progress).
## Main user flow
1. User adds ZIP files via drag/drop or file picker (`ZipDropzone`).
2. `+page.svelte` starts async extraction for each file (tracked via `archiveGeneration` so stale in-flight extractions are discarded on bulk delete).
3. Each ZIP is processed into one or more `ProcessedZipArchive` entries.
4. `ProcessedZipArchiveEditor` shows thumbnails, allows reordering, and can download the merged PDF.
5. `AttachmentPreview` renders image previews directly and PDF previews via `pdfjs-dist`.
6. A fixed bottom-right settings drawer (`<details>`) exposes **export all** and **delete all** archive actions plus the thumbnail-width slider.
## Important source files
- `src/routes/+page.svelte` — top-level page state, file selection, localStorage-backed thumbnail width, async ZIP processing, bulk export/delete, settings drawer.
- `src/routes/+layout.svelte` — app shell: header with logo and footer with Nominandum GmbH legal/imprint block.
- `src/routes/layout.css` — Tailwind v4 entrypoint; imports `tw-animate-css`, `shadcn-svelte/tailwind.css`, Geist + Nunito fonts; defines the semantic token layer (`--background`, `--primary`, `--secondary`, `--accent`, `--destructive`, `--radius`, etc.) mapping shadcn tokens onto the nom palette, including a `.dark` override.
- `src/lib/zip-processing.ts` — archive extraction, recursive nested ZIP handling, metadata ordering, PDF merge/export, image conversion.
- `src/lib/services/zip-inflating.service.ts` — thin wrapper around `fflate` unzip.
- `src/lib/services/xml-reading.service.ts` — parses XJustiz XML metadata (`sender`, `receiver`, `documentNames`).
- `src/lib/components/ZipDropzone.svelte` — file picker + drag/drop ZIP intake.
- `src/lib/components/ProcessedZipArchiveEditor.svelte` — archive editor (name input, drag reordering, per-archive PDF download, selection mode + sub-document management, export-mode switch).
- `src/lib/components/SubDocumentEditor.svelte` — sub-document block editor (editable name, count, dissolve action, draggable header for block reorder, internal horizontal reorderable attachment list).
- `src/lib/components/AttachmentPreview.svelte` — preview generation for images/PDFs.
- `src/lib/components/ui/button.svelte` — shadcn-backed button atom (see "Button system" below).
- `src/lib/components/ui/card/` — shadcn card composition (`Root/Content/Header/Title/Description/Footer/Action`, re-exported as `Card.*`).
- `src/lib/actions/ripple.ts` — Svelte action that renders a click ripple animation on an element.
- `src/lib/components/icons/` — hand-rolled SVG icon components (`IconSettings`, `IconFile`, `IconMenu`, `IconNeedle`, `IconOffice`, `IconPerson`, `IconTag`, `IconTrash`, `IconChain`, `IconUnknown`). If an icon is missing, report it, and we see if we can create
- `src/lib/utils.ts` — shared `cn()` helper (clsx + tailwind-merge) and `WithElementRef`/`WithoutChild` typing helpers used by shadcn components.
## Button system
`src/lib/components/ui/button.svelte` is a shadcn-sveltestyle primitive adapted to the nom theme:
- Built with `tailwind-variants` (`buttonVariants`) and the shared `cn()` helper.
- Variants: `primary`, `secondary` (gradient `secondary → --secondary-end`), `bordered`, `tertiary`, `success`.
- Sizes: `standard` (h-8, rounded-16px), `large` (h-12, rounded-24px).
- Renders either a `<button>` or an `<a>` (when `href` is set); both apply the `use:ripple` action.
- Accepts an optional `icon` prop (a Svelte component) rendered after `children`.
- `ButtonProps` merges `HTMLButtonAttributes` + `HTMLAnchorAttributes` with `WithElementRef` and `variant`/`size`/`icon`.
- Used across the editor, settings drawer, and the throwaway test buttons on the home `<section>` (still present on the branch).
## ZIP/PDF processing details
- ZIP entries are filtered to ignore macOS metadata (`__MACOSX`, `.DS_Store`, `._*`).
- Relevant attachments are PDFs and common image formats.
- Nested ZIP archives are processed recursively.
- `xjustiz_nachricht.xml` is used to derive archive naming and ordering.
- Ordering prefers document names from metadata before falling back to original attachment order.
- PDF merging uses `pdf-lib`; images are embedded as PNG/JPG, with browser-side canvas conversion for other image types.
- **Sub-documents:** a `ProcessedZipArchive` now has `attachments` ("loose") plus an ordered `subDocuments: SubDocument[]` list. Each `SubDocument` is a named, ordered subset of `ZipAttachment`s that live alongside the loose ones. Sub-documents are created on demand by the user (selection mode in the editor) — when none exist, the archive behaves exactly as before.
- The merge loop is shared via `mergeAttachments(attachments)`; `mergeProcessedZipArchive` flattens the archive via `flattenArchiveForMerge` (sub-documents first, then loose) so backwards compatibility holds.
- Pure helpers in `zip-processing.ts`: `createSubDocument`, `moveSubDocument`, `moveAttachmentInPlace`, `moveAttachmentIntoSubDocument`, `removeAttachmentFromSubDocument`, `dissolveSubDocument`, `flattenArchiveForMerge`, `buildArchiveExport(archive, 'single' | 'separate')`. Cross-list moves preserve the total attachment count invariant.
- **Export modes:** `single` flips the whole archive into one PDF (sub-docs flattened first); `separate` produces one PDF per non-empty sub-document (`{archiveName} - {subName}.pdf`) plus one for any residual loose attachments.
## UI/state details
- Thumbnail width is stored in `localStorage` under `thumbnailWidth` (key constant `THUMBNAIL_WIDTH_STORAGE_KEY`) and clamped to `100..400`; hydration is gated by a `thumbnailWidthHydrated` flag so the initial render does not fight `onMount`.
- Processing progress is shown as a count of pending ZIP files (`pendingZipCount`).
- The editor supports manual attachment reordering via drag-and-drop.
- The settings drawer contains: "Alle ZIP-Archive als PDF exportieren", "Alle ZIP-Archive löschen", and the thumbnail-width range input.
- Bulk delete bumps `archiveGeneration` so otherwise-orphaned async extractions no-op instead of re-populating state.
- **Sub-document editing (`ProcessedZipArchiveEditor.svelte`):**
- An "Auswählen" / "Fertig" toggle in the header puts the editor into selection mode. Only then are checkboxes rendered on each loose thumbnail (wrapped in a `<label>` for keyboard operability — Tab + Space); in normal mode the editor looks identical to today. `Esc` exits selection mode and clears the selection. Drag-to-reorder is suspended while in selection mode.
- An inline action bar with "Teildokument erstellen" appears whenever `selectionMode && selectedPaths.size > 0`. Creating a sub-document removes the selected attachments from the loose list, appends a new `SubDocument` block (named "Teildokument N"), clears the selection, and keeps selection mode on.
- Sub-documents render below the loose list as a vertical stack of `SubDocumentEditor` blocks. Each block has an editable name, a count, an "Auflösen" action (returns its attachments to the end of the loose list), a draggable header (`::`) to reorder the block, and its own horizontal reorderable attachment list.
- Drag-and-drop is generalised: HTML5 DnD payloads use MIME type `application/x-juri-merger-attachment` (carrying a `AttachmentLocation` of `{ kind: 'loose', index }` or `{ kind: 'subDocument', id, index }`) for attachment moves, and `application/x-juri-merger-block` for reordering whole sub-document blocks. Supported moves: loose↔loose, loose→sub, sub→loose, sub attachment↔sub attachment (same or different sub), and sub-document block↔sub-document block.
- Export control: with no sub-documents, the existing single "PDF herunterladen" button behaves unchanged. With sub-documents present, a segmented control ("Eine PDF" / "Getrennt") lets the user choose the export mode; "Eine PDF" downloads one flattened PDF, "Getrennt" downloads one PDF per sub-document sequentially.
- **`SubDocumentEditor.svelte`** is the new sub-document block component. It emits `onSubDocumentChange`, `onRemove`, `onAttachmentMove`, and block-level drag callbacks up to the parent; the parent stays the source of truth via `onArchiveChange`.
## Dependencies worth noting
- `fflate` for ZIP extraction
- `pdf-lib` for PDF generation/merging
- `pdfjs-dist` for PDF thumbnail previews
- `bits-ui`, `shadcn-svelte` (CLI/runtime), `clsx`, `tailwind-merge`, `class-variance-authority`, `tailwind-variants`, `tw-animate-css` for the shadcn-svelte UI layer
- `@lucide/svelte` and a set of local SVG icon components for iconography
- `@fontsource-variable/geist` font; custom `Nunito` variable font bundled under `src/lib/assets/`
- `@tailwindcss/vite`, `@tailwindcss/forms`, `@tailwindcss/typography` for styling
## shadcn-svelte configuration
- `components.json`: style `nova`, `iconLibrary` `lucide`, `baseColor` `neutral`, Tailwind CSS path `src/routes/layout.css`.
- Aliases: `components → $lib/components`, `ui → $lib/components/ui`, `utils → $lib/utils`, `hooks → $lib/hooks`, `lib → $lib`.
- `src/lib/hooks/` exists but is currently empty.
- Generated components live under `src/lib/components/ui/`; `button.svelte` is the canonical adapted example (custom variants + ripple + icon prop).
## Current working tree observations
- Branch is `features/shadcn`.
- `agents.md` is being updated to match the post-shadcn-integration state.
- `plan/shadcn-svelte-plan.md` tracks the in-progress migration (only `button` + `card` generated so far; broader UI replacement is still optional/incremental).
- Untracked: `plan/`, and several icons under `src/lib/components/icons/` (`IconChain`, `IconFile`, `IconMenu`, `IconNeedle`, `IconOffice`, `IconPerson`, `IconTag`, `IconTrash`, `IconUnknown`).
- Modified (uncommitted): `agents.md`, `src/lib/components/icons/IconSettings.svelte`, `src/lib/components/ui/button.svelte`, `src/routes/+page.svelte`, `.idea/workspace.xml`.
- `src/lib/services/` is now committed (was previously untracked).