Files
iknowyou/front/src/components/CheatsheetList.svelte
2026-04-06 15:12:34 +02:00

84 lines
2.4 KiB
Svelte

<script lang="ts">
interface Sheet {
id: string;
title: string;
description?: string;
tags?: string[];
}
let { sheets }: { sheets: Sheet[] } = $props();
let search = $state("");
let activeTag: string | null = $state(
typeof window !== "undefined"
? new URLSearchParams(window.location.search).get("tag")
: null
);
const allTags = [...new Set(sheets.flatMap((s) => s.tags ?? []))].sort();
const filtered = $derived(
sheets.filter((s) => {
const q = search.toLowerCase();
const matchSearch =
!q ||
s.title.toLowerCase().includes(q) ||
(s.description?.toLowerCase().includes(q) ?? false);
const matchTag = !activeTag || (s.tags?.includes(activeTag) ?? false);
return matchSearch && matchTag;
})
);
</script>
<div class="flex flex-col gap-4">
<input
type="search"
placeholder="Search cheatsheets..."
bind:value={search}
class="input input-bordered w-full"
/>
{#if allTags.length > 0}
<div class="flex flex-wrap gap-2">
{#each allTags as tag}
<button
class="badge badge-md cursor-pointer transition-colors {activeTag === tag
? 'badge-primary'
: 'badge-ghost hover:badge-outline'}"
onclick={() => (activeTag = activeTag === tag ? null : tag)}
>
{tag}
</button>
{/each}
</div>
{/if}
<div class="flex flex-col gap-3">
{#if filtered.length === 0}
<p class="text-base-content/40 text-sm py-6 text-center">No results.</p>
{:else}
{#each filtered as sheet}
<a
href={`/cheatsheets/${sheet.id}`}
class="card bg-base-200 hover:bg-base-300 transition-colors p-4 flex flex-row items-center gap-4"
>
<div class="size-2 rounded-full bg-primary shrink-0"></div>
<div class="flex-1 min-w-0">
<div class="font-semibold text-sm">{sheet.title}</div>
{#if sheet.description}
<div class="text-base-content/50 text-xs mt-0.5">{sheet.description}</div>
{/if}
</div>
{#if sheet.tags && sheet.tags.length > 0}
<div class="flex gap-1 shrink-0">
{#each sheet.tags as tag}
<span class="badge badge-xs badge-ghost">{tag}</span>
{/each}
</div>
{/if}
</a>
{/each}
{/if}
</div>
</div>