feat(05-03): integrate filtering into EntryList with flat list mode

- Add filters and searchQuery props to EntryList
- Apply filterEntries via $derived for reactive filtering
- Display flat list (no pinned separation) when filtering
- Show search-specific empty state when no matches
- Pass searchQuery to EntryCard for highlighting
This commit is contained in:
Thomas Richter
2026-01-31 17:17:31 +01:00
parent af61b10a59
commit 9642b51ef8

View File

@@ -1,5 +1,8 @@
<script lang="ts">
import type { Entry, Image, Tag } from '$lib/server/db/schema';
import type { SearchFilters } from '$lib/types/search';
import { filterEntries } from '$lib/utils/filterEntries';
import { hasActiveFilters } from '$lib/types/search';
import EntryCard from './EntryCard.svelte';
interface EntryWithData extends Entry {
@@ -10,27 +13,50 @@
interface Props {
entries: EntryWithData[];
availableTags: Tag[];
filters: SearchFilters;
searchQuery: string;
}
let { entries, availableTags }: Props = $props();
let { entries, availableTags, filters, searchQuery }: Props = $props();
// Separate entries into pinned and unpinned
let pinnedEntries = $derived(entries.filter(e => e.pinned));
let unpinnedEntries = $derived(entries.filter(e => !e.pinned));
// Apply filtering
let filteredEntries = $derived(filterEntries(entries, filters));
let isFiltering = $derived(hasActiveFilters(filters));
// Separate entries into pinned and unpinned (only used when not filtering)
let pinnedEntries = $derived(filteredEntries.filter((e) => e.pinned));
let unpinnedEntries = $derived(filteredEntries.filter((e) => !e.pinned));
</script>
{#if entries.length === 0}
<div class="text-center py-12 text-gray-500">
<p class="text-lg">No entries yet</p>
<p class="text-sm mt-1">Use the capture bar below to add your first entry</p>
{#if filteredEntries.length === 0}
{#if isFiltering}
<div class="text-center py-12 text-gray-500">
<p class="text-lg">No entries match your search</p>
<p class="text-sm mt-1">Try adjusting your filters or search term</p>
</div>
{:else}
<div class="text-center py-12 text-gray-500">
<p class="text-lg">No entries yet</p>
<p class="text-sm mt-1">Use the capture bar below to add your first entry</p>
</div>
{/if}
{:else if isFiltering}
<!-- Flat list when filtering (no pinned/unpinned separation) -->
<div class="divide-y divide-gray-100 md:divide-y-0 md:space-y-3">
{#each filteredEntries as entry (entry.id)}
<EntryCard {entry} {availableTags} {searchQuery} />
{/each}
</div>
{:else}
<!-- Normal view with pinned/unpinned separation -->
{#if pinnedEntries.length > 0}
<div class="mb-4">
<h2 class="text-sm font-medium text-gray-500 uppercase tracking-wide mb-2 px-4 md:px-0">Pinned</h2>
<h2 class="text-sm font-medium text-gray-500 uppercase tracking-wide mb-2 px-4 md:px-0">
Pinned
</h2>
<div class="divide-y divide-gray-100 md:divide-y-0 md:space-y-3">
{#each pinnedEntries as entry (entry.id)}
<EntryCard {entry} {availableTags} />
<EntryCard {entry} {availableTags} {searchQuery} />
{/each}
</div>
</div>
@@ -39,7 +65,7 @@
{#if unpinnedEntries.length > 0}
<div class="divide-y divide-gray-100 md:divide-y-0 md:space-y-3">
{#each unpinnedEntries as entry (entry.id)}
<EntryCard {entry} {availableTags} />
<EntryCard {entry} {availableTags} {searchQuery} />
{/each}
</div>
{/if}