feat(persons): add type selector + title + conditional fields to edit form

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-25 21:45:09 +02:00
committed by marcel
parent 110416d68b
commit 7699a4e7e2
2 changed files with 118 additions and 56 deletions

View File

@@ -6,7 +6,11 @@ import { m } from '$lib/paraglide/messages.js';
const TYPES = ['PERSON', 'INSTITUTION', 'GROUP', 'UNKNOWN'] as const; const TYPES = ['PERSON', 'INSTITUTION', 'GROUP', 'UNKNOWN'] as const;
type PersonType = (typeof TYPES)[number]; type PersonType = (typeof TYPES)[number];
let { value = 'PERSON', name = 'personType' }: { value?: string; name?: string } = $props(); let {
value = 'PERSON',
name = 'personType',
onchange
}: { value?: string; name?: string; onchange?: (type: PersonType) => void } = $props();
let selected = $state<PersonType>( let selected = $state<PersonType>(
untrack(() => (TYPES.includes(value as PersonType) ? (value as PersonType) : 'PERSON')) untrack(() => (TYPES.includes(value as PersonType) ? (value as PersonType) : 'PERSON'))
@@ -21,6 +25,7 @@ const labels: Record<PersonType, () => string> = {
function select(type: PersonType) { function select(type: PersonType) {
selected = type; selected = type;
onchange?.(type);
} }
</script> </script>

View File

@@ -1,10 +1,16 @@
<script lang="ts"> <script lang="ts">
import { untrack } from 'svelte';
import { m } from '$lib/paraglide/messages.js'; import { m } from '$lib/paraglide/messages.js';
import PersonTypeSelector from '$lib/components/PersonTypeSelector.svelte';
type PersonType = 'PERSON' | 'INSTITUTION' | 'GROUP' | 'UNKNOWN';
let { let {
person person
}: { }: {
person: { person: {
personType?: string | null;
title?: string | null;
firstName?: string | null; firstName?: string | null;
lastName: string; lastName: string;
alias?: string | null; alias?: string | null;
@@ -13,25 +19,68 @@ let {
notes?: string | null; notes?: string | null;
}; };
} = $props(); } = $props();
const TYPES = ['PERSON', 'INSTITUTION', 'GROUP', 'UNKNOWN'] as const;
let selectedType = $state<PersonType>(
untrack(() =>
TYPES.includes(person.personType as PersonType) ? (person.personType as PersonType) : 'PERSON'
)
);
const isPerson = $derived(selectedType === 'PERSON');
const lastNameLabel = $derived(
selectedType === 'INSTITUTION' || selectedType === 'GROUP'
? m.form_label_name()
: m.form_label_last_name()
);
</script> </script>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div> <div class="md:col-span-2">
<label for="firstName" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" <p class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase">
>{m.form_label_first_name()} *</label {m.form_label_person_type()}
> </p>
<input <PersonTypeSelector
id="firstName" value={selectedType}
name="firstName" name="personType"
type="text" onchange={(type: PersonType) => (selectedType = type)}
required
value={person.firstName}
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/> />
</div> </div>
<div>
{#if isPerson}
<div>
<label for="title" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
>{m.form_label_title()}</label
>
<input
id="title"
name="title"
type="text"
maxlength="50"
value={person.title ?? ''}
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
<div>
<label
for="firstName"
class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
>{m.form_label_first_name()} *</label
>
<input
id="firstName"
name="firstName"
type="text"
required
value={person.firstName ?? ''}
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
{/if}
<div class={!isPerson ? 'md:col-span-2' : ''}>
<label for="lastName" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" <label for="lastName" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
>{m.form_label_last_name()} *</label >{lastNameLabel} *</label
> >
<input <input
id="lastName" id="lastName"
@@ -42,48 +91,56 @@ let {
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/> />
</div> </div>
<div class="md:col-span-2">
<label for="alias" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" {#if isPerson}
>{m.form_label_alias()}</label <div class="md:col-span-2">
> <label for="alias" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
<input >{m.form_label_alias()}</label
id="alias" >
name="alias" <input
type="text" id="alias"
value={person.alias ?? ''} name="alias"
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" type="text"
/> value={person.alias ?? ''}
</div> class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
<div> />
<label for="birthYear" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" </div>
>{m.person_label_birth_year()}</label <div>
> <label
<input for="birthYear"
id="birthYear" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
name="birthYear" >{m.person_label_birth_year()}</label
type="number" >
min="1" <input
max="2100" id="birthYear"
placeholder={m.person_placeholder_year()} name="birthYear"
value={person.birthYear ?? ''} type="number"
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" min="1"
/> max="2100"
</div> placeholder={m.person_placeholder_year()}
<div> value={person.birthYear ?? ''}
<label for="deathYear" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
>{m.person_label_death_year()}</label />
> </div>
<input <div>
id="deathYear" <label
name="deathYear" for="deathYear"
type="number" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
min="1" >{m.person_label_death_year()}</label
max="2100" >
placeholder={m.person_placeholder_year()} <input
value={person.deathYear ?? ''} id="deathYear"
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" name="deathYear"
/> type="number"
</div> min="1"
max="2100"
placeholder={m.person_placeholder_year()}
value={person.deathYear ?? ''}
class="block w-full rounded border border-line px-3 py-2 font-serif text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
{/if}
<div class="md:col-span-2"> <div class="md:col-span-2">
<label for="notes" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase" <label for="notes" class="mb-1 block text-xs font-bold tracking-widest text-ink-3 uppercase"
>{m.person_label_notes()}</label >{m.person_label_notes()}</label