weapon sections: add name fields to metadata, move recruits to gacha

This commit is contained in:
Justin Edmund 2025-12-15 13:08:17 -08:00
parent 0812e3b2d4
commit 70c0881bb4
2 changed files with 90 additions and 95 deletions

View file

@ -7,6 +7,7 @@
import MultiSelect from '$lib/components/ui/MultiSelect.svelte' import MultiSelect from '$lib/components/ui/MultiSelect.svelte'
import CharacterTypeahead from '$lib/components/ui/CharacterTypeahead.svelte' import CharacterTypeahead from '$lib/components/ui/CharacterTypeahead.svelte'
import { PROMOTION_NAMES, getPromotionNames } from '$lib/types/enums' import { PROMOTION_NAMES, getPromotionNames } from '$lib/types/enums'
import { getCharacterImage } from '$lib/utils/images'
interface Props { interface Props {
weapon: any weapon: any
@ -40,56 +41,81 @@
if (!promotions || promotions.length === 0) return '—' if (!promotions || promotions.length === 0) return '—'
return getPromotionNames(promotions).join(', ') return getPromotionNames(promotions).join(', ')
} }
// Format recruits for display
function formatRecruitsDisplay(recruits: any): string {
if (!recruits) return '—'
if (typeof recruits === 'string') return recruits
return recruits.name?.en || recruits.granblueId || '—'
}
// Check if we should show the section in view mode
const hasGachaData = $derived.by(() => {
if (editMode) return true
const hasPromotions = weapon?.promotions && weapon.promotions.length > 0
const hasRecruits = weapon?.recruits
return hasPromotions || hasRecruits
})
</script> </script>
{#if hasGachaData} <DetailsContainer title="Gacha">
<DetailsContainer title="Gacha"> {#if editMode}
{#if editMode} <DetailItem label="Promotions" sublabel="Gacha pools where this weapon appears" editable={true}>
<DetailItem label="Promotions" sublabel="Gacha pools where this weapon appears" editable={true}> <MultiSelect
<MultiSelect size="medium"
size="medium" options={promotionOptions}
options={promotionOptions} bind:value={editData.promotions}
bind:value={editData.promotions} placeholder="Select promotions"
placeholder="Select promotions" contained
contained
/>
</DetailItem>
<DetailItem label="Recruits" sublabel="Character recruited by this weapon" editable={true}>
<CharacterTypeahead
bind:value={editData.recruits}
initialCharacter={weapon.recruits ? { id: weapon.recruits.id, name: weapon.recruits.name?.en || weapon.recruits.granblueId, granblueId: weapon.recruits.granblueId } : null}
placeholder="Search for character..."
contained
/>
</DetailItem>
{:else}
<DetailItem
label="Promotions"
sublabel="Gacha pools where this weapon appears"
value={formatPromotionsDisplay(weapon.promotions)}
/> />
</DetailItem>
<DetailItem label="Recruits" sublabel="Character recruited by this weapon" editable={true}>
<CharacterTypeahead
bind:value={editData.recruits}
initialCharacter={weapon.recruits ? { id: weapon.recruits.id, name: weapon.recruits.name?.en || weapon.recruits.granblueId, granblueId: weapon.recruits.granblueId } : null}
placeholder="Search for character..."
contained
/>
</DetailItem>
{:else}
<DetailItem
label="Promotions"
sublabel="Gacha pools where this weapon appears"
value={formatPromotionsDisplay(weapon.promotions)}
/>
<DetailItem label="Recruits" sublabel="Character recruited by this weapon">
{#if weapon.recruits} {#if weapon.recruits}
<DetailItem <a href="/database/characters/{weapon.recruits.granblueId}" class="recruits-link">
label="Recruits" <img
sublabel="Character recruited by this weapon" src={getCharacterImage(weapon.recruits.granblueId, 'square', '01')}
value={formatRecruitsDisplay(weapon.recruits)} alt={weapon.recruits.name?.en || 'Recruited character'}
/> class="recruits-image"
/>
<span class="recruits-name">{weapon.recruits.name?.en}</span>
</a>
{:else}
<span class="empty-value"></span>
{/if} {/if}
{/if} </DetailItem>
</DetailsContainer> {/if}
{/if} </DetailsContainer>
<style lang="scss">
@use '$src/themes/colors' as colors;
@use '$src/themes/spacing' as spacing;
@use '$src/themes/typography' as typography;
@use '$src/themes/layout' as layout;
.recruits-link {
display: flex;
align-items: center;
gap: spacing.$unit;
text-decoration: none;
color: colors.$grey-30;
&:hover .recruits-image {
transform: scale(1.05);
}
&:hover .recruits-name {
color: colors.$blue;
}
}
.recruits-image {
width: 32px;
height: 32px;
border-radius: layout.$item-corner-small;
transition: transform 0.2s ease;
}
.recruits-name {
font-size: typography.$font-regular;
transition: color 0.2s ease;
}
</style>

View file

@ -7,7 +7,6 @@
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 { getRarityLabel, getRarityOptions } from '$lib/utils/rarity' import { getRarityLabel, getRarityOptions } from '$lib/utils/rarity'
import { getCharacterImage } from '$lib/utils/images'
interface Props { interface Props {
weapon: any weapon: any
@ -35,6 +34,20 @@
<DetailsContainer title="Metadata"> <DetailsContainer title="Metadata">
{#if editMode} {#if editMode}
<DetailItem
label="Name (EN)"
bind:value={editData.name}
editable={true}
type="text"
placeholder="English name"
/>
<DetailItem
label="Name (JP)"
bind:value={editData.nameJp}
editable={true}
type="text"
placeholder="日本語名"
/>
<SuggestionDetailItem <SuggestionDetailItem
label="Rarity" label="Rarity"
bind:value={editData.rarity} bind:value={editData.rarity}
@ -53,6 +66,8 @@
type="text" type="text"
/> />
{:else} {:else}
<DetailItem label="Name (EN)" value={weapon.name?.en || '—'} />
<DetailItem label="Name (JP)" value={weapon.name?.ja || '—'} />
<DetailItem label="Rarity" value={getRarityLabel(weapon.rarity)} /> <DetailItem label="Rarity" value={getRarityLabel(weapon.rarity)} />
<DetailItem label="Granblue ID"> <DetailItem label="Granblue ID">
{#if weapon.granblueId} {#if weapon.granblueId}
@ -61,53 +76,7 @@
{/if} {/if}
</DetailItem> </DetailItem>
{#if weapon.recruits}
<DetailItem label="Recruits">
<a href="/database/characters/{weapon.recruits.granblueId}" class="recruits-link">
<img
src={getCharacterImage(weapon.recruits.granblueId, 'square', '01')}
alt={weapon.recruits.name.en || 'Recruited character'}
class="recruits-image"
/>
<span class="recruits-name">{weapon.recruits.name.en}</span>
</a>
</DetailItem>
{/if}
{/if} {/if}
</DetailsContainer> </DetailsContainer>
<style lang="scss">
@use '$src/themes/colors' as colors;
@use '$src/themes/spacing' as spacing;
@use '$src/themes/typography' as typography;
@use '$src/themes/layout' as layout;
.recruits-link {
display: flex;
align-items: center;
gap: spacing.$unit;
text-decoration: none;
color: colors.$grey-30;
&:hover .recruits-image {
transform: scale(1.05);
}
&:hover .recruits-name {
color: colors.$blue;
}
}
.recruits-image {
width: 32px;
height: 32px;
border-radius: layout.$item-corner-small;
transition: transform 0.2s ease;
}
.recruits-name {
font-size: typography.$font-regular;
transition: color 0.2s ease;
}
</style>