2 Commits
Author SHA1 Message Date
rehlert a450c6f5dd Merge branch 'features/shadcn' into develop
# Conflicts:
#	.idea/workspace.xml
#	agents.md
2026-07-22 22:18:59 +02:00
rehlert 47ed80bd24 adds impressum / privacy 2026-07-22 22:14:50 +02:00
5 changed files with 681 additions and 286 deletions
+46 -199
View File
@@ -3,40 +3,32 @@
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="CMakeProjectFlavorService">
<option name="flavorId" value="CMakePlainProjectFlavor" />
</component>
<component name="CMakeSettings">
<configurations />
</component>
<component name="ChangeListManager">
<list default="true" id="89f9fc3a-63ad-41cb-8d25-f07df352eb98" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agents.md" beforeDir="false" afterPath="$PROJECT_DIR$/agents.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/lib/components/ProcessedZipArchiveEditor.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib/components/ProcessedZipArchiveEditor.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/lib/zip-processing.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib/zip-processing.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/vite.config.ts" beforeDir="false" afterPath="$PROJECT_DIR$/vite.config.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/routes/+layout.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/src/routes/+layout.svelte" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="EmbeddingIndexingInfo">
<option name="cachedIndexableFilesCount" value="169" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="CSS File" />
<option value="TypeScript File" />
<option value="IconSettings" />
<option value="+page.svelte" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="features/shadcn" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="McpProjectServerCommands">
@@ -46,23 +38,23 @@
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="NextEditCompletionFeaturesState">
<decayedCancelled>
<entry key="MS100" value="1.7534270927402278" />
<entry key="MS500" value="3.946749409858449" />
<entry key="S2" value="10.803582735333821" />
<entry key="S5" value="15.959801828989763" />
<entry key="S10" value="18.60984028553002" />
<entry key="S30" value="20.774011757305356" />
<entry key="S60" value="21.423894438791837" />
<entry key="M2" value="22.530930014590602" />
<entry key="M5" value="32.256903842215344" />
<entry key="M10" value="49.10264974172939" />
<entry key="M15" value="59.99418378616175" />
<entry key="M30" value="75.77225940331346" />
<entry key="H1" value="86.24194464495858" />
<entry key="H2" value="92.30215756709606" />
<entry key="H4" value="95.56680916983069" />
<entry key="D1" value="98.41568550867962" />
<entry key="W1" value="98.91622423777348" />
<entry key="MS100" value="1.0" />
<entry key="MS500" value="1.000030264792808" />
<entry key="S2" value="1.0741710498535333" />
<entry key="S5" value="1.353259435419701" />
<entry key="S10" value="1.5943563202488056" />
<entry key="S30" value="1.8407798506380604" />
<entry key="S60" value="1.916982485499306" />
<entry key="M2" value="1.9733993920394513" />
<entry key="M5" value="2.54046111637059" />
<entry key="M10" value="3.820331613615542" />
<entry key="M15" value="4.711774035901717" />
<entry key="M30" value="6.035032387334216" />
<entry key="H1" value="6.920684152516748" />
<entry key="H2" value="7.4336791591637175" />
<entry key="H4" value="7.709839735759553" />
<entry key="D1" value="7.950638029700117" />
<entry key="W1" value="7.992923355805816" />
</decayedCancelled>
<decayedSelected>
<entry key="MS100" value="0.0" />
@@ -84,23 +76,23 @@
<entry key="W1" value="0.0" />
</decayedSelected>
<decayedShown>
<entry key="MS100" value="1.572917306599136" />
<entry key="MS500" value="3.853231737204187" />
<entry key="S2" value="10.722306786321894" />
<entry key="S5" value="15.90871853935142" />
<entry key="S10" value="18.579462450925384" />
<entry key="S30" value="20.762563658810205" />
<entry key="S60" value="21.41797857399968" />
<entry key="M2" value="22.5278009383226" />
<entry key="M5" value="32.254976079390616" />
<entry key="M10" value="49.101123585535056" />
<entry key="M15" value="59.99293373937006" />
<entry key="M30" value="75.77147145663449" />
<entry key="H1" value="86.24149819888382" />
<entry key="H2" value="92.30191941653102" />
<entry key="H4" value="95.56668611084393" />
<entry key="D1" value="98.41566442286562" />
<entry key="W1" value="98.91622121110338" />
<entry key="MS100" value="0.004910208494225893" />
<entry key="MS500" value="0.3453286512092814" />
<entry key="S2" value="0.8228647326727687" />
<entry key="S5" value="1.215480411189489" />
<entry key="S10" value="1.5106753869300364" />
<entry key="S30" value="1.8078926104734718" />
<entry key="S60" value="1.8997675156293707" />
<entry key="M2" value="1.9645730736920846" />
<entry key="M5" value="2.5367044075651064" />
<entry key="M10" value="3.818241287421449" />
<entry key="M15" value="4.710284232071638" />
<entry key="M30" value="6.034216617353951" />
<entry key="H1" value="6.9202526638434145" />
<entry key="H2" value="7.433456593321955" />
<entry key="H4" value="7.709726618573428" />
<entry key="D1" value="7.9506189104308005" />
<entry key="W1" value="7.992920617800578" />
</decayedShown>
</component>
<component name="ProjectColorInfo">{
@@ -118,21 +110,15 @@
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.MCP Project settings loaded": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.cidr.known.project.marker": "true",
"RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.readMode.enableVisualFormatting": "true",
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
"cidr.known.project.marker": "true",
"codeWithMe.voiceChat.enabledByDefault": "false",
"git-widget-placeholder": "features/shadcn",
"last_opened_file_path": "/home/rehlert/repos/pulley",
"list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"git-widget-placeholder": "develop",
"last_opened_file_path": "/home/rehlert/repos/juri-merger",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "pnpm",
"settings.editor.selected.configurable": "preferences.pluginManager",
@@ -148,18 +134,7 @@
<option name="presentableId" value="Default" />
<updated>1781169139290</updated>
<workItem from="1781169141138" duration="309000" />
<workItem from="1781251694220" duration="22281000" />
<workItem from="1781349431536" duration="3602000" />
<workItem from="1781378743498" duration="306000" />
<workItem from="1781534483559" duration="2103000" />
<workItem from="1781597500009" duration="2733000" />
<workItem from="1781621908149" duration="4463000" />
<workItem from="1781626468843" duration="1890000" />
<workItem from="1781673504756" duration="1513000" />
<workItem from="1781675346348" duration="3860000" />
<workItem from="1781797582572" duration="437000" />
<workItem from="1781844676215" duration="5049000" />
<workItem from="1782804485415" duration="4386000" />
<workItem from="1781251694220" duration="5262000" />
</task>
<task id="LOCAL-00001" summary="adapts styling of rvg.legal">
<option name="closed" value="true" />
@@ -169,111 +144,7 @@
<option name="project" value="LOCAL" />
<updated>1781256112218</updated>
</task>
<task id="LOCAL-00002" summary="adds dropzone to add zips">
<option name="closed" value="true" />
<created>1781257473070</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1781257473070</updated>
</task>
<task id="LOCAL-00003" summary="zips are getting extracted">
<option name="closed" value="true" />
<created>1781258303003</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1781258303003</updated>
</task>
<task id="LOCAL-00004" summary="parses xjustiz and orders attachments">
<option name="closed" value="true" />
<created>1781259433444</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1781259433444</updated>
</task>
<task id="LOCAL-00005" summary="renders preview of zips">
<option name="closed" value="true" />
<created>1781260304085</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1781260304085</updated>
</task>
<task id="LOCAL-00006" summary="design anpassungen">
<option name="closed" value="true" />
<created>1781261986439</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1781261986439</updated>
</task>
<task id="LOCAL-00007" summary="renders thumbnails">
<option name="closed" value="true" />
<created>1781263980882</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1781263980882</updated>
</task>
<task id="LOCAL-00008" summary="ignores mac special folders">
<option name="closed" value="true" />
<created>1781264183729</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1781264183729</updated>
</task>
<task id="LOCAL-00009" summary="handles zips in zip correctly">
<option name="closed" value="true" />
<created>1781264568851</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1781264568851</updated>
</task>
<task id="LOCAL-00010" summary="range settings">
<option name="closed" value="true" />
<created>1781267754325</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1781267754325</updated>
</task>
<task id="LOCAL-00011" summary="name generation improvement">
<option name="closed" value="true" />
<created>1781268046478</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1781268046478</updated>
</task>
<task id="LOCAL-00012" summary="The git changes introduce functionality to merge attachments from a processed ZIP archive into a single PDF file. Here is a summary of the changes: ### New Features - PDF Merging: Added the ability to merge multiple attachments (PDFs and images) from a processed ZIP archive into a single PDF document. - Image Conversion: Implemented automatic conversion of non-PNG images (like JPGs) to PNG format before embedding them into the merged PDF. ### File Changes - Dependencies: Added pdf-lib to the project's dependencies. - src/lib/zip-processing.ts: &#10; - Added mergeProcessedZipArchive to handle the core logic of creating a merged PDF. - Implemented helpers to embed PDF pages and convert/embed images. - Added toArrayBuffer and convertImageBytesToPng utilities for handling binary data and canvas-based image processing. &#10; - src/lib/components/ProcessedZipArchiveEditor.svelte: &#10; - Added a &quot;PDF herunterladen&quot; (Download PDF) button. - Added UI states to handle the merging process (loading state, error messages).&#10; - Integrated the mergeProcessedZipArchive function with the UI.&#10; - src/lib/components/AttachmentPreview.svelte: &#10; - Added a fix to ensure attachment.data is treated as a Uint8Array when loading PDF documents.">
<option name="closed" value="true" />
<created>1781350375505</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1781350375505</updated>
</task>
<task id="LOCAL-00013" summary="adds shadcn, removes skeleton, implements button after styleguide">
<option name="closed" value="true" />
<created>1781626078662</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1781626078662</updated>
</task>
<task id="LOCAL-00014" summary="adds icons">
<option name="closed" value="true" />
<created>1781845554523</created>
<option name="number" value="00014" />
<option name="presentableId" value="LOCAL-00014" />
<option name="project" value="LOCAL" />
<updated>1781845554523</updated>
</task>
<option name="localTasksCounter" value="15" />
<option name="localTasksCounter" value="2" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -281,34 +152,10 @@
</component>
<component name="UnityCheckinConfiguration" checkUnsavedScenes="true" />
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
<MESSAGE value="adapts styling of rvg.legal" />
<MESSAGE value="adds dropzone to add zips" />
<MESSAGE value="zips are getting extracted" />
<MESSAGE value="parses xjustiz and orders attachments" />
<MESSAGE value="renders preview of zips" />
<MESSAGE value="design anpassungen" />
<MESSAGE value="renders thumbnails" />
<MESSAGE value="ignores mac special folders" />
<MESSAGE value="handles zips in zip correctly" />
<MESSAGE value="range settings" />
<MESSAGE value="name generation improvement" />
<MESSAGE value="The git changes introduce functionality to merge attachments from a processed ZIP archive into a single PDF file. Here is a summary of the changes: ### New Features - PDF Merging: Added the ability to merge multiple attachments (PDFs and images) from a processed ZIP archive into a single PDF document. - Image Conversion: Implemented automatic conversion of non-PNG images (like JPGs) to PNG format before embedding them into the merged PDF. ### File Changes - Dependencies: Added pdf-lib to the project's dependencies. - src/lib/zip-processing.ts: &#10; - Added mergeProcessedZipArchive to handle the core logic of creating a merged PDF. - Implemented helpers to embed PDF pages and convert/embed images. - Added toArrayBuffer and convertImageBytesToPng utilities for handling binary data and canvas-based image processing. &#10; - src/lib/components/ProcessedZipArchiveEditor.svelte: &#10; - Added a &quot;PDF herunterladen&quot; (Download PDF) button. - Added UI states to handle the merging process (loading state, error messages).&#10; - Integrated the mergeProcessedZipArchive function with the UI.&#10; - src/lib/components/AttachmentPreview.svelte: &#10; - Added a fix to ensure attachment.data is treated as a Uint8Array when loading PDF documents." />
<MESSAGE value="adds shadcn, removes skeleton, implements button after styleguide" />
<MESSAGE value="adds icons" />
<option name="LAST_COMMIT_MESSAGE" value="adds icons" />
<option name="LAST_COMMIT_MESSAGE" value="adapts styling of rvg.legal" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
+117 -84
View File
@@ -1,93 +1,126 @@
# Project notes for agents
# Project Agent Guide
## 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).
## Project overview
## 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.
This repository contains **juri-merger**, a German-language SvelteKit application whose current UI is branded as **beA-Edit**. The main route lets users select or drag ZIP files in the browser. It currently displays the selected filenames; no server-side upload or archive-processing flow is present in this version.
## 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.
The application also contains German legal pages for the imprint and privacy policy.
## 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).
## Technology stack
## 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.
- SvelteKit 2
- Svelte 5 with runes mode forced for project source files
- TypeScript with strict mode
- Vite 8
- Tailwind CSS 4 through `@tailwindcss/vite`
- Skeleton 4 with a custom `nominandum` theme
- pnpm and `pnpm-lock.yaml`
- `@sveltejs/adapter-auto`
- Prettier with the Svelte and Tailwind plugins
## 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`.
Use **pnpm**, not npm or yarn, when installing packages or running project scripts.
## 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
## Commands
## 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).
```sh
pnpm install # Install dependencies
pnpm dev # Start the development server
pnpm build # Create a production build
pnpm preview # Preview the production build
pnpm check # Run Svelte and TypeScript diagnostics
pnpm check:watch # Run diagnostics in watch mode
pnpm lint # Check formatting with Prettier
pnpm format # Format the repository with Prettier
```
## 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).
There is currently no automated unit or end-to-end test suite. For code changes, run at least:
```sh
pnpm check
pnpm lint
pnpm build
```
If pre-existing warnings remain outside the files being changed, report them rather than making unrelated edits.
## Repository structure
```text
src/
├── app.html # German document shell and Skeleton theme selection
├── app.d.ts # SvelteKit application type declarations
├── lib/
│ ├── assets/ # Bundled favicon and Nunito font files
│ ├── components/ # Reusable Svelte components
│ │ ├── Button.svelte
│ │ ├── Card.svelte
│ │ └── ZipDropzone.svelte
│ ├── index.ts # Public `$lib` exports
│ └── nom-theme.css # Custom Skeleton theme tokens
└── routes/
├── +layout.svelte # Shared logo header and branded footer
├── +page.svelte # Main ZIP-selection page
├── layout.css # Tailwind/Skeleton imports and global font setup
├── datenschutz/+page.svelte # Privacy policy
└── impressum/+page.svelte # Imprint
static/ # Files served unchanged from the site root
```
Generated directories such as `.svelte-kit/`, `build/`, and `node_modules/` must not be edited or committed.
## Svelte conventions
- Use Svelte 5 runes and current event syntax. Prefer `$props()`, `$state`, `$derived`, snippets, `{@render ...}`, and handlers such as `onclick` over legacy APIs.
- Keep component scripts typed with `<script lang="ts">`.
- Define a local `Props` type for non-trivial component props.
- Use callback props for child-to-parent communication, as `ZipDropzone.svelte` does with `onFilesSelected`.
- Use `$lib/...` for imports from `src/lib` rather than long relative paths.
- Name reusable component files in PascalCase and route files according to SvelteKit conventions.
- Keep browser-only APIs such as `File`, `FileList`, and drag-and-drop handling in components that execute in the browser. Do not introduce server-side upload behavior unless requested.
- Preserve semantic HTML. Interactive drop zones must remain keyboard-operable buttons with an accessible name.
The Vite configuration forces runes mode for application files, so do not add legacy Svelte component patterns.
## Styling conventions
Use **Tailwind utility classes in Svelte markup** for component and route styling. Orient new work around the existing classes in `+layout.svelte`, `+page.svelte`, `Card.svelte`, and `ZipDropzone.svelte`.
- Prefer existing theme utilities such as `bg-primary-50`, `text-primary-900`, `border-primary-500`, and `rounded-container`.
- Use the custom `primary`, `secondary`, `tertiary`, and `surface` scales defined in `src/lib/nom-theme.css` instead of adding arbitrary brand colors.
- Keep the established visual language: cool blue-gray page background, white cards, dark blue headings, subtle shadows, rounded containers, and the Nunito typeface.
- Use responsive Tailwind variants and ensure layouts work on narrow screens.
- Prefer utilities over new component-level `<style>` blocks or inline styles. Add global CSS only when defining shared theme primitives, imports, font faces, or behavior that cannot reasonably be expressed with utilities.
- Tailwind 4 is configured through Vite and `src/routes/layout.css`; there is no `tailwind.config` file.
- Keep complete utility class names visible to Tailwind. For variants, map each state to complete class strings rather than constructing fragments such as `text-${color}`.
- Preserve clear focus states, adequate contrast, and visible drag-and-drop feedback.
`src/app.html` applies `data-theme="nominandum"`. Theme-level changes belong in `src/lib/nom-theme.css`; global Tailwind and Skeleton imports belong in `src/routes/layout.css`.
## Formatting
Follow the checked-in Prettier configuration:
- Tabs for indentation
- Single quotes in scripts and styles where supported
- No trailing commas
- 100-character print width
- Svelte-aware and Tailwind-aware formatting
Use `pnpm exec prettier --write <changed-files>` for targeted formatting. Avoid formatting unrelated files solely to clean up existing differences.
## Product and content constraints
- User-facing copy is German unless a task explicitly requests another language.
- Preserve legal text in `datenschutz/+page.svelte` and `impressum/+page.svelte` unless the request explicitly asks for content changes.
- Keep the shared Nominandum logo, footer artwork, and theme consistent across routes.
- ZIP selection is client-side and accepts `.zip`, `application/zip`, and `application/x-zip-compressed` files.
- Resetting the file input after selection is intentional so the same archive can be selected twice.
- Do not add network requests, file uploads, analytics, or persistence without an explicit requirement.
## Change discipline
- Keep changes scoped to the request and preserve unrelated work, including untracked files.
- Inspect existing components and theme tokens before introducing new abstractions.
- Do not hand-edit generated output or lockfile contents. Update the lockfile only through pnpm when dependency changes are required.
- Avoid adding dependencies when the task can be completed with Svelte, browser APIs, Tailwind, or existing Skeleton packages.
- After implementation, review the changed files, run the relevant checks, and mention any remaining warnings or limitations.
+10 -3
View File
@@ -18,9 +18,16 @@
<footer class="flex flex-col justify-end gap-15 min-h-78.5 h-96 px-4 mt-8.75 text-white py-8.75"
style="background-image: url('/footer.svg');background-position: top right; background-size: cover; background-repeat: no-repeat">
<div class="w-full max-w-360 mx-auto">
<h2 class="font-bold mb-4">Nominandum GmbH</h2>
<h2 class="hidden font-bold mb-4">Nominandum GmbH</h2>
<div class="flex flex-row flex-wrap gap-15 text-[14px] leading-5 mx-auto">
<div>
<a class="underline" href="/impressum">Impressum</a><br/>
<a class="underline" href="/datenschutz">Datenschutzerklärung</a><br/>
</div>
</div>
<div class="hidden flex flex-row flex-wrap gap-15 text-[14px] leading-5 mx-auto">
<div class="not-sm:hidden">
Holstenwall 1<br/>
20355 Hamburg<br/>
@@ -34,8 +41,8 @@
UstId. DE321802543
</div>
<div>
<a class="underline" href="">Impressum</a><br/>
<a class="underline" href="">Datenschutzerklärung</a><br/>
<a class="underline" href="/impressum">Impressum</a><br/>
<a class="underline" href="/datenschutz">Datenschutzerklärung</a><br/>
<a class="underline" href="">Nutzungsbedingungen</a><br/>
</div>
<div class="grow">
+411
View File
@@ -0,0 +1,411 @@
<svelte:head>
<title>Datenschutzerklärung | Nominandum</title>
<meta
name="description"
content="Informationen zum Datenschutz und zur Verarbeitung personenbezogener Daten bei Nominandum."
/>
</svelte:head>
<main class="min-h-screen bg-primary-50/50 text-surface-800">
<header class="border-b-4 border-tertiary-400 bg-primary-900 text-white">
<div class="mx-auto max-w-7xl px-4 py-12 sm:px-8 sm:py-16 lg:py-20">
<a
class="mb-10 inline-flex items-center gap-2 rounded-sm text-sm font-bold text-primary-200 transition-colors hover:text-white focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white"
href="/"
aria-label="Zurück zur Startseite"
>
<span aria-hidden="true"></span>
Startseite
</a>
<p class="mb-3 text-xs font-extrabold tracking-[0.16em] text-tertiary-300 uppercase">
Rechtliches · Datenschutz
</p>
<h1
id="page-title"
class="max-w-4xl text-4xl leading-none font-extrabold tracking-tight text-white sm:text-6xl lg:text-7xl"
>
Datenschutz&shy;erklärung
</h1>
<p class="mt-6 max-w-2xl text-lg leading-relaxed text-primary-100 sm:text-xl">
Was wir erfassen, warum wir es verarbeiten und welche Rechte Sie dabei haben.
</p>
</div>
</header>
<div
class="mx-auto grid max-w-7xl gap-8 px-4 py-8 sm:px-8 sm:py-12 lg:grid-cols-[14rem_minmax(0,1fr)] lg:gap-12 lg:py-16"
>
<aside class="hidden lg:block" aria-label="Inhaltsverzeichnis">
<div class="sticky top-8">
<p class="mb-4 text-xs font-extrabold tracking-[0.16em] text-primary-700 uppercase">
Inhalt
</p>
<nav
class="flex flex-col border-l border-primary-200 [&_a]:grid [&_a]:grid-cols-[2rem_1fr] [&_a]:gap-2 [&_a]:border-l-2 [&_a]:border-transparent [&_a]:px-4 [&_a]:py-2.5 [&_a]:text-sm [&_a]:font-bold [&_a]:text-surface-600 [&_a]:transition-colors [&_a:hover]:border-tertiary-500 [&_a:hover]:text-primary-900 [&_span]:font-extrabold [&_span]:text-primary-400"
>
<a href="#ueberblick"><span>01</span>Auf einen Blick</a>
<a href="#hosting"><span>02</span>Hosting</a>
<a href="#pflichtinformationen"><span>03</span>Pflichtinformationen</a>
<a href="#datenerfassung"><span>04</span>Datenerfassung</a>
</nav>
<p class="mt-6 text-xs leading-relaxed text-surface-500">Vier Kapitel</p>
</div>
</aside>
<article aria-labelledby="page-title">
<div
class="[&_address]:my-6 [&_address]:w-fit [&_address]:rounded-r-xl [&_address]:border-l-4 [&_address]:border-tertiary-400 [&_address]:bg-primary-50 [&_address]:px-5 [&_address]:py-4 [&_address]:not-italic [&_address]:leading-relaxed [&_h2]:mb-8 [&_h2]:text-2xl [&_h2]:leading-tight [&_h2]:font-extrabold [&_h2]:tracking-tight [&_h2]:text-primary-900 sm:[&_h2]:text-3xl [&_h3]:mt-10 [&_h3]:mb-3 [&_h3]:text-xl [&_h3]:leading-snug [&_h3]:font-extrabold [&_h3]:text-primary-800 [&_h4]:mt-6 [&_h4]:mb-2 [&_h4]:font-extrabold [&_h4]:text-surface-900 [&_li]:leading-relaxed [&_p]:leading-[1.75] [&_p+p]:mt-4 [&_section]:scroll-mt-6 [&_section]:rounded-container [&_section]:border [&_section]:border-primary-100 [&_section]:bg-white [&_section]:p-6 [&_section]:shadow-sm sm:[&_section]:p-10 lg:[&_section]:p-14 [&_section+section]:mt-6 [&_ul]:my-5 [&_ul]:grid [&_ul]:list-disc [&_ul]:gap-2 [&_ul]:pl-6 [&_li::marker]:text-tertiary-600 [&_.legal-notice]:my-6 [&_.legal-notice]:rounded-xl [&_.legal-notice]:border [&_.legal-notice]:border-primary-200 [&_.legal-notice]:bg-primary-50 [&_.legal-notice]:p-5 sm:[&_.legal-notice]:p-7 [&_.legal-notice_p]:text-sm [&_.legal-notice_p]:font-bold [&_.legal-notice_p]:tracking-wide [&_.legal-notice_p]:text-primary-950 [&_.source]:mt-8 [&_.source]:flex [&_.source]:items-center [&_.source]:gap-3 [&_.source]:rounded-container [&_.source]:border [&_.source]:border-primary-100 [&_.source]:bg-white [&_.source]:px-6 [&_.source]:py-4 [&_.source]:text-sm [&_.source]:text-surface-500 [&_.source_span]:font-extrabold [&_.source_span]:tracking-wider [&_.source_span]:text-primary-700 [&_.source_span]:uppercase [&_.source_a]:font-bold [&_.source_a]:text-primary-700 [&_.source_a]:underline [&_.source_a]:underline-offset-4"
>
<section id="ueberblick" data-section="01">
<h2>1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3>
<p>
Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren
personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene
Daten sind alle Daten, mit denen Sie persönlich identifiziert werden können.
Ausführliche Informationen zum Thema Datenschutz entnehmen Sie unserer unter diesem Text
aufgeführten Datenschutzerklärung.
</p>
<h3>Datenerfassung auf dieser Website</h3>
<h4>Wer ist verantwortlich für die Datenerfassung auf dieser Website?</h4>
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen
Kontaktdaten können Sie dem Abschnitt „Hinweis zur Verantwortlichen Stelle“ in dieser
Datenschutzerklärung entnehmen.
</p>
<h4>Wie erfassen wir Ihre Daten?</h4>
<p>
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese mitteilen. Hierbei kann
es sich z. B. um Daten handeln, die Sie in ein Kontaktformular eingeben.
</p>
<p>
Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch der Website
durch unsere IT-Systeme erfasst. Das sind vor allem technische Daten (z. B.
Internetbrowser, Betriebssystem oder Uhrzeit des Seitenaufrufs). Die Erfassung dieser
Daten erfolgt automatisch, sobald Sie diese Website betreten.
</p>
<h4>Wofür nutzen wir Ihre Daten?</h4>
<p>
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu
gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet werden.
Sofern über die Website Verträge geschlossen oder angebahnt werden können, werden die
übermittelten Daten auch für Vertragsangebote, Bestellungen oder sonstige
Auftragsanfragen verarbeitet.
</p>
<h4>Welche Rechte haben Sie bezüglich Ihrer Daten?</h4>
<p>
Sie haben jederzeit das Recht, unentgeltlich Auskunft über Herkunft, Empfänger und Zweck
Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben außerdem ein Recht,
die Berichtigung oder Löschung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur
Datenverarbeitung erteilt haben, können Sie diese Einwilligung jederzeit für die Zukunft
widerrufen. Außerdem haben Sie das Recht, unter bestimmten Umständen die Einschränkung
der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Des Weiteren steht Ihnen
ein Beschwerderecht bei der zuständigen Aufsichtsbehörde zu.
</p>
<p>
Hierzu sowie zu weiteren Fragen zum Thema Datenschutz können Sie sich jederzeit an uns
wenden.
</p>
<h3>Analyse-Tools und Tools von Dritt­anbietern</h3>
<p>
Beim Besuch dieser Website kann Ihr Surf-Verhalten statistisch ausgewertet werden. Das
geschieht vor allem mit sogenannten Analyseprogrammen.
</p>
<p>
Detaillierte Informationen zu diesen Analyseprogrammen finden Sie in der folgenden
Datenschutzerklärung.
</p>
</section>
<section id="hosting" data-section="02">
<h2>2. Hosting</h2>
<p>Wir hosten die Inhalte unserer Website bei folgendem Anbieter:</p>
<h3>Externes Hosting</h3>
<p>
Diese Website wird extern gehostet. Die personenbezogenen Daten, die auf dieser Website
erfasst werden, werden auf den Servern des Hosters / der Hoster gespeichert. Hierbei
kann es sich v. a. um IP-Adressen, Kontaktanfragen, Meta- und Kommunikationsdaten,
Vertragsdaten, Kontaktdaten, Namen, Websitezugriffe und sonstige Daten, die über eine
Website generiert werden, handeln.
</p>
<p>
Das externe Hosting erfolgt zum Zwecke der Vertragserfüllung gegenüber unseren
potenziellen und bestehenden Kunden (Art. 6 Abs. 1 lit. b DSGVO) und im Interesse einer
sicheren, schnellen und effizienten Bereitstellung unseres Online-Angebots durch einen
professionellen Anbieter (Art. 6 Abs. 1 lit. f DSGVO). Sofern eine entsprechende
Einwilligung abgefragt wurde, erfolgt die Verarbeitung ausschließlich auf Grundlage von
Art. 6 Abs. 1 lit. a DSGVO und § 25 Abs. 1 TDDDG, soweit die Einwilligung die
Speicherung von Cookies oder den Zugriff auf Informationen im Endgerät des Nutzers (z.
B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die Einwilligung ist jederzeit
widerrufbar.
</p>
<p>
Unser(e) Hoster wird bzw. werden Ihre Daten nur insoweit verarbeiten, wie dies zur
Erfüllung seiner Leistungspflichten erforderlich ist und unsere Weisungen in Bezug auf
diese Daten befolgen.
</p>
<p>Wir setzen folgende(n) Hoster ein:</p>
<address>
netcup GmbH<br />
Emmy-Noether-Str. 10<br />
76131 Karlsruhe
</address>
<h3>Auftragsverarbeitung</h3>
<p>
Wir haben einen Vertrag über Auftragsverarbeitung (AVV) zur Nutzung des oben genannten
Dienstes geschlossen. Hierbei handelt es sich um einen datenschutzrechtlich
vorgeschriebenen Vertrag, der gewährleistet, dass dieser die personenbezogenen Daten
unserer Websitebesucher nur nach unseren Weisungen und unter Einhaltung der DSGVO
verarbeitet.
</p>
</section>
<section id="pflichtinformationen" data-section="03">
<h2>3. Allgemeine Hinweise und Pflicht­informationen</h2>
<h3>Datenschutz</h3>
<p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir
behandeln Ihre personenbezogenen Daten vertraulich und entsprechend den gesetzlichen
Datenschutzvorschriften sowie dieser Datenschutzerklärung.
</p>
<p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten erhoben.
Personenbezogene Daten sind Daten, mit denen Sie persönlich identifiziert werden können.
Die vorliegende Datenschutzerklärung erläutert, welche Daten wir erheben und wofür wir
sie nutzen. Sie erläutert auch, wie und zu welchem Zweck das geschieht.
</p>
<p>
Wir weisen darauf hin, dass die Datenübertragung im Internet (z. B. bei der
Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der
Daten vor dem Zugriff durch Dritte ist nicht möglich.
</p>
<h3>Hinweis zur verantwortlichen Stelle</h3>
<p>Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:</p>
<address>
Robin Ehlert<br />
Am Frohnacker 3<br />
76829 Landau in der Pfalz<br /><br />
Telefon: +49 (0) 1782877207<br />
E-Mail: post@rehlert.de
</address>
<p>
Verantwortliche Stelle ist die natürliche oder juristische Person, die allein oder
gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen
Daten (z. B. Namen, E-Mail-Adressen o. Ä.) entscheidet.
</p>
<h3>Speicherdauer</h3>
<p>
Soweit innerhalb dieser Datenschutzerklärung keine speziellere Speicherdauer genannt
wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck für die
Datenverarbeitung entfällt. Wenn Sie ein berechtigtes Löschersuchen geltend machen oder
eine Einwilligung zur Datenverarbeitung widerrufen, werden Ihre Daten gelöscht, sofern
wir keine anderen rechtlich zulässigen Gründe für die Speicherung Ihrer
personenbezogenen Daten haben (z. B. steuer- oder handelsrechtliche
Aufbewahrungsfristen); im letztgenannten Fall erfolgt die Löschung nach Fortfall dieser
Gründe.
</p>
<h3>
Allgemeine Hinweise zu den Rechtsgrundlagen der Datenverarbeitung auf dieser Website
</h3>
<p>
Sofern Sie in die Datenverarbeitung eingewilligt haben, verarbeiten wir Ihre
personenbezogenen Daten auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO bzw. Art. 9 Abs. 2
lit. a DSGVO, sofern besondere Datenkategorien nach Art. 9 Abs. 1 DSGVO verarbeitet
werden. Im Falle einer ausdrücklichen Einwilligung in die Übertragung personenbezogener
Daten in Drittstaaten erfolgt die Datenverarbeitung außerdem auf Grundlage von Art. 49
Abs. 1 lit. a DSGVO. Sofern Sie in die Speicherung von Cookies oder in den Zugriff auf
Informationen in Ihr Endgerät (z. B. via Device-Fingerprinting) eingewilligt haben,
erfolgt die Datenverarbeitung zusätzlich auf Grundlage von § 25 Abs. 1 TDDDG. Die
Einwilligung ist jederzeit widerrufbar. Sind Ihre Daten zur Vertragserfüllung oder zur
Durchführung vorvertraglicher Maßnahmen erforderlich, verarbeiten wir Ihre Daten auf
Grundlage des Art. 6 Abs. 1 lit. b DSGVO. Des Weiteren verarbeiten wir Ihre Daten,
sofern diese zur Erfüllung einer rechtlichen Verpflichtung erforderlich sind auf
Grundlage von Art. 6 Abs. 1 lit. c DSGVO. Die Datenverarbeitung kann ferner auf
Grundlage unseres berechtigten Interesses nach Art. 6 Abs. 1 lit. f DSGVO erfolgen. Über
die jeweils im Einzelfall einschlägigen Rechtsgrundlagen wird in den folgenden Absätzen
dieser Datenschutzerklärung informiert.
</p>
<h3>Empfänger von personenbezogenen Daten</h3>
<p>
Im Rahmen unserer Geschäftstätigkeit arbeiten wir mit verschiedenen externen Stellen
zusammen. Dabei ist teilweise auch eine Übermittlung von personenbezogenen Daten an
diese externen Stellen erforderlich. Wir geben personenbezogene Daten nur dann an
externe Stellen weiter, wenn dies im Rahmen einer Vertragserfüllung erforderlich ist,
wenn wir gesetzlich hierzu verpflichtet sind (z. B. Weitergabe von Daten an
Steuerbehörden), wenn wir ein berechtigtes Interesse nach Art. 6 Abs. 1 lit. f DSGVO an
der Weitergabe haben oder wenn eine sonstige Rechtsgrundlage die Datenweitergabe
erlaubt. Beim Einsatz von Auftragsverarbeitern geben wir personenbezogene Daten unserer
Kunden nur auf Grundlage eines gültigen Vertrags über Auftragsverarbeitung weiter. Im
Falle einer gemeinsamen Verarbeitung wird ein Vertrag über gemeinsame Verarbeitung
geschlossen.
</p>
<h3>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h3>
<p>
Viele Datenverarbeitungsvorgänge sind nur mit Ihrer ausdrücklichen Einwilligung möglich.
Sie können eine bereits erteilte Einwilligung jederzeit widerrufen. Die Rechtmäßigkeit
der bis zum Widerruf erfolgten Datenverarbeitung bleibt vom Widerruf unberührt.
</p>
<h3>
Widerspruchsrecht gegen die Datenerhebung in besonderen Fällen sowie gegen Direktwerbung
(Art. 21 DSGVO)
</h3>
<div class="legal-notice">
<p>
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO
ERFOLGT, HABEN SIE JEDERZEIT DAS RECHT, AUS GRÜNDEN, DIE SICH AUS IHRER BESONDEREN
SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER PERSONENBEZOGENEN DATEN WIDERSPRUCH
EINZULEGEN; DIES GILT AUCH FÜR EIN AUF DIESE BESTIMMUNGEN GESTÜTZTES PROFILING. DIE
JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER
DATENSCHUTZERKLÄRUNG. WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN
PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI DENN, WIR KÖNNEN ZWINGENDE
SCHUTZWÜRDIGE GRÜNDE FÜR DIE VERARBEITUNG NACHWEISEN, DIE IHRE INTERESSEN, RECHTE UND
FREIHEITEN ÜBERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUSÜBUNG ODER
VERTEIDIGUNG VON RECHTSANSPRÜCHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p>
<p>
WERDEN IHRE PERSONENBEZOGENEN DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO
HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE VERARBEITUNG SIE BETREFFENDER
PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH FÜR
DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE
WIDERSPRECHEN, WERDEN IHRE PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM ZWECKE
DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21 ABS. 2 DSGVO).
</p>
</div>
<h3>Beschwerde­recht bei der zuständigen Aufsichts­behörde</h3>
<p>
Im Falle von Verstößen gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei
einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat ihres gewöhnlichen
Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes zu. Das
Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder
gerichtlicher Rechtsbehelfe.
</p>
<h3>Recht auf Daten­übertrag­barkeit</h3>
<p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung oder in Erfüllung
eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem
gängigen, maschinenlesbaren Format aushändigen zu lassen. Sofern Sie die direkte
Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur,
soweit es technisch machbar ist.
</p>
<h3>Auskunft, Berichtigung und Löschung</h3>
<p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit das Recht auf
unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, deren Herkunft
und Empfänger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung
oder Löschung dieser Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene
Daten können Sie sich jederzeit an uns wenden.
</p>
<h3>Recht auf Einschränkung der Verarbeitung</h3>
<p>
Sie haben das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu
verlangen. Hierzu können Sie sich jederzeit an uns wenden. Das Recht auf Einschränkung
der Verarbeitung besteht in folgenden Fällen:
</p>
<ul>
<li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten
bestreiten, benötigen wir in der Regel Zeit, um dies zu überprüfen. Für die Dauer der
Prüfung haben Sie das Recht, die Einschränkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtmäßig geschah/geschieht,
können Sie statt der Löschung die Einschränkung der Datenverarbeitung verlangen.
</li>
<li>
Wenn wir Ihre personenbezogenen Daten nicht mehr benötigen, Sie sie jedoch zur
Ausübung, Verteidigung oder Geltendmachung von Rechtsansprüchen benötigen, haben Sie
das Recht, statt der Löschung die Einschränkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine
Abwägung zwischen Ihren und unseren Interessen vorgenommen werden. Solange noch nicht
feststeht, wessen Interessen überwiegen, haben Sie das Recht, die Einschränkung der
Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>
</ul>
<p>
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschränkt haben, dürfen
diese Daten von ihrer Speicherung abgesehen nur mit Ihrer Einwilligung oder zur
Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen oder zum Schutz der
Rechte einer anderen natürlichen oder juristischen Person oder aus Gründen eines
wichtigen öffentlichen Interesses der Europäischen Union oder eines Mitgliedstaats
verarbeitet werden.
</p>
<h3>SSL- bzw. TLS-Verschlüsselung</h3>
<p>
Diese Seite nutzt aus Sicherheitsgründen und zum Schutz der Übertragung vertraulicher
Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber
senden, eine SSL- bzw. TLS-Verschlüsselung. Eine verschlüsselte Verbindung erkennen Sie
daran, dass die Adresszeile des Browsers von „http://“ auf „https://“ wechselt und an
dem Schloss-Symbol in Ihrer Browserzeile.
</p>
<p>
Wenn die SSL- bzw. TLS-Verschlüsselung aktiviert ist, können die Daten, die Sie an uns
übermitteln, nicht von Dritten mitgelesen werden.
</p>
<h3>Widerspruch gegen Werbe-E-Mails</h3>
<p>
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten zur
Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien
wird hiermit widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich
rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa
durch Spam-E-Mails, vor.
</p>
</section>
<section id="datenerfassung" data-section="04">
<h2>4. Datenerfassung auf dieser Website</h2>
<h3>Server-Log-Dateien</h3>
<p>
Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten
Server-Log-Dateien, die Ihr Browser automatisch an uns übermittelt. Dies sind:
</p>
<ul>
<li>Browsertyp und Browserversion</li>
<li>verwendetes Betriebssystem</li>
<li>Referrer URL</li>
<li>Hostname des zugreifenden Rechners</li>
<li>Uhrzeit der Serveranfrage</li>
<li>IP-Adresse</li>
</ul>
<p>Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen.</p>
<p>
Die Erfassung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Der
Websitebetreiber hat ein berechtigtes Interesse an der technisch fehlerfreien
Darstellung und der Optimierung seiner Website hierzu müssen die Server-Log-Files
erfasst werden.
</p>
</section>
<p class="source">
<span>Quelle</span>
<a href="https://www.e-recht24.de">e-recht24.de</a>
</p>
</div>
</article>
</div>
</main>
+97
View File
@@ -0,0 +1,97 @@
<svelte:head>
<title>Impressum | Nominandum</title>
<meta name="description" content="Anbieterkennzeichnung und Kontaktdaten von Nominandum." />
</svelte:head>
<main class="min-h-screen bg-primary-50/50 text-surface-800">
<header class="border-b-4 border-tertiary-400 bg-primary-900 text-white">
<div class="mx-auto max-w-7xl px-4 py-12 sm:px-8 sm:py-16 lg:py-20">
<a
class="mb-10 inline-flex items-center gap-2 rounded-sm text-sm font-bold text-primary-200 transition-colors hover:text-white focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white"
href="/"
aria-label="Zurück zur Startseite"
>
<span aria-hidden="true"></span>
Startseite
</a>
<p class="mb-3 text-xs font-extrabold tracking-[0.16em] text-tertiary-300 uppercase">
Rechtliches · Anbieterkennzeichnung
</p>
<h1
id="page-title"
class="text-4xl leading-none font-extrabold tracking-tight text-white sm:text-6xl lg:text-7xl"
>
Impressum
</h1>
<p class="mt-6 max-w-2xl text-lg leading-relaxed text-primary-100 sm:text-xl">
Verantwortliche Person, ladungsfähige Anschrift und direkter Kontakt.
</p>
</div>
</header>
<div class="mx-auto max-w-7xl px-4 py-8 sm:px-8 sm:py-12 lg:py-16">
<article
class="relative grid overflow-hidden rounded-container border border-primary-100 bg-white shadow-sm md:grid-cols-2"
aria-labelledby="page-title"
>
<div
class="absolute top-0 right-6 rounded-b-lg bg-tertiary-400 px-3 py-2 text-xs font-extrabold tracking-[0.14em] text-primary-950"
aria-hidden="true"
>
IMP
</div>
<section class="p-7 sm:p-10 lg:p-14" aria-labelledby="address-heading">
<p class="mb-8 text-sm font-extrabold text-primary-400">01</p>
<h2
id="address-heading"
class="text-2xl font-extrabold tracking-tight text-primary-900 sm:text-3xl"
>
Anschrift
</h2>
<address class="mt-8 flex flex-col gap-1 text-base leading-relaxed not-italic sm:text-lg">
<strong class="mb-2 font-extrabold text-primary-900">Robin Ehlert</strong>
<span>Am Frohnacker 3</span>
<span>76829 Landau in der Pfalz</span>
</address>
</section>
<section
class="border-t border-primary-100 bg-primary-50/60 p-7 sm:p-10 md:border-t-0 md:border-l lg:p-14"
aria-labelledby="contact-heading"
>
<p class="mb-8 text-sm font-extrabold text-primary-400">02</p>
<h2
id="contact-heading"
class="text-2xl font-extrabold tracking-tight text-primary-900 sm:text-3xl"
>
Kontakt
</h2>
<dl class="mt-8 grid gap-6">
<div>
<dt class="mb-1 text-xs font-extrabold tracking-wider text-surface-500 uppercase">
Telefon
</dt>
<dd>
<a
class="rounded-sm text-lg font-bold text-primary-800 underline decoration-primary-300 underline-offset-4 hover:text-primary-600 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-primary-700"
href="tel:+491782877207">+49 (0) 178 2877207</a
>
</dd>
</div>
<div>
<dt class="mb-1 text-xs font-extrabold tracking-wider text-surface-500 uppercase">
E-Mail
</dt>
<dd>
<a
class="rounded-sm text-lg font-bold text-primary-800 underline decoration-primary-300 underline-offset-4 hover:text-primary-600 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-primary-700"
href="mailto:jm@rehlert.de">jm@rehlert.de</a
>
</dd>
</div>
</dl>
</section>
</article>
</div>
</main>