From 2a8721fde0699eb62801c7f86cc0d0dcb3ebb409 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Tue, 19 May 2026 10:13:26 +0200 Subject: [PATCH] feat(hikes): clickable tag chips + tag filter on the overview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detail-page tag chips become anchor links to `/hikes?tag=`. HikesFilterBar grows a tags fieldset (sorted by frequency, with the hash prefix the chips use) so the user can keep narrowing from there. Multi-tag filtering is OR — a hike matching any selected tag stays visible. AND would shrink the listing fast given how few tags most hikes carry; OR matches what "show me more like this" feels like. The overview page reads `tag` query params on mount and pre-fills the filter — supports repeated params (`?tag=winter&tag=easy`). --- package.json | 2 +- .../components/hikes/HikesFilterBar.svelte | 63 +++++++++++++++++++ src/routes/hikes/+page.svelte | 26 +++++++- src/routes/hikes/[slug]/+page.svelte | 23 ++++++- 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 15052c3c..bacd2e6e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.75.2", + "version": "1.75.3", "private": true, "type": "module", "scripts": { diff --git a/src/lib/components/hikes/HikesFilterBar.svelte b/src/lib/components/hikes/HikesFilterBar.svelte index 0aebba3c..daefcb36 100644 --- a/src/lib/components/hikes/HikesFilterBar.svelte +++ b/src/lib/components/hikes/HikesFilterBar.svelte @@ -9,6 +9,7 @@ maxLossM: number; difficulties: SvelteSet; regions: SvelteSet; + tags: SvelteSet; }; interface Props { @@ -37,6 +38,22 @@ return out.sort((a, b) => a.localeCompare(b)); }); + // Tags sorted by usage frequency (most-used first), alphabetical for + // ties. Frequency ordering surfaces broadly-applicable filters like + // "winter" or "easy" at the head of the list, where they're most + // useful for narrowing the listing. + const tags = $derived.by(() => { + const counts = new Map(); + for (const h of hikes) { + for (const t of h.tags ?? []) { + counts.set(t, (counts.get(t) ?? 0) + 1); + } + } + return [...counts.entries()] + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + .map(([t]) => t); + }); + function toggleDifficulty(d: Difficulty) { if (filter.difficulties.has(d)) filter.difficulties.delete(d); else filter.difficulties.add(d); @@ -47,6 +64,11 @@ else filter.regions.add(r); } + function toggleTag(t: string) { + if (filter.tags.has(t)) filter.tags.delete(t); + else filter.tags.add(t); + } + function resetFilters() { filter.maxDistanceKm = maxDistance; filter.maxDurationMin = maxDuration; @@ -54,6 +76,7 @@ filter.maxLossM = maxLoss; filter.difficulties.clear(); filter.regions.clear(); + filter.tags.clear(); } @@ -149,6 +172,24 @@ + + {#if tags.length > 0} +
+ Schlagwörter +
+ {#each tags as t (t)} + + {/each} +
+
+ {/if} diff --git a/src/routes/hikes/+page.svelte b/src/routes/hikes/+page.svelte index cb28defd..5f12bc41 100644 --- a/src/routes/hikes/+page.svelte +++ b/src/routes/hikes/+page.svelte @@ -1,5 +1,6 @@