kammer/src/routes/+page.svelte
Christopher Mühl 1ffdb937ce feat: all route pages — dashboard, scan, items, locations, labels, settings
- Dashboard with stats grid, checked-out/low-stock/recent items
- Scan route with check-in/out flow
- Items list with search, filters (category/type/custody), sorting
- Item detail with full metadata, check-in/out, edit, delete
- New item form wired to inventory store
- Locations browser with tree view and items-at-location
- Labels page with batch generation and PDF download
- Settings page with DB stats
- Fixed Svelte 5 event modifier syntax (no pipe modifiers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:22:19 +01:00

87 lines
2.7 KiB
Svelte

<script lang="ts">
import { inventory } from '$lib/stores/inventory.svelte';
import ItemCard from '$lib/components/ItemCard.svelte';
import { goto } from '$app/navigation';
const totalItems = $derived(inventory.items.length);
const checkedOut = $derived(inventory.checkedOutItems.length);
const overdue = $derived(inventory.overdueItems.length);
const lowStock = $derived(inventory.lowStockItems.length);
const stats = $derived([
{ label: 'Total Items', value: totalItems, color: 'text-blue-400' },
{ label: 'Checked Out', value: checkedOut, color: 'text-amber-400' },
{ label: 'Overdue', value: overdue, color: overdue > 0 ? 'text-red-400' : 'text-slate-400' },
{ label: 'Low Stock', value: lowStock, color: lowStock > 0 ? 'text-red-400' : 'text-slate-400' },
]);
const recentItems = $derived(
[...inventory.items]
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
.slice(0, 5)
);
</script>
<div class="p-4 space-y-6">
<div>
<h1 class="text-2xl font-bold">SolidHaus</h1>
<p class="text-slate-400 text-sm">Household inventory at a glance</p>
</div>
<!-- Stats Grid -->
<div class="grid grid-cols-2 gap-3">
{#each stats as stat}
<div class="bg-slate-800 rounded-lg p-3">
<div class="text-2xl font-bold {stat.color}">{stat.value}</div>
<div class="text-xs text-slate-400">{stat.label}</div>
</div>
{/each}
</div>
<!-- Checked Out Items -->
{#if inventory.checkedOutItems.length > 0}
<section>
<h2 class="text-sm font-medium text-slate-400 uppercase mb-2">Checked Out</h2>
<div class="space-y-2">
{#each inventory.checkedOutItems.slice(0, 5) as item}
<ItemCard {item} onclick={() => goto(`/items/${item.shortId}`)} />
{/each}
</div>
</section>
{/if}
<!-- Low Stock -->
{#if inventory.lowStockItems.length > 0}
<section>
<h2 class="text-sm font-medium text-slate-400 uppercase mb-2">Low Stock</h2>
<div class="space-y-2">
{#each inventory.lowStockItems.slice(0, 5) as item}
<ItemCard {item} onclick={() => goto(`/items/${item.shortId}`)} />
{/each}
</div>
</section>
{/if}
<!-- Recent Items -->
{#if recentItems.length > 0}
<section>
<h2 class="text-sm font-medium text-slate-400 uppercase mb-2">Recently Updated</h2>
<div class="space-y-2">
{#each recentItems as item}
<ItemCard {item} onclick={() => goto(`/items/${item.shortId}`)} />
{/each}
</div>
</section>
{:else}
<div class="text-center py-8">
<p class="text-slate-500 mb-4">No items yet. Start by scanning or adding an item.</p>
<a
href="/items/new"
class="inline-block px-6 py-3 bg-blue-500 text-white rounded-lg font-medium
hover:bg-blue-600 transition-colors"
>
Add First Item
</a>
</div>
{/if}
</div>