extract CharacterTags component, use in unit and search

This commit is contained in:
Justin Edmund 2025-12-15 19:51:38 -08:00
parent d0fc56d00c
commit 321e7585b8
5 changed files with 89 additions and 53 deletions

View file

@ -3,9 +3,7 @@
<script lang="ts">
import type { Cell } from 'wx-svelte-grid'
import type { Character } from '$lib/types/api/entities'
import type { CharacterSeriesRef } from '$lib/types/api/characterSeries'
import CharacterTag from '$lib/components/tags/CharacterTag.svelte'
import { CHARACTER_SEASON_NAMES, CHARACTER_SERIES_NAMES } from '$lib/types/enums'
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
const { row }: Cell = $props()
@ -19,52 +17,11 @@
if (typeof nameObj === 'string') return nameObj
return nameObj.en || nameObj.ja || '—'
})
// Get season text for comparison
const seasonText = $derived.by(() => {
if (character.season === undefined || character.season === null || character.season <= 0) {
return null
}
return CHARACTER_SEASON_NAMES[character.season] ?? null
})
// Get first series text for comparison
const seriesText = $derived.by(() => {
if (!character.series || !Array.isArray(character.series) || character.series.length === 0) {
return null
}
const seriesValue = character.series[0] as number | CharacterSeriesRef
if (typeof seriesValue === 'object' && seriesValue !== null && 'name' in seriesValue) {
return seriesValue.name.en
}
if (typeof seriesValue === 'number') {
return CHARACTER_SERIES_NAMES[seriesValue] ?? null
}
return null
})
// Special case: Yukata is more specific than Summer, so hide Summer if Yukata is present
const isYukataWithSummer = $derived(seriesText === 'Yukata' && seasonText === 'Summer')
// Check if character has season (seasonal variant), but hide if Yukata+Summer
const hasSeason = $derived(seasonText !== null && !isYukataWithSummer)
// Check if character has series with different text than season
const hasDistinctSeries = $derived(seriesText !== null && seriesText !== seasonText)
</script>
<div class="name-cell">
<span class="name">{displayName}</span>
{#if hasSeason || hasDistinctSeries}
<div class="tags">
{#if hasSeason}
<CharacterTag {character} type="season" />
{/if}
{#if hasDistinctSeries}
<CharacterTag {character} type="series" />
{/if}
</div>
{/if}
<CharacterTags {character} />
</div>
<style lang="scss">
@ -81,10 +38,4 @@
.name {
font-weight: $medium;
}
.tags {
display: flex;
flex-wrap: wrap;
gap: $unit-half;
}
</style>

View file

@ -7,6 +7,7 @@
import { collectionQueries } from '$lib/api/queries/collection.queries'
import Button from '../ui/Button.svelte'
import Icon from '../Icon.svelte'
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
import { IsInViewport } from 'runed'
import { getCharacterImage, getWeaponImage, getSummonImage } from '$lib/features/database/detail/image'
import type { AddItemResult, SearchMode } from '$lib/types/api/search'
@ -447,6 +448,9 @@
loading="lazy"
/>
<span class="result-name">{getItemName(item)}</span>
{#if type === 'character'}
<CharacterTags character={item} />
{/if}
{#if item.collectionId}
<Icon name="bookmark" size={14} class="collection-indicator" />
{:else if owned}

View file

@ -0,0 +1,77 @@
<svelte:options runes={true} />
<script lang="ts">
import type { CharacterSeriesRef } from '$lib/types/api/characterSeries'
import CharacterTag from './CharacterTag.svelte'
import { CHARACTER_SEASON_NAMES, CHARACTER_SERIES_NAMES } from '$lib/types/enums'
/** Minimal character data needed for tag display */
interface CharacterForTags {
element?: number | null
season?: number | null
series?: (number | CharacterSeriesRef)[] | null
seriesNames?: string[] | null
}
interface Props {
character: CharacterForTags
}
let { character }: Props = $props()
// Get season text for comparison
const seasonText = $derived.by(() => {
if (character.season === undefined || character.season === null || character.season <= 0) {
return null
}
return CHARACTER_SEASON_NAMES[character.season] ?? null
})
// Get first series text for comparison
const seriesText = $derived.by(() => {
if (!character.series || !Array.isArray(character.series) || character.series.length === 0) {
return null
}
const seriesValue = character.series[0] as number | CharacterSeriesRef
if (typeof seriesValue === 'object' && seriesValue !== null && 'name' in seriesValue) {
return seriesValue.name.en
}
if (typeof seriesValue === 'number') {
return CHARACTER_SERIES_NAMES[seriesValue] ?? null
}
return null
})
// Special case: Yukata is more specific than Summer, so hide Summer if Yukata is present
const isYukataWithSummer = $derived(seriesText === 'Yukata' && seasonText === 'Summer')
// Check if character has season (seasonal variant), but hide if Yukata+Summer
const hasSeason = $derived(seasonText !== null && !isYukataWithSummer)
// Check if character has series with different text than season
const hasDistinctSeries = $derived(seriesText !== null && seriesText !== seasonText)
// Whether any tags should be shown
const hasTags = $derived(hasSeason || hasDistinctSeries)
</script>
{#if hasTags}
<div class="tags">
{#if hasSeason}
<CharacterTag {character} type="season" />
{/if}
{#if hasDistinctSeries}
<CharacterTag {character} type="series" />
{/if}
</div>
{/if}
<style lang="scss">
@use '$src/themes/spacing' as *;
.tags {
display: flex;
flex-wrap: wrap;
gap: $unit-half;
}
</style>

View file

@ -6,6 +6,7 @@
import UnitMenuContainer from '$lib/components/ui/menu/UnitMenuContainer.svelte'
import MenuItems from '$lib/components/ui/menu/MenuItems.svelte'
import UncapIndicator from '$lib/components/uncap/UncapIndicator.svelte'
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
import { getCharacterImageWithPose } from '$lib/utils/images'
import { openDetailsSidebar } from '$lib/features/details/openDetailsSidebar.svelte'
import { sidebar } from '$lib/stores/sidebar.svelte'
@ -326,6 +327,9 @@
<Icon name="gem" size={12} class="artifact-indicator" />
{/if}
</div>
{#if item?.character}
<CharacterTags character={item.character} />
{/if}
</div>
<style lang="scss">

View file

@ -37,7 +37,7 @@
buildKamigameUrl
} from '$lib/utils/external-links'
import Button from '$lib/components/ui/Button.svelte'
import CharacterTag from '$lib/components/tags/CharacterTag.svelte'
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
// Types
import type { PageData } from './$types'
@ -325,7 +325,7 @@
class="related-image"
/>
<span class="related-name">{related.name.en}</span>
<CharacterTag character={related} type="element" />
<CharacterTags character={related} />
</a>
{/each}
</div>