feat(#68): lead new document form with file upload, all metadata optional
Some checks failed
CI / Unit & Component Tests (push) Failing after 1m17s
CI / Backend Unit Tests (push) Failing after 9h3m48s
CI / E2E Tests (push) Failing after 28m15s

Restructure the "New Document" page so users can save quickly:

- FileSectionNew becomes the first element, redesigned as a prominent
  upload zone with an icon and large click target
- Title field is rendered standalone below the upload zone; it
  auto-populates from the filename (via parseFilename + stripExtension
  fallback) unless the user has already typed something
- All remaining metadata (who/when, description, transcription) moves
  into a collapsible "Weitere Details" section that auto-expands when
  URL prefill data or a form error is present, or when filename parsing
  detects a date/person
- title is no longer required — the form can be saved with only a file
- DescriptionSection gains a `hideTitle` prop for use in this layout
- `form_label_title` translation key no longer carries a hardcoded `*`;
  the asterisk is rendered by the template only when `titleRequired` is
  set (currently only the edit form)
- E2E tests added for all three scenarios from the issue

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-26 22:52:12 +01:00
parent d6f4ea05d9
commit c5e28ac18e
7 changed files with 203 additions and 67 deletions

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { parseFilename, type FilenameParseResult } from '$lib/utils/filename';
import { parseFilename, stripExtension, type FilenameParseResult } from '$lib/utils/filename';
let {
onfileParsed
@@ -10,29 +10,58 @@ let {
function handleFileChange(e: Event) {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) onfileParsed?.(parseFilename(file.name));
if (!file) return;
const parsed = parseFilename(file.name);
const result: FilenameParseResult = {
...parsed,
suggestedTitle: parsed.suggestedTitle ?? stripExtension(file.name)
};
onfileParsed?.(result);
}
</script>
<div class="rounded-sm border border-line bg-surface p-6 shadow-sm">
<h2 class="mb-5 text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.doc_section_file()}
</h2>
<div class="rounded-sm border border-line bg-surface shadow-sm">
<div class="border-b border-line px-6 py-4">
<h2 class="text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.doc_section_file()}
</h2>
</div>
<label for="file-upload" class="mb-1 block text-sm font-medium text-ink-2">
{m.doc_file_upload_label()}
<span class="font-normal text-ink-3">({m.doc_file_upload_note()})</span>
<label
for="file-upload"
class="flex cursor-pointer flex-col items-center gap-3 px-6 py-10 transition-colors hover:bg-muted/40"
>
<svg
class="h-10 w-10 text-ink-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
/>
</svg>
<span class="text-sm font-medium text-ink-2">
{m.doc_file_upload_label()}
</span>
<span class="text-xs text-ink-3">{m.doc_file_upload_note()}</span>
</label>
<input
id="file-upload"
type="file"
name="file"
onchange={handleFileChange}
class="block w-full cursor-pointer text-sm
text-ink-2 file:mr-4 file:rounded
file:border-0 file:bg-muted
file:px-4 file:py-2
file:text-sm file:font-semibold
file:text-ink hover:file:bg-muted"
/>
<div class="px-6 pb-6">
<input
id="file-upload"
type="file"
name="file"
onchange={handleFileChange}
class="block w-full cursor-pointer rounded border border-dashed border-line p-2 text-sm
text-ink-2 file:mr-4 file:rounded
file:border-0 file:bg-muted
file:px-4 file:py-2
file:text-sm file:font-semibold
file:text-ink hover:file:bg-muted"
/>
</div>
</div>