From a01c6e8d31815763d2b85f5642adc8aaa69c3783 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 21 Dec 2025 22:22:57 -0800 Subject: [PATCH] add extra_prerequisite and forge chain to weapon database pages --- src/lib/components/ui/WeaponTypeahead.svelte | 364 ++++++++++++++++++ .../sections/WeaponForgeSection.svelte | 159 ++++++++ .../sections/WeaponUncapSection.svelte | 26 ++ src/lib/types/api/entities.ts | 5 + .../weapons/[granblueId]/+page.svelte | 2 + .../weapons/[granblueId]/edit/+page.svelte | 20 +- .../database/weapons/import/+page.svelte | 19 +- .../(app)/database/weapons/new/+page.svelte | 16 +- 8 files changed, 604 insertions(+), 7 deletions(-) create mode 100644 src/lib/components/ui/WeaponTypeahead.svelte create mode 100644 src/lib/features/database/weapons/sections/WeaponForgeSection.svelte diff --git a/src/lib/components/ui/WeaponTypeahead.svelte b/src/lib/components/ui/WeaponTypeahead.svelte new file mode 100644 index 00000000..73444a4b --- /dev/null +++ b/src/lib/components/ui/WeaponTypeahead.svelte @@ -0,0 +1,364 @@ + + + + + + +
+ + {#snippet toggleIcon(dropdownShow)} + + {/snippet} + {#snippet option(opt)} + {@const weapon = opt as WeaponOption} +
+ + {weapon.label} +
+ {/snippet} + {#snippet selection(sel)} + {@const weapon = (sel as WeaponOption[])[0]} + {#if weapon} +
+ + {weapon.label} +
+ {/if} + {/snippet} +
+ {#if isLoading} + ... + {/if} +
+ + diff --git a/src/lib/features/database/weapons/sections/WeaponForgeSection.svelte b/src/lib/features/database/weapons/sections/WeaponForgeSection.svelte new file mode 100644 index 00000000..9712615d --- /dev/null +++ b/src/lib/features/database/weapons/sections/WeaponForgeSection.svelte @@ -0,0 +1,159 @@ + + + + +{#if hasForgeData} + + {#if editMode} + + + + + {:else} + {#if forgeChain.length > 0} + +
+ {#each forgeChain as chainWeapon, index} + + + {chainWeapon.name?.en || chainWeapon.name?.ja} + ({chainWeapon.forgeOrder}) + + {#if index < forgeChain.length - 1} + + {/if} + {/each} +
+
+ {/if} + + {#if forgedFrom && forgeChain.length === 0} + + + {forgedFrom.name?.en || forgedFrom.name?.ja} + + + {/if} + + {#if forgeOrder != null} + + {/if} + {/if} +
+{/if} + + diff --git a/src/lib/features/database/weapons/sections/WeaponUncapSection.svelte b/src/lib/features/database/weapons/sections/WeaponUncapSection.svelte index cde07d2c..48ab085a 100644 --- a/src/lib/features/database/weapons/sections/WeaponUncapSection.svelte +++ b/src/lib/features/database/weapons/sections/WeaponUncapSection.svelte @@ -46,6 +46,22 @@ const uncapLevel = $derived(transcendence ? 6 : ulb ? 5 : flb ? 4 : 3) const transcendenceStage = $derived(transcendence ? 5 : 0) + // Extra prerequisite options for dropdown + const extraPrerequisiteOptions = [ + { value: '', label: 'None' }, + { value: 3, label: 'MLB' }, + { value: 4, label: 'FLB' }, + { value: 5, label: 'ULB' }, + { value: 6, label: 'Transcendence' } + ] + + // Get label for extra prerequisite value + function getExtraPrerequisiteLabel(value: number | null | undefined): string { + if (value == null) return '—' + const option = extraPrerequisiteOptions.find((o) => o.value === value) + return option?.label ?? '—' + } + // Get element name for checkbox theming const elementName = $derived.by((): ElementName | undefined => { const el = editMode ? editData.element : weapon?.element @@ -132,5 +148,15 @@ element={elementName} onchange={handleTranscendenceChange} /> + + {:else if weapon?.uncap?.extraPrerequisite != null} + {/if} diff --git a/src/lib/types/api/entities.ts b/src/lib/types/api/entities.ts index 2f2b3a99..dade4861 100644 --- a/src/lib/types/api/entities.ts +++ b/src/lib/types/api/entities.ts @@ -42,6 +42,7 @@ export interface Weapon { flb: boolean ulb: boolean transcendence: boolean + extraPrerequisite?: number | null } transcendenceHp?: number transcendenceAtk?: number @@ -57,6 +58,10 @@ export interface Weapon { kamigame?: string nicknames?: { en?: string[]; ja?: string[] } recruits?: string | { id: string; granblueId: string; name: LocalizedName } + // Forge chain fields + forgeOrder?: number | null + forgedFrom?: { id: string; granblueId: string; name: LocalizedName } | null + forgeChain?: Array<{ id: string; granblueId: string; name: LocalizedName; forgeOrder: number }> | null } // Character entity from CharacterBlueprint diff --git a/src/routes/(app)/database/weapons/[granblueId]/+page.svelte b/src/routes/(app)/database/weapons/[granblueId]/+page.svelte index cf515899..c72538c5 100644 --- a/src/routes/(app)/database/weapons/[granblueId]/+page.svelte +++ b/src/routes/(app)/database/weapons/[granblueId]/+page.svelte @@ -25,6 +25,7 @@ import WeaponTaxonomySection from '$lib/features/database/weapons/sections/WeaponTaxonomySection.svelte' import WeaponStatsSection from '$lib/features/database/weapons/sections/WeaponStatsSection.svelte' import WeaponGachaSection from '$lib/features/database/weapons/sections/WeaponGachaSection.svelte' + import WeaponForgeSection from '$lib/features/database/weapons/sections/WeaponForgeSection.svelte' import EntityImagesTab from '$lib/features/database/detail/tabs/EntityImagesTab.svelte' import EntityRawDataTab from '$lib/features/database/detail/tabs/EntityRawDataTab.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' @@ -205,6 +206,7 @@ + diff --git a/src/routes/(app)/database/weapons/[granblueId]/edit/+page.svelte b/src/routes/(app)/database/weapons/[granblueId]/edit/+page.svelte index 4a815587..69036a7f 100644 --- a/src/routes/(app)/database/weapons/[granblueId]/edit/+page.svelte +++ b/src/routes/(app)/database/weapons/[granblueId]/edit/+page.svelte @@ -17,6 +17,7 @@ import WeaponTaxonomySection from '$lib/features/database/weapons/sections/WeaponTaxonomySection.svelte' import WeaponStatsSection from '$lib/features/database/weapons/sections/WeaponStatsSection.svelte' import WeaponGachaSection from '$lib/features/database/weapons/sections/WeaponGachaSection.svelte' + import WeaponForgeSection from '$lib/features/database/weapons/sections/WeaponForgeSection.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' import DetailItem from '$lib/components/ui/DetailItem.svelte' import TagInput from '$lib/components/ui/TagInput.svelte' @@ -74,6 +75,7 @@ flb: false, ulb: false, transcendence: false, + extraPrerequisite: '' as number | '', extra: false, limit: false, ax: false, @@ -88,7 +90,10 @@ kamigame: '', nicknamesEn: [] as string[], nicknamesJp: [] as string[], - recruits: '' + recruits: '', + // Forge chain fields + forgedFrom: '' as string | null, + forgeOrder: null as number | null }) // Populate edit data when weapon loads @@ -117,6 +122,7 @@ flb: weapon.uncap?.flb || false, ulb: weapon.uncap?.ulb || false, transcendence: weapon.uncap?.transcendence || false, + extraPrerequisite: weapon.uncap?.extraPrerequisite ?? '', extra: weapon.extra || false, limit: Boolean(weapon.limit), ax: weapon.ax || false, @@ -131,7 +137,10 @@ kamigame: weapon.kamigame || '', nicknamesEn: weapon.nicknames?.en || [], nicknamesJp: weapon.nicknames?.ja || [], - recruits: typeof weapon.recruits === 'string' ? weapon.recruits : (weapon.recruits?.granblueId ?? '') + recruits: typeof weapon.recruits === 'string' ? weapon.recruits : (weapon.recruits?.granblueId ?? ''), + // Forge chain fields + forgedFrom: weapon.forgedFrom?.granblueId || null, + forgeOrder: weapon.forgeOrder ?? null } } }) @@ -165,6 +174,7 @@ flb: editData.flb, ulb: editData.ulb, transcendence: editData.transcendence, + extra_prerequisite: editData.extraPrerequisite === '' ? null : editData.extraPrerequisite, extra: editData.extra, limit: editData.limit, ax: editData.ax, @@ -179,7 +189,10 @@ kamigame: editData.kamigame, nicknames_en: editData.nicknamesEn, nicknames_jp: editData.nicknamesJp, - recruits: editData.recruits || undefined + recruits: editData.recruits || undefined, + // Forge chain fields + forged_from: editData.forgedFrom || null, + forge_order: editData.forgeOrder } await entityAdapter.updateWeapon(weapon.id, payload) @@ -226,6 +239,7 @@ + diff --git a/src/routes/(app)/database/weapons/import/+page.svelte b/src/routes/(app)/database/weapons/import/+page.svelte index ffbc1524..23c8fa99 100644 --- a/src/routes/(app)/database/weapons/import/+page.svelte +++ b/src/routes/(app)/database/weapons/import/+page.svelte @@ -20,6 +20,7 @@ import WeaponStatsSection from '$lib/features/database/weapons/sections/WeaponStatsSection.svelte' import WeaponMetadataSection from '$lib/features/database/weapons/sections/WeaponMetadataSection.svelte' import WeaponGachaSection from '$lib/features/database/weapons/sections/WeaponGachaSection.svelte' + import WeaponForgeSection from '$lib/features/database/weapons/sections/WeaponForgeSection.svelte' import TabbedEntitySelector from '$lib/features/database/import/TabbedEntitySelector.svelte' import type { EntityTab } from '$lib/features/database/import/TabbedEntitySelector.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' @@ -123,6 +124,7 @@ flb: suggestions?.flb ?? false, ulb: suggestions?.ulb ?? false, transcendence: suggestions?.transcendence ?? false, + extraPrerequisite: '' as number | '', extra: false, limit: false, ax: false, @@ -136,7 +138,10 @@ kamigame: suggestions?.kamigame ?? '', nicknamesEn: [] as string[], nicknamesJp: [] as string[], - recruits: suggestions?.recruits ?? null + recruits: suggestions?.recruits ?? null, + // Forge chain + forgedFrom: null as string | null, + forgeOrder: null as number | null } } @@ -279,6 +284,7 @@ flb: formData.flb, ulb: formData.ulb, transcendence: formData.transcendence, + extra_prerequisite: formData.extraPrerequisite === '' ? null : formData.extraPrerequisite, extra: formData.extra, limit: formData.limit, ax: formData.ax, @@ -293,7 +299,10 @@ nicknames_en: formData.nicknamesEn, nicknames_jp: formData.nicknamesJp, recruits: formData.recruits, - wiki_raw: wikiRawByPage[selectedWikiPage] || undefined + wiki_raw: wikiRawByPage[selectedWikiPage] || undefined, + // Forge chain + forged_from: formData.forgedFrom || null, + forge_order: formData.forgeOrder } const newWeapon = await entityAdapter.createWeapon(payload) @@ -510,6 +519,12 @@ onDismissSuggestion={handleDismissSuggestion} /> + + diff --git a/src/routes/(app)/database/weapons/new/+page.svelte b/src/routes/(app)/database/weapons/new/+page.svelte index 85b7a4b8..53bf4625 100644 --- a/src/routes/(app)/database/weapons/new/+page.svelte +++ b/src/routes/(app)/database/weapons/new/+page.svelte @@ -12,6 +12,7 @@ import WeaponUncapSection from '$lib/features/database/weapons/sections/WeaponUncapSection.svelte' import WeaponTaxonomySection from '$lib/features/database/weapons/sections/WeaponTaxonomySection.svelte' import WeaponStatsSection from '$lib/features/database/weapons/sections/WeaponStatsSection.svelte' + import WeaponForgeSection from '$lib/features/database/weapons/sections/WeaponForgeSection.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' import DetailItem from '$lib/components/ui/DetailItem.svelte' import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte' @@ -79,6 +80,7 @@ flb: false, ulb: false, transcendence: false, + extraPrerequisite: '' as number | '', extra: false, limit: false, ax: false, @@ -100,7 +102,11 @@ nicknamesJp: [] as string[], // Recruits (Character ID) - recruits: null as string | null + recruits: null as string | null, + + // Forge chain + forgedFrom: null as string | null, + forgeOrder: null as number | null }) const rarityOptions = getRarityOptions() @@ -183,6 +189,7 @@ flb: editData.flb, ulb: editData.ulb, transcendence: editData.transcendence, + extra_prerequisite: editData.extraPrerequisite === '' ? null : editData.extraPrerequisite, extra: editData.extra, limit: editData.limit, ax: editData.ax, @@ -204,7 +211,11 @@ nicknames_jp: editData.nicknamesJp, // Recruits - recruits: editData.recruits + recruits: editData.recruits, + + // Forge chain + forged_from: editData.forgedFrom || null, + forge_order: editData.forgeOrder } const newWeapon = await entityAdapter.createWeapon(payload) @@ -285,6 +296,7 @@ +