|
<script lang="ts"> |
|
import type { PicletInstance, Monster } from '$lib/db/schema'; |
|
import PicletCard from '../Piclets/PicletCard.svelte'; |
|
import DraggablePicletCard from '../Piclets/DraggablePicletCard.svelte'; |
|
import DiscoveredCard from '../Piclets/DiscoveredCard.svelte'; |
|
import PicletDetail from '../Piclets/PicletDetail.svelte'; |
|
|
|
interface Props { |
|
title: string; |
|
type: 'storage' | 'discovered'; |
|
items: PicletInstance[] | Monster[]; |
|
onBack: () => void; |
|
onItemsChanged?: () => void; |
|
onDragStart?: (instance: PicletInstance) => void; |
|
onDragEnd?: () => void; |
|
} |
|
|
|
let { title, type, items, onBack, onItemsChanged, onDragStart, onDragEnd }: Props = $props(); |
|
let selectedPiclet: PicletInstance | null = $state(null); |
|
|
|
function handleItemClick(item: PicletInstance | Monster) { |
|
if ('currentHp' in item) { |
|
selectedPiclet = item as PicletInstance; |
|
} else { |
|
console.log('View discovered monster:', item); |
|
} |
|
} |
|
</script> |
|
|
|
<div class="view-all-page"> |
|
<header class="page-header"> |
|
<button class="back-btn" onclick={onBack} aria-label="Back"> |
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M19 12H5m0 0l7 7m-7-7l7-7"></path> |
|
</svg> |
|
</button> |
|
<h1>{title}</h1> |
|
<div class="header-spacer"></div> |
|
</header> |
|
|
|
<div class="content"> |
|
{#if items.length === 0} |
|
<div class="empty-state"> |
|
<p>No {type === 'storage' ? 'piclets in storage' : 'discovered piclets'} yet.</p> |
|
</div> |
|
{:else} |
|
<div class="items-grid"> |
|
{#each items as item} |
|
{#if type === 'storage' && 'currentHp' in item} |
|
<DraggablePicletCard |
|
instance={item as PicletInstance} |
|
size={100} |
|
onClick={() => handleItemClick(item)} |
|
onDragStart={onDragStart} |
|
onDragEnd={onDragEnd} |
|
/> |
|
{:else if type === 'discovered' && 'stats' in item} |
|
<DiscoveredCard |
|
monster={item as Monster} |
|
size={100} |
|
onClick={() => handleItemClick(item)} |
|
/> |
|
{/if} |
|
{/each} |
|
</div> |
|
{/if} |
|
</div> |
|
|
|
{#if selectedPiclet} |
|
<PicletDetail |
|
instance={selectedPiclet} |
|
onClose={() => selectedPiclet = null} |
|
onDeleted={() => { |
|
selectedPiclet = null; |
|
onItemsChanged?.(); |
|
}} |
|
/> |
|
{/if} |
|
</div> |
|
|
|
<style> |
|
.view-all-page { |
|
height: 100%; |
|
display: flex; |
|
flex-direction: column; |
|
background: white; |
|
} |
|
|
|
.page-header { |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
padding: 0.5rem 1rem; |
|
background: white; |
|
position: sticky; |
|
top: 0; |
|
z-index: 10; |
|
border-bottom: 1px solid #e5e5ea; |
|
} |
|
|
|
.page-header h1 { |
|
margin: 0; |
|
font-size: 1.5rem; |
|
font-weight: bold; |
|
color: #333; |
|
} |
|
|
|
.back-btn { |
|
background: none; |
|
border: none; |
|
padding: 0.5rem; |
|
cursor: pointer; |
|
color: #007bff; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.header-spacer { |
|
width: 40px; |
|
} |
|
|
|
.content { |
|
flex: 1; |
|
overflow-y: auto; |
|
padding: 1rem; |
|
padding-bottom: 100px; |
|
} |
|
|
|
.empty-state { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
height: 200px; |
|
color: #666; |
|
text-align: center; |
|
} |
|
|
|
.items-grid { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); |
|
gap: 1rem; |
|
justify-items: center; |
|
} |
|
</style> |