feat(05-03): add highlighting to EntryCard and integrate search UI

- Add searchQuery prop to EntryCard for text highlighting
- Use {@html highlightText()} for title and content in collapsed view
- Integrate SearchBar and FilterBar in +page.svelte
- Add search/filter state with reactive sync to filters.query
- Pass recentSearches store to SearchBar
- Update filterEntries to use generics for type preservation
This commit is contained in:
Thomas Richter
2026-01-31 17:18:55 +01:00
parent 9642b51ef8
commit bb1e64ad2b
3 changed files with 52 additions and 11 deletions

View File

@@ -6,6 +6,7 @@
import ImageGallery from './ImageGallery.svelte';
import ImageUpload from './ImageUpload.svelte';
import TagInput from './TagInput.svelte';
import { highlightText } from '$lib/utils/highlightText';
interface EntryWithData extends Entry {
images: Image[];
@@ -15,9 +16,10 @@
interface Props {
entry: EntryWithData;
availableTags: Tag[];
searchQuery?: string;
}
let { entry, availableTags }: Props = $props();
let { entry, availableTags, searchQuery = '' }: Props = $props();
// Expand/collapse state
let expanded = $state(false);
@@ -300,7 +302,11 @@
? 'line-through text-gray-400'
: ''}"
>
{entry.title || 'Untitled'}
{#if !expanded && searchQuery}
{@html highlightText(entry.title || 'Untitled', searchQuery)}
{:else}
{entry.title || 'Untitled'}
{/if}
</h3>
{#if !expanded}
<p
@@ -308,7 +314,11 @@
? 'text-gray-400'
: ''}"
>
{entry.content}
{#if searchQuery}
{@html highlightText(entry.content, searchQuery)}
{:else}
{entry.content}
{/if}
</p>
{#if entry.tags?.length > 0}
<div class="flex flex-wrap gap-1 mt-1">

View File

@@ -7,15 +7,16 @@ interface EntryWithTags extends Entry {
/**
* Filters entries based on search criteria.
* Uses generics to preserve full entry type (including images, etc.)
*
* @param entries - Array of entries with their tags
* @param filters - SearchFilters object containing filter criteria
* @returns Filtered array of entries
*/
export function filterEntries(
entries: EntryWithTags[],
export function filterEntries<T extends EntryWithTags>(
entries: T[],
filters: SearchFilters
): EntryWithTags[] {
): T[] {
let result = entries;
// Text search (title + content) - minimum 2 characters