svelte lol

This commit is contained in:
2026-07-19 19:40:25 +02:00
parent 3344064030
commit 1324512ebf
56 changed files with 5506 additions and 2 deletions

View File

@@ -0,0 +1,79 @@
<script lang="ts">
import type { PageData } from './$types';
import type { GridItem } from '$lib/types/item';
import ItemCard from '$lib/components/item/ItemCard.svelte';
import Pagination from '$lib/components/ui/Pagination.svelte';
import { onSSE } from '$lib/stores/sse';
import { pinEvent } from '$lib/stores/pin';
import { onDestroy } from 'svelte';
let { data }: { data: PageData } = $props();
// Local mutable copy of the items list — SSE patches it live
let items = $state<GridItem[]>(data.items);
let total = $state(data.total);
// Re-sync when server data changes (e.g. navigation / invalidation)
$effect(() => {
items = data.items;
total = data.total;
});
// ── Live grid updates via SSE ─────────────────────────────────────────────
const unsubSSE = onSSE((event) => {
if (event.type === 'new_item') {
const d = event.data as GridItem & { dest: string; username: string };
if (!items.some(i => i.id === d.id)) {
items = [d, ...items];
total += 1;
}
} else if (event.type === 'delete_item') {
const d = event.data as { id: number };
const before = items.length;
items = items.filter(i => i.id !== d.id);
if (items.length < before) total = Math.max(0, total - 1);
}
});
onDestroy(unsubSSE);
// ── Pin store: patch the grid card is_pinned live ─────────────────────────
const unsubPin = pinEvent.subscribe((evt) => {
if (!evt) return;
items = items.map(i => i.id === evt.itemId ? { ...i, is_pinned: evt.pinned } : i);
});
onDestroy(unsubPin);
</script>
<svelte:head>
<title>f0ckm — {total} items</title>
</svelte:head>
<div class="max-w-[1600px] mx-auto px-3 py-4">
<!-- Grid header -->
{#if total > 0}
<p class="text-xs opacity-40 mb-3 font-mono">{total.toLocaleString()} items</p>
{/if}
<!-- Thumbnail grid -->
{#if items.length > 0}
<div class="
grid gap-1.5
grid-cols-[repeat(auto-fill,minmax(140px,1fr))]
sm:grid-cols-[repeat(auto-fill,minmax(180px,1fr))]
md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))]
">
{#each items as item (item.id)}
<ItemCard {item} link={data.link} />
{/each}
</div>
{#if data.pagination}
<Pagination pagination={data.pagination} link={data.link} />
{/if}
{:else}
<div class="flex flex-col items-center justify-center py-32 gap-4 opacity-40">
<i class="fa-solid fa-box-open text-5xl"></i>
<p class="text-sm">No items found.</p>
</div>
{/if}
</div>