From 6f4507492ae3a5f2e2bfa21d7b87107378d6d052 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Fri, 2 Jan 2026 21:41:17 +0100 Subject: [PATCH] feat: add graceful degradation and conditional favorites filter Add progressive enhancement to hide filter panel when JavaScript is disabled, and conditionally render favorites filter based on login status. Search Component: - Added showFilters state (default false) - Set showFilters to true in onMount when JS is enabled - Wrapped FilterPanel in {#if showFilters} for graceful degradation - Filters hidden without JavaScript, visible with JS FilterPanel: - Split grid layout into two variants: - with-favorites: 5 columns (120px 120px 1fr 160px 90px) - without-favorites: 4 columns (120px 120px 1fr 160px) - Conditionally render FavoritesFilter only when isLoggedIn - Apply appropriate class based on login status FavoritesFilter: - Simplified template (no internal login check) - Only rendered when user is logged in via FilterPanel UX: - Non-JS browsers: Simple search only, filters gracefully hidden - Not logged in: 4-column layout without favorites filter - Logged in: 5-column layout with favorites filter --- src/lib/components/FavoritesFilter.svelte | 24 ++++---------- src/lib/components/FilterPanel.svelte | 25 +++++++++----- src/lib/components/Search.svelte | 40 +++++++++++++---------- 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/lib/components/FavoritesFilter.svelte b/src/lib/components/FavoritesFilter.svelte index 12e40ab3..91e3e873 100644 --- a/src/lib/components/FavoritesFilter.svelte +++ b/src/lib/components/FavoritesFilter.svelte @@ -10,8 +10,7 @@ } = $props(); const isEnglish = $derived(lang === 'en'); - const label = $derived(isEnglish ? 'Favorites Only' : 'Nur Favoriten'); - const loginRequiredLabel = $derived(isEnglish ? 'Login required' : 'Anmeldung erforderlich'); + const label = $derived(isEnglish ? 'Favorites' : 'Favoriten'); let checked = $state(enabled); @@ -57,24 +56,13 @@ text-align: left; } } - - .login-required { - font-size: 0.85rem; - color: var(--nord3); - font-style: italic; - padding: 0.5rem 0; - }
{label}
- {#if isLoggedIn} - - {:else} - - {/if} +
diff --git a/src/lib/components/FilterPanel.svelte b/src/lib/components/FilterPanel.svelte index 8e06fb1d..b4a49fe6 100644 --- a/src/lib/components/FilterPanel.svelte +++ b/src/lib/components/FilterPanel.svelte @@ -79,11 +79,18 @@ .filter-panel { display: grid; - grid-template-columns: 120px 120px 1fr 160px 140px; gap: 2rem; align-items: start; } + .filter-panel.with-favorites { + grid-template-columns: 120px 120px 1fr 160px 90px; + } + + .filter-panel.without-favorites { + grid-template-columns: 120px 120px 1fr 160px; + } + @media (max-width: 968px) { .toggle-button { display: flex; @@ -125,7 +132,7 @@ -
+
- + {#if isLoggedIn} + + {/if}
diff --git a/src/lib/components/Search.svelte b/src/lib/components/Search.svelte index 10ce3045..2cdbb2ea 100644 --- a/src/lib/components/Search.svelte +++ b/src/lib/components/Search.svelte @@ -27,6 +27,7 @@ }); let searchQuery = $state(''); + let showFilters = $state(false); // Filter data loaded from APIs let availableTags = $state([]); @@ -246,6 +247,9 @@ clearButton.style.display = 'flex'; } + // Enable filter panel for JS-enabled browsers + showFilters = true; + // Get initial search value from URL if present const urlParams = new URLSearchParams(window.location.search); const urlQuery = urlParams.get('q'); @@ -340,20 +344,22 @@ scale: 0.8 0.8; - +{#if showFilters} + +{/if}