From c220815b89d295064326aa9e1842c308532a01d6 Mon Sep 17 00:00:00 2001 From: lew Date: Tue, 24 Mar 2026 02:33:35 +0000 Subject: [PATCH] fix(state): changing species clears language, citizenship, and subspecies selections --- data/schema/template.xsd | 2 + data/templates/ipc.xml | 24 +++---- data/templates/standard.xml | 3 +- package-lock.json | 63 ------------------- src/lib/components/CharacterSwitcher.svelte | 6 +- src/lib/components/Header.svelte | 4 +- src/lib/components/ImportModal.svelte | 4 +- src/lib/components/RecordCard.svelte | 5 +- src/lib/components/SchemaForm.svelte | 21 ++++++- .../components/fields/CitizenshipField.svelte | 21 +++++-- src/lib/components/fields/DynamicField.svelte | 11 +++- .../components/fields/LanguagesField.svelte | 16 +++-- .../components/fields/SeparatorField.svelte | 15 +++++ src/lib/data/parse.ts | 3 + src/lib/file.ts | 5 +- src/lib/output.ts | 29 +++++++-- src/lib/schema.ts | 2 + src/lib/state.svelte.ts | 24 +++++++ src/lib/types.ts | 14 ++++- src/lib/utils/blank.ts | 4 +- 20 files changed, 172 insertions(+), 104 deletions(-) create mode 100644 src/lib/components/fields/SeparatorField.svelte diff --git a/data/schema/template.xsd b/data/schema/template.xsd index 4826112..8aac7f2 100644 --- a/data/schema/template.xsd +++ b/data/schema/template.xsd @@ -43,6 +43,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/data/templates/ipc.xml b/data/templates/ipc.xml index 63587a7..a6428a8 100644 --- a/data/templates/ipc.xml +++ b/data/templates/ipc.xml @@ -4,18 +4,8 @@ Basic identification information visible on all records. - - - + - - - - - + + + + + + + + + diff --git a/data/templates/standard.xml b/data/templates/standard.xml index f6244d4..077a101 100644 --- a/data/templates/standard.xml +++ b/data/templates/standard.xml @@ -4,7 +4,7 @@ Basic identification information visible on all records. - + @@ -19,6 +19,7 @@ + diff --git a/package-lock.json b/package-lock.json index 7e77c12..14db5e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -828,9 +828,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -845,9 +842,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -862,9 +856,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -879,9 +870,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -896,9 +884,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -913,9 +898,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -930,9 +912,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -947,9 +926,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -964,9 +940,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -981,9 +954,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -998,9 +968,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1015,9 +982,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1032,9 +996,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1375,9 +1336,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1395,9 +1353,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1415,9 +1370,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1435,9 +1387,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2285,9 +2234,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2309,9 +2255,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2333,9 +2276,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2357,9 +2297,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/src/lib/components/CharacterSwitcher.svelte b/src/lib/components/CharacterSwitcher.svelte index fefd1ed..2d0b9b1 100644 --- a/src/lib/components/CharacterSwitcher.svelte +++ b/src/lib/components/CharacterSwitcher.svelte @@ -2,8 +2,10 @@ import { roster } from '$lib/state.svelte'; import { slugify } from '$lib/utils/slugify'; - function displayName(char: { data: Record }): string { - const name = char.data[slugify('Name')]; + function displayName(char: { template: { records: { fields: { type: string; label: string }[] }[] }; data: Record }): string { + const nameField = char.template.records.flatMap((r) => r.fields).find((f) => f.type === 'name'); + const key = nameField ? slugify(nameField.label) : slugify('Name'); + const name = char.data[key]; return (name as string) || 'Unnamed Character'; } diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte index ad32172..a922ccb 100644 --- a/src/lib/components/Header.svelte +++ b/src/lib/components/Header.svelte @@ -46,7 +46,9 @@ function displayName(): string { const char = roster.active; if (!char) return ''; - const name = char.data[slugify('Name')]; + const nameField = char.template.records.flatMap((r) => r.fields).find((f) => f.type === 'name'); + const key = nameField ? slugify(nameField.label) : slugify('Name'); + const name = char.data[key]; return (name as string) || 'Unnamed Character'; } diff --git a/src/lib/components/ImportModal.svelte b/src/lib/components/ImportModal.svelte index 9c7a6c0..2296da8 100644 --- a/src/lib/components/ImportModal.svelte +++ b/src/lib/components/ImportModal.svelte @@ -63,7 +63,9 @@ function charName(): string { if (!charData) return 'Unknown'; - return (charData.data[slugify('Name')] as string) || 'Unnamed Character'; + const nameField = charData.template.records.flatMap((r: any) => r.fields).find((f: any) => f.type === 'name'); + const key = nameField ? slugify(nameField.label) : slugify('Name'); + return (charData.data[key] as string) || 'Unnamed Character'; } async function importCharacter() { diff --git a/src/lib/components/RecordCard.svelte b/src/lib/components/RecordCard.svelte index 793f468..cfb1a9f 100644 --- a/src/lib/components/RecordCard.svelte +++ b/src/lib/components/RecordCard.svelte @@ -13,8 +13,9 @@ let expanded = $state(false); + let dataFields = $derived(record.fields.filter((f) => f.type !== 'separator')); let filled = $derived( - record.fields.filter((f) => { + dataFields.filter((f) => { const v = data[slugify(f.label)]; if (v === undefined || v === null || v === '' || v === 0) return false; if (Array.isArray(v) && v.length === 0) return false; @@ -47,7 +48,7 @@ {/if} - {filled}/{record.fields.length} + {filled}/{dataFields.length} diff --git a/src/lib/components/SchemaForm.svelte b/src/lib/components/SchemaForm.svelte index a976b3b..9654bd9 100644 --- a/src/lib/components/SchemaForm.svelte +++ b/src/lib/components/SchemaForm.svelte @@ -14,6 +14,17 @@ let showTemplateSwitcher = $state(false); let showMigrationModal = $state(false); + let speciesKeys = $derived(new Set( + character.template.records.flatMap((r) => r.fields) + .filter((f) => f.type === 'species') + .map((f) => slugify(f.label)) + )); + const SPECIES_DEPENDENT_TYPES = new Set(['subspecies', 'citizenship', 'languages']); + let speciesDependentKeys = $derived(new Set( + character.template.records.flatMap((r) => r.fields) + .filter((f) => SPECIES_DEPENDENT_TYPES.has(f.type)) + .map((f) => slugify(f.label)) + )); let speciesKey = slugify('Species'); let pendingMigration = $derived.by(() => { @@ -59,9 +70,8 @@ return null; }); - function switchTemplate(template: Template) { - character.template = $state.snapshot(template); - roster.scheduleSave(character); + async function switchTemplate(template: Template) { + await roster.migrateToPreset(character, template); dismissed = null; showTemplateSwitcher = false; } @@ -143,6 +153,11 @@ data={character.data} onFieldChange={(key, value) => { character.data[key] = value; + if (speciesKeys.has(key)) { + for (const depKey of speciesDependentKeys) { + character.data[depKey] = ''; + } + } roster.scheduleSave(character); }} /> diff --git a/src/lib/components/fields/CitizenshipField.svelte b/src/lib/components/fields/CitizenshipField.svelte index 6647a31..d15c9a2 100644 --- a/src/lib/components/fields/CitizenshipField.svelte +++ b/src/lib/components/fields/CitizenshipField.svelte @@ -1,8 +1,21 @@