feat(stellungnahme): Notizfeld pro Argument + editierbare Einleitung/Abschluss
- Notizfeld an jedem Argument (expanded) → erscheint im Output als "Anmerkung:" - Einleitung und Abschluss in Step 5 via <details> editierbar - Beide mit Zurücksetzen-Button auf Default - Alles in localStorage persistiert Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -105,13 +105,15 @@
|
||||
absenderName,
|
||||
absenderAnschrift,
|
||||
absenderOrt,
|
||||
argNotes,
|
||||
openingOverride,
|
||||
closingOverride,
|
||||
}));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
// track all persisted fields reactively
|
||||
void [selectedSlugs, persoenlicheEingabe, absenderName, absenderAnschrift, absenderOrt];
|
||||
void [selectedSlugs, persoenlicheEingabe, absenderName, absenderAnschrift, absenderOrt, argNotes, openingOverride, closingOverride];
|
||||
if (mounted) saveState();
|
||||
});
|
||||
|
||||
@@ -138,6 +140,22 @@
|
||||
let absenderOrt = $state("");
|
||||
let showOutput = $state(false);
|
||||
|
||||
// Per-argument notes (appear in output after bullet points)
|
||||
let argNotes = $state<Record<string, string>>({});
|
||||
function setArgNote(slug: string, value: string) {
|
||||
argNotes = { ...argNotes, [slug]: value };
|
||||
}
|
||||
|
||||
// Editable opening/closing — null = use reactive default
|
||||
const defaultOpening = $derived(
|
||||
`ich erhebe Einwendung gegen die Ausweisung des Windenergie-Vorranggebiets ${gebietsBez} im 2. Entwurf des Regionalplans Südwestthüringen.`,
|
||||
);
|
||||
const defaultClosing = "Ich fordere die Regionalplanung auf, das Vorranggebiet aus dem Regionalplan zu streichen oder zumindest einer erneuten, umfassenden Überprüfung zu unterziehen.";
|
||||
let openingOverride = $state<string | null>(null);
|
||||
let closingOverride = $state<string | null>(null);
|
||||
const effectiveOpening = $derived(openingOverride ?? defaultOpening);
|
||||
const effectiveClosing = $derived(closingOverride ?? defaultClosing);
|
||||
|
||||
|
||||
function toggleSlug(slug: string) {
|
||||
const next = new Set(selectedSlugs);
|
||||
@@ -221,7 +239,7 @@ Karl-Liebknecht-Straße 4
|
||||
Stichpunkte müssen vor dem Einreichen in eigene, ausformulierte
|
||||
Sätze überführt werden. Text individuell anpassen.
|
||||
${"=".repeat(64)}`;
|
||||
let body = `ich erhebe Einwendung gegen die Ausweisung des Windenergie-Vorranggebiets ${gebietsBez} im 2. Entwurf des Regionalplans Südwestthüringen.\n\n`;
|
||||
let body = `${effectiveOpening}\n\n`;
|
||||
for (const f of selectedFragments) {
|
||||
if (f.title) body += `${f.title}\n\n`;
|
||||
if (f.bulletPoints?.length) {
|
||||
@@ -230,10 +248,12 @@ ${"=".repeat(64)}`;
|
||||
} else if (f.text) {
|
||||
body += `${stripMd(f.text)}\n\n`;
|
||||
}
|
||||
const note = argNotes[f._slug]?.trim();
|
||||
if (note) body += `Anmerkung: ${note}\n\n`;
|
||||
}
|
||||
if (persoenlicheEingabe.trim())
|
||||
body += `Persönliche Betroffenheit\n\n${persoenlicheEingabe.trim()}\n\n`;
|
||||
body += `Ich fordere die Regionalplanung auf, das Vorranggebiet aus dem Regionalplan zu streichen oder zumindest einer erneuten, umfassenden Überprüfung zu unterziehen.\n\n${closing}`;
|
||||
body += `${effectiveClosing}\n\n${closing}`;
|
||||
|
||||
return [disclaimer, "", sender, "", heute, "", "An:", RECIPIENT, "", "Betreff: " + betreff.split("\n")[0], betreff.split("\n")[1] ?? "", "", "Sehr geehrte Damen und Herren,", "", body.trimEnd()]
|
||||
.join("\n")
|
||||
@@ -276,6 +296,9 @@ ${"=".repeat(64)}`;
|
||||
selectedSlugs = new Set();
|
||||
expandedItems = new Set();
|
||||
expandedGroups = new Set();
|
||||
argNotes = {};
|
||||
openingOverride = null;
|
||||
closingOverride = null;
|
||||
persoenlicheEingabe = "";
|
||||
absenderName = "";
|
||||
absenderAnschrift = "";
|
||||
@@ -385,6 +408,9 @@ ${"=".repeat(64)}`;
|
||||
if (typeof s.persoenlicheEingabe === "string") persoenlicheEingabe = s.persoenlicheEingabe;
|
||||
if (typeof s.absenderName === "string") absenderName = s.absenderName;
|
||||
if (typeof s.absenderAnschrift === "string") absenderAnschrift = s.absenderAnschrift;
|
||||
if (typeof s.absenderOrt === "string") absenderOrt = s.absenderOrt;
|
||||
if (s.argNotes && typeof s.argNotes === "object") argNotes = s.argNotes;
|
||||
if (typeof s.openingOverride === "string") openingOverride = s.openingOverride;
|
||||
if (typeof s.closingOverride === "string") closingOverride = s.closingOverride;
|
||||
if ((s.selectedSlugs?.length ?? 0) > 0 || s.absenderName || s.persoenlicheEingabe) {
|
||||
hadSavedState = true;
|
||||
@@ -637,9 +663,18 @@ ${"=".repeat(64)}`;
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if k.text && expandedItems.has(k._slug)}
|
||||
</div>
|
||||
{#if expandedItems.has(k._slug)}
|
||||
<div class="border-t border-stein-100 px-3 pb-3 pt-2 space-y-2">
|
||||
{#if k.text}
|
||||
<div class="prose prose-sm prose-stein max-w-none text-sm text-stein-700">{@html md(k.text)}</div>
|
||||
{/if}
|
||||
<textarea
|
||||
class="w-full rounded border border-stein-200 px-2 py-1.5 text-xs text-stein-700 placeholder:text-stein-400 focus:border-wald-400 focus:outline-none focus:ring-1 focus:ring-wald-200 resize-none"
|
||||
rows="2"
|
||||
placeholder="Persönliche Notiz zu diesem Punkt (erscheint im Dokument) …"
|
||||
value={argNotes[k._slug] ?? ""}
|
||||
oninput={(e) => setArgNote(k._slug, (e.target as HTMLTextAreaElement).value)}
|
||||
></textarea>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -729,9 +764,18 @@ ${"=".repeat(64)}`;
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if f.text && expandedItems.has(f._slug)}
|
||||
</div>
|
||||
{#if expandedItems.has(f._slug)}
|
||||
<div class="border-t border-stein-100 px-3 pb-3 pt-2 space-y-2">
|
||||
{#if f.text}
|
||||
<div class="prose prose-sm prose-stein max-w-none text-sm text-stein-700">{@html md(f.text)}</div>
|
||||
{/if}
|
||||
<textarea
|
||||
class="w-full rounded border border-stein-200 px-2 py-1.5 text-xs text-stein-700 placeholder:text-stein-400 focus:border-wald-400 focus:outline-none focus:ring-1 focus:ring-wald-200 resize-none"
|
||||
rows="2"
|
||||
placeholder="Persönliche Notiz zu diesem Punkt (erscheint im Dokument) …"
|
||||
value={argNotes[f._slug] ?? ""}
|
||||
oninput={(e) => setArgNote(f._slug, (e.target as HTMLTextAreaElement).value)}
|
||||
></textarea>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -810,6 +854,44 @@ ${"=".repeat(64)}`;
|
||||
<div class="mb-1 font-semibold text-stein-700">Einzureichen bei:</div>
|
||||
<div class="whitespace-pre">{RECIPIENT}</div>
|
||||
</div>
|
||||
|
||||
<!-- Einleitung & Abschluss anpassen -->
|
||||
<div class="mb-4 space-y-2">
|
||||
<details class="rounded-lg border border-stein-200 overflow-hidden">
|
||||
<summary class="flex cursor-pointer items-center justify-between bg-stein-50 px-4 py-2.5 text-sm font-medium text-stein-700 hover:bg-stein-100 list-none">
|
||||
<span>Einleitung anpassen</span>
|
||||
<Icon icon="mdi:chevron-down" class="size-4 text-stein-400" />
|
||||
</summary>
|
||||
<div class="border-t border-stein-100 px-4 py-3">
|
||||
<textarea
|
||||
class="w-full rounded border border-stein-200 px-3 py-2 text-sm text-stein-800 focus:border-wald-400 focus:outline-none focus:ring-1 focus:ring-wald-200 resize-y"
|
||||
rows="3"
|
||||
value={effectiveOpening}
|
||||
oninput={(e) => (openingOverride = (e.target as HTMLTextAreaElement).value)}
|
||||
></textarea>
|
||||
{#if openingOverride !== null}
|
||||
<button class="mt-1 text-xs text-stein-400 hover:text-stein-600" onclick={() => (openingOverride = null)}>Zurücksetzen</button>
|
||||
{/if}
|
||||
</div>
|
||||
</details>
|
||||
<details class="rounded-lg border border-stein-200 overflow-hidden">
|
||||
<summary class="flex cursor-pointer items-center justify-between bg-stein-50 px-4 py-2.5 text-sm font-medium text-stein-700 hover:bg-stein-100 list-none">
|
||||
<span>Abschluss anpassen</span>
|
||||
<Icon icon="mdi:chevron-down" class="size-4 text-stein-400" />
|
||||
</summary>
|
||||
<div class="border-t border-stein-100 px-4 py-3">
|
||||
<textarea
|
||||
class="w-full rounded border border-stein-200 px-3 py-2 text-sm text-stein-800 focus:border-wald-400 focus:outline-none focus:ring-1 focus:ring-wald-200 resize-y"
|
||||
rows="3"
|
||||
value={effectiveClosing}
|
||||
oninput={(e) => (closingOverride = (e.target as HTMLTextAreaElement).value)}
|
||||
></textarea>
|
||||
{#if closingOverride !== null}
|
||||
<button class="mt-1 text-xs text-stein-400 hover:text-stein-600" onclick={() => (closingOverride = null)}>Zurücksetzen</button>
|
||||
{/if}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="mb-2 flex gap-3">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user