move artifact image/name to header, use DetailRows for skills
This commit is contained in:
parent
ee2e51affd
commit
dc4c2c3117
2 changed files with 47 additions and 85 deletions
|
|
@ -8,12 +8,13 @@
|
||||||
* provides Edit button in header to push edit pane onto stack.
|
* provides Edit button in header to push edit pane onto stack.
|
||||||
*/
|
*/
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import type { CollectionArtifact } from '$lib/types/api/artifact'
|
import type { CollectionArtifact, ArtifactSkillInstance } from '$lib/types/api/artifact'
|
||||||
import { isQuirkArtifact } from '$lib/types/api/artifact'
|
import { isQuirkArtifact } from '$lib/types/api/artifact'
|
||||||
|
import { createQuery } from '@tanstack/svelte-query'
|
||||||
|
import { artifactQueries } from '$lib/api/queries/artifact.queries'
|
||||||
import { useDeleteCollectionArtifact } from '$lib/api/mutations/artifact.mutations'
|
import { useDeleteCollectionArtifact } from '$lib/api/mutations/artifact.mutations'
|
||||||
import { usePaneStack, type PaneConfig, type ElementType } from '$lib/stores/paneStack.svelte'
|
import { usePaneStack, type PaneConfig, type ElementType } from '$lib/stores/paneStack.svelte'
|
||||||
import { sidebar } from '$lib/stores/sidebar.svelte'
|
import { sidebar } from '$lib/stores/sidebar.svelte'
|
||||||
import { getArtifactImage } from '$lib/utils/images'
|
|
||||||
import DetailsSection from '$lib/components/sidebar/details/DetailsSection.svelte'
|
import DetailsSection from '$lib/components/sidebar/details/DetailsSection.svelte'
|
||||||
import DetailRow from '$lib/components/sidebar/details/DetailRow.svelte'
|
import DetailRow from '$lib/components/sidebar/details/DetailRow.svelte'
|
||||||
import ElementLabel from '$lib/components/labels/ElementLabel.svelte'
|
import ElementLabel from '$lib/components/labels/ElementLabel.svelte'
|
||||||
|
|
@ -28,19 +29,19 @@
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
let { artifact, isOwner = false, onClose }: Props = $props()
|
let { artifact: initialArtifact, isOwner = false, onClose }: Props = $props()
|
||||||
|
|
||||||
|
// Local state that can be updated when returning from edit pane
|
||||||
|
let artifact = $state(initialArtifact)
|
||||||
|
|
||||||
|
// Update artifact when edit pane returns with new data
|
||||||
|
function handleArtifactUpdated(updatedArtifact: CollectionArtifact) {
|
||||||
|
artifact = updatedArtifact
|
||||||
|
}
|
||||||
|
|
||||||
const paneStack = usePaneStack()
|
const paneStack = usePaneStack()
|
||||||
const deleteMutation = useDeleteCollectionArtifact()
|
const deleteMutation = useDeleteCollectionArtifact()
|
||||||
|
|
||||||
// Image and name
|
|
||||||
const imageUrl = $derived(getArtifactImage(artifact.artifact?.granblueId))
|
|
||||||
const displayName = $derived.by(() => {
|
|
||||||
const name = artifact.artifact?.name
|
|
||||||
if (!name) return '—'
|
|
||||||
if (typeof name === 'string') return name
|
|
||||||
return name.en || name.ja || '—'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Artifact properties
|
// Artifact properties
|
||||||
const isQuirk = $derived(isQuirkArtifact(artifact.artifact))
|
const isQuirk = $derived(isQuirkArtifact(artifact.artifact))
|
||||||
|
|
@ -52,6 +53,15 @@
|
||||||
const skills = $derived(artifact.skills ?? [])
|
const skills = $derived(artifact.skills ?? [])
|
||||||
const hasSkills = $derived(!isQuirk && skills.some((s) => s !== null))
|
const hasSkills = $derived(!isQuirk && skills.some((s) => s !== null))
|
||||||
|
|
||||||
|
// Query skill definitions to get names
|
||||||
|
const skillsQuery = createQuery(() => artifactQueries.skills())
|
||||||
|
|
||||||
|
// Get skill name by modifier
|
||||||
|
function getSkillName(skill: ArtifactSkillInstance): string {
|
||||||
|
const skillDef = skillsQuery.data?.find((s) => s.modifier === skill.modifier)
|
||||||
|
return skillDef?.name?.en ?? 'Unknown Skill'
|
||||||
|
}
|
||||||
|
|
||||||
// Convert numeric element to ElementType string
|
// Convert numeric element to ElementType string
|
||||||
const elementNames: Record<number, ElementType> = {
|
const elementNames: Record<number, ElementType> = {
|
||||||
1: 'wind',
|
1: 'wind',
|
||||||
|
|
@ -70,7 +80,8 @@
|
||||||
title: 'Edit Artifact',
|
title: 'Edit Artifact',
|
||||||
component: CollectionArtifactEditPane,
|
component: CollectionArtifactEditPane,
|
||||||
props: {
|
props: {
|
||||||
artifact
|
artifact,
|
||||||
|
onSaved: handleArtifactUpdated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paneStack.push(config)
|
paneStack.push(config)
|
||||||
|
|
@ -108,20 +119,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="artifact-detail-pane">
|
<div class="artifact-detail-pane">
|
||||||
<!-- Header with image -->
|
|
||||||
<div class="pane-header">
|
|
||||||
<div class="artifact-image">
|
|
||||||
<img src={imageUrl} alt={displayName} />
|
|
||||||
</div>
|
|
||||||
<h2 class="artifact-name">{displayName}</h2>
|
|
||||||
{#if artifact.nickname}
|
|
||||||
<p class="artifact-nickname">"{artifact.nickname}"</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Details content -->
|
|
||||||
<div class="pane-content">
|
<div class="pane-content">
|
||||||
<DetailsSection title="Properties">
|
<DetailsSection title="Properties">
|
||||||
|
{#if artifact.nickname}
|
||||||
|
<DetailRow label="Nickname" value={artifact.nickname} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
<DetailRow label="Element">
|
<DetailRow label="Element">
|
||||||
<ElementLabel element={artifact.element} size="medium" />
|
<ElementLabel element={artifact.element} size="medium" />
|
||||||
</DetailRow>
|
</DetailRow>
|
||||||
|
|
@ -139,13 +142,13 @@
|
||||||
|
|
||||||
{#if hasSkills}
|
{#if hasSkills}
|
||||||
<DetailsSection title="Skills">
|
<DetailsSection title="Skills">
|
||||||
<div class="skills-list">
|
{#each skills as skill}
|
||||||
{#each skills as skill, index}
|
{#if skill}
|
||||||
{#if skill}
|
<DetailRow label={getSkillName(skill)}>
|
||||||
<ArtifactSkillDisplay slot={index + 1} {skill} />
|
<ArtifactSkillDisplay {skill} element={elementType} />
|
||||||
{/if}
|
</DetailRow>
|
||||||
{/each}
|
{/if}
|
||||||
</div>
|
{/each}
|
||||||
</DetailsSection>
|
</DetailsSection>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
@ -155,13 +158,10 @@
|
||||||
</div>
|
</div>
|
||||||
</DetailsSection>
|
</DetailsSection>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use '$src/themes/spacing' as *;
|
@use '$src/themes/spacing' as *;
|
||||||
@use '$src/themes/typography' as *;
|
|
||||||
@use '$src/themes/layout' as *;
|
|
||||||
|
|
||||||
.artifact-detail-pane {
|
.artifact-detail-pane {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -169,45 +169,6 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pane-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
padding: $unit-2x;
|
|
||||||
border-bottom: 1px solid var(--border-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.artifact-image {
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
border-radius: $item-corner;
|
|
||||||
overflow: hidden;
|
|
||||||
background: var(--card-bg, #f5f5f5);
|
|
||||||
margin-bottom: $unit;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.artifact-name {
|
|
||||||
margin: 0;
|
|
||||||
font-size: $font-large;
|
|
||||||
font-weight: $bold;
|
|
||||||
color: var(--text-primary);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.artifact-nickname {
|
|
||||||
margin: $unit-half 0 0;
|
|
||||||
font-size: $font-small;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-style: italic;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pane-content {
|
.pane-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
@ -217,13 +178,6 @@
|
||||||
padding-bottom: $unit-2x;
|
padding-bottom: $unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skills-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $unit;
|
|
||||||
padding: 0 $unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grade-section {
|
.grade-section {
|
||||||
padding: $unit;
|
padding: $unit;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
import { viewMode, type ViewMode } from '$lib/stores/viewMode.svelte'
|
import { viewMode, type ViewMode } from '$lib/stores/viewMode.svelte'
|
||||||
import SegmentedControl from '$lib/components/ui/segmented-control/SegmentedControl.svelte'
|
import SegmentedControl from '$lib/components/ui/segmented-control/SegmentedControl.svelte'
|
||||||
import Segment from '$lib/components/ui/segmented-control/Segment.svelte'
|
import Segment from '$lib/components/ui/segmented-control/Segment.svelte'
|
||||||
|
import { getArtifactImage } from '$lib/utils/images'
|
||||||
|
|
||||||
const { data }: { data: PageData } = $props()
|
const { data }: { data: PageData } = $props()
|
||||||
|
|
||||||
|
|
@ -76,11 +77,18 @@
|
||||||
? artifact.artifact.name
|
? artifact.artifact.name
|
||||||
: artifact.artifact?.name?.en || 'Artifact'
|
: artifact.artifact?.name?.en || 'Artifact'
|
||||||
|
|
||||||
sidebar.openWithComponent(artifactName, CollectionArtifactDetailPane, {
|
sidebar.openWithComponent(
|
||||||
artifact,
|
artifactName,
|
||||||
isOwner: data.isOwner,
|
CollectionArtifactDetailPane,
|
||||||
onClose: () => sidebar.close()
|
{
|
||||||
})
|
artifact,
|
||||||
|
isOwner: data.isOwner,
|
||||||
|
onClose: () => sidebar.close()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: getArtifactImage(artifact.artifact?.granblueId)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue