From bf74a3cc92b74fca7629e48568548fb91d4ab2b6 Mon Sep 17 00:00:00 2001 From: iamdoubz <> Date: Thu, 2 Jul 2026 10:38:54 -0500 Subject: [PATCH] feat(ui): tag/date filters and tag chips in the meetings list (T8.3, FR-SEARCH-2) --- src/lib/views/MeetingsList.svelte | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/lib/views/MeetingsList.svelte b/src/lib/views/MeetingsList.svelte index d93cdf9..d7961ff 100644 --- a/src/lib/views/MeetingsList.svelte +++ b/src/lib/views/MeetingsList.svelte @@ -12,6 +12,28 @@ searchTimer = setTimeout(() => meetings.search(query), 250); } + // Tag/date filters (T8.3, FR-SEARCH-2) apply to the plain list, not + // full-text search — changing one drops out of search mode so the + // filtered list is immediately visible rather than hidden behind results. + let tagFilter = $state(""); + let fromFilter = $state(""); + let toFilter = $state(""); + + function toUnix(dateStr: string): number | undefined { + if (!dateStr) return undefined; + return Math.floor(new Date(dateStr).getTime() / 1000); + } + + function onFilterChange() { + query = ""; + meetings.search(null); + meetings.load({ + tag: tagFilter || undefined, + from: toUnix(fromFilter), + to: toUnix(toFilter), + }); + } + // Unified view: full-text results (with snippets) while searching, else the // plain list. Same underlying fields either way. let displayItems = $derived<(MeetingListItem | SearchHit)[]>( @@ -61,6 +83,16 @@ bind:value={query} oninput={onSearchInput} /> +
+ + + +
{#if meetings.searching}

Searching…

{:else if displayItems.length === 0 && meetings.loading} @@ -91,6 +123,13 @@ {#if snippetOf(m)} {snippetOf(m)} {/if} + {#if m.tags.length > 0} + + {#each m.tags as t (t)} + {t} + {/each} + + {/if}
{#if m.status === "recovering"} @@ -138,6 +177,34 @@ text-overflow: ellipsis; white-space: nowrap; } + .filters { + display: flex; + gap: 0.3rem; + margin-bottom: 0.5rem; + } + .filters select, + .filters input { + flex: 1; + min-width: 0; + padding: 0.25rem; + font-size: 0.78rem; + background: var(--bg); + color: var(--fg); + border: 1px solid var(--border); + border-radius: 5px; + } + .tags { + justify-content: flex-start; + flex-wrap: wrap; + margin-top: 0.2rem; + } + .chip { + font-size: 0.68rem; + padding: 0.05rem 0.35rem; + border-radius: 8px; + background: color-mix(in srgb, var(--muted) 15%, transparent); + color: var(--muted); + } ul { list-style: none; padding: 0;