move season field to Metadata section

This commit is contained in:
Justin Edmund 2025-12-15 09:52:03 -08:00
parent 75a97cabaa
commit 879a3bd8bd
2 changed files with 40 additions and 77 deletions

View file

@ -6,8 +6,10 @@
import DetailItem from '$lib/components/ui/DetailItem.svelte' import DetailItem from '$lib/components/ui/DetailItem.svelte'
import SuggestionDetailItem from '$lib/components/ui/SuggestionDetailItem.svelte' import SuggestionDetailItem from '$lib/components/ui/SuggestionDetailItem.svelte'
import CopyableText from '$lib/components/ui/CopyableText.svelte' import CopyableText from '$lib/components/ui/CopyableText.svelte'
import Select from '$lib/components/ui/Select.svelte'
import { getRarityLabel, getRarityOptions } from '$lib/utils/rarity' import { getRarityLabel, getRarityOptions } from '$lib/utils/rarity'
import { getWeaponImage } from '$lib/utils/images' import { getWeaponImage } from '$lib/utils/images'
import { CHARACTER_SEASON_NAMES, getSeasonName } from '$lib/types/enums'
interface Props { interface Props {
character: any character: any
@ -32,6 +34,15 @@
const rarityOptions = getRarityOptions() const rarityOptions = getRarityOptions()
// Season options (nullable, so include a "None" option)
const seasonOptions = [
{ value: 0, label: 'None' },
...Object.entries(CHARACTER_SEASON_NAMES).map(([value, label]) => ({
value: Number(value),
label
}))
]
function formatPromotions(promotionNames: string[] | undefined): string { function formatPromotions(promotionNames: string[] | undefined): string {
if (!promotionNames || promotionNames.length === 0) return '—' if (!promotionNames || promotionNames.length === 0) return '—'
return promotionNames.join(', ') return promotionNames.join(', ')
@ -52,13 +63,30 @@
onDismissSuggestion={() => onDismissSuggestion?.('rarity')} onDismissSuggestion={() => onDismissSuggestion?.('rarity')}
/> />
<DetailItem <DetailItem
label="Granblue ID" label="Season"
bind:value={editData.granblueId} sublabel="Used to disambiguate characters with the same name"
editable={true}
>
<Select
size="medium"
options={seasonOptions}
bind:value={editData.season}
contained
/>
</DetailItem>
<DetailItem
label="Character ID"
sublabel="Separate multiple IDs with commas"
bind:value={editData.characterId}
editable={true} editable={true}
type="text" type="text"
placeholder="Character IDs"
/> />
{:else} {:else}
<DetailItem label="Rarity" value={getRarityLabel(character.rarity)} /> <DetailItem label="Rarity" value={getRarityLabel(character.rarity)} />
{#if character.season}
<DetailItem label="Season" value={getSeasonName(character.season) || '—'} />
{/if}
<DetailItem label="Granblue ID"> <DetailItem label="Granblue ID">
{#if character.granblueId} {#if character.granblueId}
<CopyableText value={character.granblueId} /> <CopyableText value={character.granblueId} />
@ -66,6 +94,11 @@
{/if} {/if}
</DetailItem> </DetailItem>
{#if character.characterId?.length}
<DetailItem label="Character ID">
<CopyableText value={character.characterId.join(', ')} />
</DetailItem>
{/if}
{#if character.recruitedBy} {#if character.recruitedBy}
<DetailItem label="Recruited By"> <DetailItem label="Recruited By">
<a href="/database/weapons/{character.recruitedBy.id}" class="recruited-by-link"> <a href="/database/weapons/{character.recruitedBy.id}" class="recruited-by-link">

View file

@ -8,22 +8,11 @@
import MultiSelect from '$lib/components/ui/MultiSelect.svelte' import MultiSelect from '$lib/components/ui/MultiSelect.svelte'
import ElementLabel from '$lib/components/labels/ElementLabel.svelte' import ElementLabel from '$lib/components/labels/ElementLabel.svelte'
import ProficiencyLabel from '$lib/components/labels/ProficiencyLabel.svelte' import ProficiencyLabel from '$lib/components/labels/ProficiencyLabel.svelte'
import { getElementLabel, getElementOptions } from '$lib/utils/element' import { getElementOptions } from '$lib/utils/element'
import { getRaceLabel, getRaceOptions } from '$lib/utils/race' import { getRaceLabel, getRaceOptions } from '$lib/utils/race'
import { getGenderLabel, getGenderOptions } from '$lib/utils/gender' import { getGenderLabel, getGenderOptions } from '$lib/utils/gender'
import { getProficiencyOptions } from '$lib/utils/proficiency' import { getProficiencyOptions } from '$lib/utils/proficiency'
import { import { CHARACTER_SERIES_NAMES, getSeriesNames } from '$lib/types/enums'
CharacterSeason,
CharacterSeries,
CHARACTER_SEASON_NAMES,
CHARACTER_SERIES_NAMES,
PROMOTION_NAMES,
getSeasonName,
getSeriesNames,
getPromotionNames
} from '$lib/types/enums'
type ElementName = 'wind' | 'fire' | 'water' | 'earth' | 'dark' | 'light'
interface Props { interface Props {
character: any character: any
@ -51,45 +40,17 @@
const genderOptions = getGenderOptions() const genderOptions = getGenderOptions()
const proficiencyOptions = getProficiencyOptions() const proficiencyOptions = getProficiencyOptions()
// Season options (nullable, so include a "None" option)
const seasonOptions = [
{ value: 0, label: 'None' },
...Object.entries(CHARACTER_SEASON_NAMES).map(([value, label]) => ({
value: Number(value),
label
}))
]
// Series options for multiselect // Series options for multiselect
const seriesOptions = Object.entries(CHARACTER_SERIES_NAMES).map(([value, label]) => ({ const seriesOptions = Object.entries(CHARACTER_SERIES_NAMES).map(([value, label]) => ({
value: Number(value), value: Number(value),
label label
})) }))
// Promotion options for multiselect
const promotionOptions = Object.entries(PROMOTION_NAMES).map(([value, label]) => ({
value: Number(value),
label
}))
// Get element name for checkbox theming
const elementName = $derived.by((): ElementName | undefined => {
const el = editMode ? editData?.element : character?.element
const label = getElementLabel(el)
return label !== '—' && label !== 'Null' ? (label.toLowerCase() as ElementName) : undefined
})
// Format series for display // Format series for display
function formatSeriesDisplay(series: number[]): string { function formatSeriesDisplay(series: number[]): string {
if (!series || series.length === 0) return '—' if (!series || series.length === 0) return '—'
return getSeriesNames(series).join(', ') return getSeriesNames(series).join(', ')
} }
// Format promotions for display
function formatPromotionsDisplay(promotions: number[]): string {
if (!promotions || promotions.length === 0) return '—'
return getPromotionNames(promotions).join(', ')
}
</script> </script>
<DetailsContainer title="Details"> <DetailsContainer title="Details">
@ -160,39 +121,15 @@
onAcceptSuggestion={() => onAcceptSuggestion?.('proficiency2', suggestions?.proficiency2)} onAcceptSuggestion={() => onAcceptSuggestion?.('proficiency2', suggestions?.proficiency2)}
onDismissSuggestion={() => onDismissSuggestion?.('proficiency2')} onDismissSuggestion={() => onDismissSuggestion?.('proficiency2')}
/> />
<DetailItem
label="Season"
bind:value={editData.season}
editable={true}
type="select"
options={seasonOptions}
/>
<DetailItem <DetailItem
label="Series" label="Series"
bind:value={editData.series}
editable={true}
type="multiselect"
options={seriesOptions}
element={elementName}
/>
<DetailItem
label="Gacha Available"
sublabel="Can be pulled from gacha"
bind:value={editData.gacha_available}
editable={true}
type="checkbox"
element={elementName}
/>
<DetailItem
label="Promotions"
sublabel="Gacha pools where this character appears"
editable={true} editable={true}
> >
<MultiSelect <MultiSelect
size="medium" size="medium"
options={promotionOptions} options={seriesOptions}
bind:value={editData.promotions} bind:value={editData.series}
placeholder="Select promotions" placeholder="Select series"
contained contained
/> />
</DetailItem> </DetailItem>
@ -209,13 +146,6 @@
<DetailItem label="Proficiency 2"> <DetailItem label="Proficiency 2">
<ProficiencyLabel proficiency={character.proficiency?.[1] ?? 0} size="medium" /> <ProficiencyLabel proficiency={character.proficiency?.[1] ?? 0} size="medium" />
</DetailItem> </DetailItem>
<DetailItem label="Season" value={getSeasonName(character.season) || '—'} />
<DetailItem label="Series" value={formatSeriesDisplay(character.series)} /> <DetailItem label="Series" value={formatSeriesDisplay(character.series)} />
<DetailItem label="Gacha Available" value={character.gachaAvailable ? 'Yes' : 'No'} />
<DetailItem
label="Promotions"
sublabel="Gacha pools where this character appears"
value={formatPromotionsDisplay(character.promotions)}
/>
{/if} {/if}
</DetailsContainer> </DetailsContainer>