feat: implement i18n — extract all UI strings, add EN + ES-MX translations, add language selector
Extract all hardcoded German strings from every .svelte file and component into Paraglide message keys. Add complete translations for all keys in messages/en.json (English) and messages/es.json (Spanish/Mexico). Changes: - messages/de.json: 100+ keys covering navigation, buttons, form labels, placeholders, section headings, empty states, and error messages - messages/en.json, messages/es.json: complete translations for all keys - project.inlang/settings.json: change baseLocale from "en" to "de" - +layout.svelte: add DE/EN/ES language selector in header using setLocale(); active language is bold, choice persists via Paraglide cookie strategy - All 10 route pages + 3 shared components: replace hardcoded German with m.key() - e2e/lang.spec.ts: E2E tests for language selector visibility, switching, persistence across navigation, and active state highlighting Closes #2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #9.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const doc = $derived(data.document);
|
||||
@@ -53,7 +55,7 @@
|
||||
>
|
||||
<img src="/degruyter-icons/Simple/Medium-24px/SVG/Action/Arrow/Arrow-Left-MD.svg" alt="" aria-hidden="true" class="w-4 h-4" />
|
||||
</div>
|
||||
<span>Zurück</span>
|
||||
<span>{m.btn_back()}</span>
|
||||
</a>
|
||||
|
||||
<div class="flex items-center gap-4 overflow-hidden border-l border-gray-200 pl-6">
|
||||
@@ -77,7 +79,7 @@
|
||||
class="text-brand-navy bg-transparent border border-brand-navy hover:bg-brand-navy hover:text-white px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2"
|
||||
>
|
||||
<img src="/degruyter-icons/Simple/Medium-24px/SVG/Action/Edit-Content-MD.svg" alt="" aria-hidden="true" class="w-4 h-4" />
|
||||
Bearbeiten
|
||||
{m.btn_edit()}
|
||||
</a>
|
||||
|
||||
{#if doc.filePath}
|
||||
@@ -105,7 +107,7 @@
|
||||
<h3
|
||||
class="text-xs font-sans font-bold text-brand-navy uppercase tracking-widest mb-4 border-b border-brand-sand pb-2"
|
||||
>
|
||||
Details
|
||||
{m.doc_section_details()}
|
||||
</h3>
|
||||
<div class="space-y-5">
|
||||
<!-- Date -->
|
||||
@@ -117,7 +119,7 @@
|
||||
<span class="block font-serif text-lg text-brand-navy">
|
||||
{doc.documentDate ? new Intl.DateTimeFormat('de-DE', { day: 'numeric', month: 'long', year: 'numeric' }).format(new Date(doc.documentDate + 'T12:00:00')) : '—'}
|
||||
</span>
|
||||
<span class="text-xs font-sans text-gray-500">Dokumentendatum</span>
|
||||
<span class="text-xs font-sans text-gray-500">{m.doc_label_document_date()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -130,7 +132,7 @@
|
||||
<span class="block font-serif text-lg text-brand-navy">
|
||||
{doc.location ? doc.location : '—'}
|
||||
</span>
|
||||
<span class="text-xs font-sans text-gray-500">Erstellungsort</span>
|
||||
<span class="text-xs font-sans text-gray-500">{m.doc_label_creation_location()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -144,7 +146,7 @@
|
||||
<span class="block font-serif text-lg text-brand-navy">
|
||||
{doc.documentLocation}
|
||||
</span>
|
||||
<span class="text-xs font-sans text-gray-500">Aufbewahrungsort (Original)</span>
|
||||
<span class="text-xs font-sans text-gray-500">{m.doc_label_archive_location_original()}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -167,7 +169,7 @@
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<span class="text-xs font-sans text-gray-500">Schlagworte</span>
|
||||
<span class="text-xs font-sans text-gray-500">{m.form_label_tags()}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -179,11 +181,11 @@
|
||||
<h3
|
||||
class="text-xs font-sans font-bold text-brand-navy uppercase tracking-widest mb-4 border-b border-brand-sand pb-2"
|
||||
>
|
||||
Personen
|
||||
{m.doc_section_persons()}
|
||||
</h3>
|
||||
|
||||
<div class="mb-6">
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">Absender</span>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">{m.form_label_sender()}</span>
|
||||
{#if doc.sender}
|
||||
<a
|
||||
href="/persons/{doc.sender.id}"
|
||||
@@ -209,12 +211,12 @@
|
||||
</div>
|
||||
</a>
|
||||
{:else}
|
||||
<span class="text-sm font-serif text-gray-400 italic">Nicht angegeben</span>
|
||||
<span class="text-sm font-serif text-gray-400 italic">{m.doc_sender_not_specified()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">Empfänger</span>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">{m.form_label_receivers()}</span>
|
||||
{#if doc.receivers && doc.receivers.length > 0}
|
||||
<div class="space-y-2">
|
||||
{#each doc.receivers as receiver}
|
||||
@@ -248,7 +250,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<span class="text-sm font-serif text-gray-400 italic">Keine Empfänger</span>
|
||||
<span class="text-sm font-serif text-gray-400 italic">{m.doc_no_receivers()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -259,13 +261,13 @@
|
||||
<h3
|
||||
class="text-xs font-sans font-bold text-brand-navy uppercase tracking-widest mb-4 border-b border-brand-sand pb-2"
|
||||
>
|
||||
Inhalt
|
||||
{m.doc_section_content()}
|
||||
</h3>
|
||||
|
||||
<div class="space-y-6">
|
||||
{#if doc.summary}
|
||||
<div>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">Zusammenfassung</span>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">{m.doc_label_summary()}</span>
|
||||
<div
|
||||
class="bg-brand-sand/30 p-5 rounded border border-brand-sand text-sm font-serif text-brand-navy leading-relaxed whitespace-pre-wrap"
|
||||
>
|
||||
@@ -276,7 +278,7 @@
|
||||
|
||||
{#if doc.transcription}
|
||||
<div>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">Transkription</span>
|
||||
<span class="text-xs font-sans text-gray-400 block mb-2 uppercase">{m.form_label_transcription()}</span>
|
||||
<div
|
||||
class="bg-brand-sand/30 p-5 rounded border border-brand-sand text-sm font-serif text-brand-navy leading-relaxed whitespace-pre-wrap"
|
||||
>
|
||||
@@ -314,7 +316,7 @@
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="font-sans text-sm tracking-wide">Lade Dokument...</span>
|
||||
<span class="font-sans text-sm tracking-wide">{m.doc_loading()}</span>
|
||||
</div>
|
||||
{:else if error}
|
||||
<div class="text-gray-400 text-center px-4">
|
||||
@@ -325,7 +327,7 @@
|
||||
target="_blank"
|
||||
class="underline hover:text-white text-sm"
|
||||
>
|
||||
Direkter Download versuchen
|
||||
{m.doc_download_link()}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -334,7 +336,7 @@
|
||||
<div class="bg-white/5 p-8 rounded-full mb-6">
|
||||
<img src="/degruyter-icons/Simple/Medium-24px/SVG/Action/PDF-Document-MD.svg" alt="" aria-hidden="true" class="w-12 h-12 opacity-50 invert" />
|
||||
</div>
|
||||
<p class="font-sans text-sm tracking-wide uppercase">Kein Scan vorhanden</p>
|
||||
<p class="font-sans text-sm tracking-wide uppercase">{m.doc_no_scan()}</p>
|
||||
</div>
|
||||
{:else if fileUrl && doc.originalFilename.toLowerCase().endsWith('.pdf')}
|
||||
<iframe
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import PersonMultiSelect from '$lib/components/PersonMultiSelect.svelte';
|
||||
import { untrack } from 'svelte';
|
||||
import { isoToGerman, germanToIso } from '$lib/utils';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
let { data, form } = $props();
|
||||
|
||||
@@ -43,10 +44,10 @@
|
||||
<div class="mb-6">
|
||||
<a href="/documents/{doc.id}" class="inline-flex items-center text-xs font-bold uppercase tracking-widest text-gray-500 hover:text-brand-navy transition-colors group mb-4">
|
||||
<img src="/degruyter-icons/Simple/Medium-24px/SVG/Action/Arrow/Arrow-Left-MD.svg" alt="" aria-hidden="true" class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" />
|
||||
Zurück zum Dokument
|
||||
{m.btn_back_to_document()}
|
||||
</a>
|
||||
<h1 class="text-3xl font-serif text-brand-navy">
|
||||
Bearbeiten — <span class="text-brand-navy/70">{doc.title || doc.originalFilename}</span>
|
||||
{m.doc_edit_heading()} — <span class="text-brand-navy/70">{doc.title || doc.originalFilename}</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -58,20 +59,20 @@
|
||||
|
||||
<!-- ── Section 1: Wer & Wann ── -->
|
||||
<div class="bg-white shadow-sm border border-brand-sand rounded-sm p-6">
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">Wer & Wann</h2>
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">{m.doc_section_who_when()}</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<label for="documentDate" class="block text-sm font-medium text-gray-700 mb-1">Datum</label>
|
||||
<label for="documentDate" class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_date()}</label>
|
||||
<input
|
||||
id="documentDate"
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
value={dateDisplay}
|
||||
oninput={handleDateInput}
|
||||
placeholder="TT.MM.JJJJ"
|
||||
placeholder={m.form_placeholder_date()}
|
||||
maxlength="10"
|
||||
class="block w-full rounded border-gray-300 shadow-sm p-2 border text-sm
|
||||
{dateInvalid ? 'border-red-400 focus:border-red-500 focus:ring-red-500' : 'focus:border-brand-navy focus:ring-brand-navy'}"
|
||||
@@ -79,19 +80,19 @@
|
||||
/>
|
||||
<input type="hidden" name="documentDate" value={dateIso} />
|
||||
{#if dateInvalid}
|
||||
<p id="date-error" class="mt-1 text-xs text-red-600">Bitte im Format TT.MM.JJJJ eingeben, z.B. 20.12.2026</p>
|
||||
<p id="date-error" class="mt-1 text-xs text-red-600">{m.form_date_error()}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Ort -->
|
||||
<div>
|
||||
<label for="location" class="block text-sm font-medium text-gray-700 mb-1">Ort</label>
|
||||
<label for="location" class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_location()}</label>
|
||||
<input
|
||||
id="location"
|
||||
type="text"
|
||||
name="location"
|
||||
value={doc.location || ''}
|
||||
placeholder="z.B. Berlin, Wien…"
|
||||
placeholder={m.form_placeholder_location()}
|
||||
class="block w-full rounded border-gray-300 shadow-sm p-2 border focus:border-brand-navy focus:ring-brand-navy text-sm"
|
||||
/>
|
||||
</div>
|
||||
@@ -100,7 +101,7 @@
|
||||
<div>
|
||||
<PersonTypeahead
|
||||
name="senderId"
|
||||
label="Absender"
|
||||
label={m.form_label_sender()}
|
||||
bind:value={senderId}
|
||||
initialName={doc.sender ? `${doc.sender.firstName} ${doc.sender.lastName}` : ''}
|
||||
/>
|
||||
@@ -108,7 +109,7 @@
|
||||
|
||||
<!-- Empfänger -->
|
||||
<div>
|
||||
<p class="block text-sm font-medium text-gray-700 mb-1">Empfänger</p>
|
||||
<p class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_receivers()}</p>
|
||||
<PersonMultiSelect bind:selectedPersons={selectedReceivers} />
|
||||
</div>
|
||||
|
||||
@@ -117,13 +118,13 @@
|
||||
|
||||
<!-- ── Section 2: Beschreibung ── -->
|
||||
<div class="bg-white shadow-sm border border-brand-sand rounded-sm p-6">
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">Beschreibung</h2>
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">{m.doc_section_description()}</h2>
|
||||
|
||||
<div class="space-y-5">
|
||||
|
||||
<!-- Titel -->
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-1">Titel *</label>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_title()} *</label>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
@@ -136,33 +137,33 @@
|
||||
|
||||
<!-- Aufbewahrungsort -->
|
||||
<div>
|
||||
<label for="documentLocation" class="block text-sm font-medium text-gray-700 mb-1">Aufbewahrungsort</label>
|
||||
<label for="documentLocation" class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_archive_location()}</label>
|
||||
<input
|
||||
id="documentLocation"
|
||||
type="text"
|
||||
name="documentLocation"
|
||||
value={doc.documentLocation || ''}
|
||||
placeholder="z.B. Schrank 3, Mappe B"
|
||||
placeholder={m.form_placeholder_archive_location()}
|
||||
class="block w-full rounded border-gray-300 shadow-sm p-2 border focus:border-brand-navy focus:ring-brand-navy text-sm"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-400">Wo befindet sich das Originaldokument?</p>
|
||||
<p class="mt-1 text-xs text-gray-400">{m.form_helper_archive_location()}</p>
|
||||
</div>
|
||||
|
||||
<!-- Schlagworte -->
|
||||
<div>
|
||||
<p class="block text-sm font-medium text-gray-700 mb-1">Schlagworte</p>
|
||||
<p class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_tags()}</p>
|
||||
<TagInput bind:tags />
|
||||
<input type="hidden" name="tags" value={tags.join(',')} />
|
||||
</div>
|
||||
|
||||
<!-- Inhalt -->
|
||||
<div>
|
||||
<label for="summary" class="block text-sm font-medium text-gray-700 mb-1">Inhalt</label>
|
||||
<label for="summary" class="block text-sm font-medium text-gray-700 mb-1">{m.form_label_content()}</label>
|
||||
<textarea
|
||||
id="summary"
|
||||
name="summary"
|
||||
rows="5"
|
||||
placeholder="Kurze Beschreibung des Inhalts…"
|
||||
placeholder={m.form_placeholder_content()}
|
||||
class="block w-full rounded border-gray-300 shadow-sm p-2 border focus:border-brand-navy focus:ring-brand-navy text-sm font-serif"
|
||||
>{doc.summary || ''}</textarea>
|
||||
</div>
|
||||
@@ -172,27 +173,27 @@
|
||||
|
||||
<!-- ── Section 3: Transkription ── -->
|
||||
<div class="bg-white shadow-sm border border-brand-sand rounded-sm p-6">
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">Transkription</h2>
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">{m.form_label_transcription()}</h2>
|
||||
<textarea
|
||||
id="transcription"
|
||||
name="transcription"
|
||||
rows="12"
|
||||
placeholder="Vollständiger Text des Dokuments…"
|
||||
placeholder={m.form_placeholder_transcription()}
|
||||
class="block w-full rounded border-gray-300 shadow-sm p-2 border focus:border-brand-navy focus:ring-brand-navy text-sm font-serif"
|
||||
>{doc.transcription || ''}</textarea>
|
||||
</div>
|
||||
|
||||
<!-- ── Section 4: Datei ── -->
|
||||
<div class="bg-white shadow-sm border border-brand-sand rounded-sm p-6">
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">Datei</h2>
|
||||
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">{m.doc_section_file()}</h2>
|
||||
|
||||
<div class="flex items-center gap-3 mb-4 text-sm text-gray-600 bg-brand-sand/20 rounded px-3 py-2">
|
||||
<img src="/degruyter-icons/Simple/Medium-24px/SVG/Action/PDF-Document-MD.svg" alt="" aria-hidden="true" class="w-4 h-4 flex-shrink-0" />
|
||||
<span>Aktuelle Datei: <strong class="text-brand-navy font-medium">{doc.originalFilename}</strong></span>
|
||||
<span>{m.doc_current_file_label()} <strong class="text-brand-navy font-medium">{doc.originalFilename}</strong></span>
|
||||
</div>
|
||||
|
||||
<label for="file-upload" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Neue Datei hochladen <span class="font-normal text-gray-400">(ersetzt die aktuelle Datei)</span>
|
||||
{m.doc_file_replace_label()} <span class="font-normal text-gray-400">({m.doc_file_replace_note()})</span>
|
||||
</label>
|
||||
<input
|
||||
id="file-upload"
|
||||
@@ -213,13 +214,13 @@
|
||||
href="/documents/{doc.id}"
|
||||
class="text-sm text-gray-500 hover:text-brand-navy transition-colors font-medium"
|
||||
>
|
||||
Abbrechen
|
||||
{m.btn_cancel()}
|
||||
</a>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-6 py-2 bg-brand-navy text-white text-sm font-bold uppercase tracking-widest rounded hover:bg-brand-navy/80 transition-colors"
|
||||
>
|
||||
Speichern
|
||||
{m.btn_save()}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { enhance } from '$app/forms';
|
||||
import TagInput from '$lib/components/TagInput.svelte';
|
||||
import PersonTypeahead from '$lib/components/PersonTypeahead.svelte';
|
||||
import PersonMultiSelect from '$lib/components/PersonMultiSelect.svelte';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
let { form } = $props();
|
||||
|
||||
@@ -61,9 +62,9 @@ function handleDateInput(e: Event) {
|
||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||
/>
|
||||
</svg>
|
||||
Zurück zur Übersicht
|
||||
{m.btn_back_to_overview()}
|
||||
</a>
|
||||
<h1 class="font-serif text-3xl text-brand-navy">Neues Dokument</h1>
|
||||
<h1 class="font-serif text-3xl text-brand-navy">{m.doc_new_heading()}</h1>
|
||||
</div>
|
||||
|
||||
{#if form?.error}
|
||||
@@ -73,13 +74,13 @@ function handleDateInput(e: Event) {
|
||||
<form method="POST" enctype="multipart/form-data" use:enhance class="space-y-6 pb-20">
|
||||
<!-- ── Section 1: Wer & Wann ── -->
|
||||
<div class="rounded-sm border border-brand-sand bg-white p-6 shadow-sm">
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">Wer & Wann</h2>
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">{m.doc_section_who_when()}</h2>
|
||||
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2">
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<label for="documentDate" class="mb-1 block text-sm font-medium text-gray-700"
|
||||
>Datum</label
|
||||
>{m.form_label_date()}</label
|
||||
>
|
||||
<input
|
||||
id="documentDate"
|
||||
@@ -87,7 +88,7 @@ function handleDateInput(e: Event) {
|
||||
inputmode="numeric"
|
||||
value={dateDisplay}
|
||||
oninput={handleDateInput}
|
||||
placeholder="TT.MM.JJJJ"
|
||||
placeholder={m.form_placeholder_date()}
|
||||
maxlength="10"
|
||||
class="block w-full rounded border border-gray-300 p-2 text-sm shadow-sm
|
||||
{dateInvalid ? 'border-red-400 focus:border-red-500 focus:ring-red-500' : 'focus:border-brand-navy focus:ring-brand-navy'}"
|
||||
@@ -96,31 +97,31 @@ function handleDateInput(e: Event) {
|
||||
<input type="hidden" name="documentDate" value={dateIso} />
|
||||
{#if dateInvalid}
|
||||
<p id="date-error" class="mt-1 text-xs text-red-600">
|
||||
Bitte im Format TT.MM.JJJJ eingeben, z.B. 20.12.2026
|
||||
{m.form_date_error()}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Ort -->
|
||||
<div>
|
||||
<label for="location" class="mb-1 block text-sm font-medium text-gray-700">Ort</label>
|
||||
<label for="location" class="mb-1 block text-sm font-medium text-gray-700">{m.form_label_location()}</label>
|
||||
<input
|
||||
id="location"
|
||||
type="text"
|
||||
name="location"
|
||||
placeholder="z.B. Berlin, Wien…"
|
||||
placeholder={m.form_placeholder_location()}
|
||||
class="block w-full rounded border border-gray-300 p-2 text-sm shadow-sm focus:border-brand-navy focus:ring-brand-navy"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Absender -->
|
||||
<div>
|
||||
<PersonTypeahead name="senderId" label="Absender" bind:value={senderId} />
|
||||
<PersonTypeahead name="senderId" label={m.form_label_sender()} bind:value={senderId} />
|
||||
</div>
|
||||
|
||||
<!-- Empfänger -->
|
||||
<div>
|
||||
<p class="mb-1 block text-sm font-medium text-gray-700">Empfänger</p>
|
||||
<p class="mb-1 block text-sm font-medium text-gray-700">{m.form_label_receivers()}</p>
|
||||
<PersonMultiSelect bind:selectedPersons={selectedReceivers} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,12 +129,12 @@ function handleDateInput(e: Event) {
|
||||
|
||||
<!-- ── Section 2: Beschreibung ── -->
|
||||
<div class="rounded-sm border border-brand-sand bg-white p-6 shadow-sm">
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">Beschreibung</h2>
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">{m.doc_section_description()}</h2>
|
||||
|
||||
<div class="space-y-5">
|
||||
<!-- Titel -->
|
||||
<div>
|
||||
<label for="title" class="mb-1 block text-sm font-medium text-gray-700">Titel *</label>
|
||||
<label for="title" class="mb-1 block text-sm font-medium text-gray-700">{m.form_label_title()} *</label>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
@@ -146,33 +147,33 @@ function handleDateInput(e: Event) {
|
||||
<!-- Aufbewahrungsort -->
|
||||
<div>
|
||||
<label for="documentLocation" class="mb-1 block text-sm font-medium text-gray-700"
|
||||
>Aufbewahrungsort</label
|
||||
>{m.form_label_archive_location()}</label
|
||||
>
|
||||
<input
|
||||
id="documentLocation"
|
||||
type="text"
|
||||
name="documentLocation"
|
||||
placeholder="z.B. Schrank 3, Mappe B"
|
||||
placeholder={m.form_placeholder_archive_location()}
|
||||
class="block w-full rounded border border-gray-300 p-2 text-sm shadow-sm focus:border-brand-navy focus:ring-brand-navy"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-400">Wo befindet sich das Originaldokument?</p>
|
||||
<p class="mt-1 text-xs text-gray-400">{m.form_helper_archive_location()}</p>
|
||||
</div>
|
||||
|
||||
<!-- Schlagworte -->
|
||||
<div>
|
||||
<p class="mb-1 block text-sm font-medium text-gray-700">Schlagworte</p>
|
||||
<p class="mb-1 block text-sm font-medium text-gray-700">{m.form_label_tags()}</p>
|
||||
<TagInput bind:tags={tags} />
|
||||
<input type="hidden" name="tags" value={tags.join(',')} />
|
||||
</div>
|
||||
|
||||
<!-- Inhalt -->
|
||||
<div>
|
||||
<label for="summary" class="mb-1 block text-sm font-medium text-gray-700">Inhalt</label>
|
||||
<label for="summary" class="mb-1 block text-sm font-medium text-gray-700">{m.form_label_content()}</label>
|
||||
<textarea
|
||||
id="summary"
|
||||
name="summary"
|
||||
rows="5"
|
||||
placeholder="Kurze Beschreibung des Inhalts…"
|
||||
placeholder={m.form_placeholder_content()}
|
||||
class="block w-full rounded border border-gray-300 p-2 font-serif text-sm shadow-sm focus:border-brand-navy focus:ring-brand-navy"
|
||||
></textarea>
|
||||
</div>
|
||||
@@ -181,22 +182,22 @@ function handleDateInput(e: Event) {
|
||||
|
||||
<!-- ── Section 3: Transkription ── -->
|
||||
<div class="rounded-sm border border-brand-sand bg-white p-6 shadow-sm">
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">Transkription</h2>
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">{m.form_label_transcription()}</h2>
|
||||
<textarea
|
||||
id="transcription"
|
||||
name="transcription"
|
||||
rows="12"
|
||||
placeholder="Vollständiger Text des Dokuments…"
|
||||
placeholder={m.form_placeholder_transcription()}
|
||||
class="block w-full rounded border border-gray-300 p-2 font-serif text-sm shadow-sm focus:border-brand-navy focus:ring-brand-navy"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- ── Section 4: Datei ── -->
|
||||
<div class="rounded-sm border border-brand-sand bg-white p-6 shadow-sm">
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">Datei</h2>
|
||||
<h2 class="mb-5 text-xs font-bold tracking-widest text-gray-400 uppercase">{m.doc_section_file()}</h2>
|
||||
|
||||
<label for="file-upload" class="mb-1 block text-sm font-medium text-gray-700">
|
||||
Datei hochladen <span class="font-normal text-gray-400">(optional)</span>
|
||||
{m.doc_file_upload_label()} <span class="font-normal text-gray-400">({m.doc_file_upload_note()})</span>
|
||||
</label>
|
||||
<input
|
||||
id="file-upload"
|
||||
@@ -216,13 +217,13 @@ function handleDateInput(e: Event) {
|
||||
class="sticky bottom-0 z-10 -mx-4 flex items-center justify-between border-t border-brand-sand bg-white px-6 py-4 shadow-[0_-2px_8px_rgba(0,0,0,0.06)]"
|
||||
>
|
||||
<a href="/" class="text-sm font-medium text-gray-500 transition-colors hover:text-brand-navy">
|
||||
Abbrechen
|
||||
{m.btn_cancel()}
|
||||
</a>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded bg-brand-navy px-6 py-2 text-sm font-bold tracking-widest text-white uppercase transition-colors hover:bg-brand-navy/80"
|
||||
>
|
||||
Speichern
|
||||
{m.btn_save()}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user