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