add CharacterTag component, show tags in db list
This commit is contained in:
parent
d1376396b4
commit
cbef8f5518
3 changed files with 251 additions and 6 deletions
67
src/lib/components/database/cells/CharacterNameCell.svelte
Normal file
67
src/lib/components/database/cells/CharacterNameCell.svelte
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import type { Cell } from 'wx-svelte-grid'
|
||||
import type { Character } from '$lib/types/api/entities'
|
||||
import CharacterTag from '$lib/components/tags/CharacterTag.svelte'
|
||||
|
||||
const { row }: Cell = $props()
|
||||
|
||||
// Cast row to Character type for type safety
|
||||
const character = row as Character
|
||||
|
||||
// Get display name
|
||||
const displayName = $derived.by(() => {
|
||||
const nameObj = character.name
|
||||
if (!nameObj) return '—'
|
||||
if (typeof nameObj === 'string') return nameObj
|
||||
return nameObj.en || nameObj.ja || '—'
|
||||
})
|
||||
|
||||
// Check if character has season (seasonal variant)
|
||||
const hasSeason = $derived(
|
||||
character.season !== undefined && character.season !== null && character.season > 0
|
||||
)
|
||||
|
||||
// Check if character has series (need to check for non-empty array)
|
||||
const hasSeries = $derived.by(() => {
|
||||
if (!character.series || !Array.isArray(character.series)) return false
|
||||
return character.series.length > 0
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="name-cell">
|
||||
<span class="name">{displayName}</span>
|
||||
{#if hasSeason || hasSeries}
|
||||
<div class="tags">
|
||||
{#if hasSeason}
|
||||
<CharacterTag {character} type="season" />
|
||||
{/if}
|
||||
{#if hasSeries}
|
||||
<CharacterTag {character} type="series" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$src/themes/spacing' as *;
|
||||
@use '$src/themes/typography' as *;
|
||||
|
||||
.name-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $unit-half;
|
||||
padding: $unit-half 0;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: $medium;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $unit-half;
|
||||
}
|
||||
</style>
|
||||
182
src/lib/components/tags/CharacterTag.svelte
Normal file
182
src/lib/components/tags/CharacterTag.svelte
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import type { Character } from '$lib/types/api/entities'
|
||||
import type { CharacterSeriesRef } from '$lib/types/api/characterSeries'
|
||||
import { getElementLabel } from '$lib/utils/element'
|
||||
import { CHARACTER_SEASON_NAMES, CHARACTER_SERIES_NAMES } from '$lib/types/enums'
|
||||
|
||||
type TagType = 'element' | 'season' | 'series'
|
||||
|
||||
interface Props {
|
||||
/** The character to display the tag for */
|
||||
character: Character
|
||||
/** Which characteristic to display */
|
||||
type: TagType
|
||||
/** Optional specific series index to display (for multi-series characters) */
|
||||
seriesIndex?: number
|
||||
}
|
||||
|
||||
let { character, type, seriesIndex = 0 }: Props = $props()
|
||||
|
||||
// Get element class name for styling
|
||||
const elementClass = $derived.by(() => {
|
||||
const element = character.element
|
||||
switch (element) {
|
||||
case 1:
|
||||
return 'wind'
|
||||
case 2:
|
||||
return 'fire'
|
||||
case 3:
|
||||
return 'water'
|
||||
case 4:
|
||||
return 'earth'
|
||||
case 5:
|
||||
return 'dark'
|
||||
case 6:
|
||||
return 'light'
|
||||
default:
|
||||
return 'neutral'
|
||||
}
|
||||
})
|
||||
|
||||
// Get the display text based on tag type
|
||||
const displayText = $derived.by(() => {
|
||||
switch (type) {
|
||||
case 'element':
|
||||
return getElementLabel(character.element)
|
||||
|
||||
case 'season':
|
||||
if (character.season === undefined || character.season === null) return null
|
||||
return CHARACTER_SEASON_NAMES[character.season] ?? null
|
||||
|
||||
case 'series':
|
||||
// Handle array of CharacterSeriesRef objects
|
||||
if (character.series && Array.isArray(character.series)) {
|
||||
const seriesArray = character.series as (number | CharacterSeriesRef)[]
|
||||
const seriesValue = seriesArray[seriesIndex]
|
||||
|
||||
if (seriesValue === undefined) return null
|
||||
|
||||
// Check if it's an object (CharacterSeriesRef) or number
|
||||
if (typeof seriesValue === 'object' && seriesValue !== null && 'name' in seriesValue) {
|
||||
return seriesValue.name.en
|
||||
}
|
||||
// Legacy number format
|
||||
if (typeof seriesValue === 'number') {
|
||||
return CHARACTER_SERIES_NAMES[seriesValue] ?? null
|
||||
}
|
||||
}
|
||||
// Fallback to seriesNames if available
|
||||
if (character.seriesNames && character.seriesNames[seriesIndex]) {
|
||||
return character.seriesNames[seriesIndex]
|
||||
}
|
||||
return null
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
// Only render if we have text to display
|
||||
const shouldRender = $derived(displayText !== null && displayText !== '—')
|
||||
</script>
|
||||
|
||||
{#if shouldRender}
|
||||
<span class="character-tag {elementClass}">
|
||||
{displayText}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
@use '$src/themes/colors' as *;
|
||||
@use '$src/themes/spacing' as *;
|
||||
@use '$src/themes/typography' as *;
|
||||
@use '$src/themes/layout' as *;
|
||||
|
||||
.character-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $unit-fourth $unit;
|
||||
border-radius: $item-corner-small;
|
||||
font-size: $font-tiny;
|
||||
font-weight: $medium;
|
||||
white-space: nowrap;
|
||||
line-height: 1;
|
||||
|
||||
// Element-specific styling
|
||||
&.wind {
|
||||
background-color: $wind-bg-20;
|
||||
color: $wind-text-20;
|
||||
}
|
||||
|
||||
&.fire {
|
||||
background-color: $fire-bg-20;
|
||||
color: $fire-text-20;
|
||||
}
|
||||
|
||||
&.water {
|
||||
background-color: $water-bg-20;
|
||||
color: $water-text-20;
|
||||
}
|
||||
|
||||
&.earth {
|
||||
background-color: $earth-bg-20;
|
||||
color: $earth-text-20;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background-color: $dark-bg-20;
|
||||
color: $dark-text-20;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: $light-bg-20;
|
||||
color: $light-text-20;
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
background-color: $grey-80;
|
||||
color: $grey-40;
|
||||
}
|
||||
}
|
||||
|
||||
// Dark mode adjustments
|
||||
:global(.dark) .character-tag {
|
||||
&.wind {
|
||||
background-color: $wind-text-10;
|
||||
color: $wind-bg-20;
|
||||
}
|
||||
|
||||
&.fire {
|
||||
background-color: $fire-text-10;
|
||||
color: $fire-bg-20;
|
||||
}
|
||||
|
||||
&.water {
|
||||
background-color: $water-text-10;
|
||||
color: $water-bg-20;
|
||||
}
|
||||
|
||||
&.earth {
|
||||
background-color: $earth-text-10;
|
||||
color: $earth-bg-20;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background-color: $dark-text-10;
|
||||
color: $dark-bg-20;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: $light-text-10;
|
||||
color: $light-bg-20;
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
background-color: $grey-30;
|
||||
color: $grey-80;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
// Svelte components
|
||||
import CharacterImageCell from '$lib/components/database/cells/CharacterImageCell.svelte'
|
||||
import CharacterNameCell from '$lib/components/database/cells/CharacterNameCell.svelte'
|
||||
import CharacterUncapCell from '$lib/components/database/cells/CharacterUncapCell.svelte'
|
||||
import DatabaseGridWithProvider from '$lib/components/database/DatabaseGridWithProvider.svelte'
|
||||
import ElementCell from '$lib/components/database/cells/ElementCell.svelte'
|
||||
|
|
@ -28,12 +29,7 @@
|
|||
header: 'Name',
|
||||
flexgrow: 1,
|
||||
sort: true,
|
||||
template: (nameObj: { en: any; ja: any }) => {
|
||||
if (!nameObj) return '—'
|
||||
if (typeof nameObj === 'string') return nameObj
|
||||
// Handle {en: "...", ja: "..."} structure
|
||||
return nameObj.en || nameObj.ja || '—'
|
||||
}
|
||||
cell: CharacterNameCell
|
||||
},
|
||||
{
|
||||
id: 'rarity',
|
||||
|
|
|
|||
Loading…
Reference in a new issue