| <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> |