From 92fab94ae02d2155b75a7449900cfe0fc46f38d8 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 11 May 2026 11:57:10 -0700 Subject: [PATCH] feat(find): active-filter bar with clear-all (closes #129) Adds a summary bar that appears at the top of the Find Recipes panel whenever any filter is active. Shows a count ("3 filters active") and a Clear all button that resets all Find-tab filters in one tap: constraints, allergies, excluded ingredients, shopping mode, pantry-match-only, hard day mode, time budgets (active + total), max missing, style, category, and all four nutrition limits. Local input refs (constraintInput, allergyInput, etc.) are also cleared so the text fields don't show stale uncommitted values after a clear. --- frontend/src/components/RecipesView.vue | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/frontend/src/components/RecipesView.vue b/frontend/src/components/RecipesView.vue index 55c8cb4..7c6d0ad 100644 --- a/frontend/src/components/RecipesView.vue +++ b/frontend/src/components/RecipesView.vue @@ -95,6 +95,14 @@

Find Recipes

+ +
+ {{ activeFilterCount }} filter{{ activeFilterCount !== 1 ? 's' : '' }} active + +
+
@@ -968,6 +976,42 @@ const advancedActive = computed(() => !!recipesStore.styleId ) +const activeFilterCount = computed(() => { + let n = 0 + if (recipesStore.constraints.length > 0) n++ + if (recipesStore.allergies.length > 0) n++ + if (recipesStore.excludeIngredients.length > 0) n++ + if (recipesStore.shoppingMode) n++ + if (recipesStore.pantryMatchOnly) n++ + if (recipesStore.hardDayMode) n++ + if (recipesStore.maxActiveMin !== null) n++ + if (recipesStore.maxTotalMin !== null) n++ + if (recipesStore.maxMissing !== null) n++ + if (recipesStore.styleId !== null) n++ + if (recipesStore.category !== null) n++ + n += Object.values(recipesStore.nutritionFilters).filter((v) => v !== null).length + return n +}) + +function clearAllFindFilters() { + recipesStore.clearConstraints() + recipesStore.clearAllergies() + recipesStore.clearExcludeIngredients() + recipesStore.shoppingMode = false + recipesStore.pantryMatchOnly = false + recipesStore.hardDayMode = false + recipesStore.maxActiveMin = null + recipesStore.maxTotalMin = null + recipesStore.maxMissing = null + recipesStore.styleId = null + recipesStore.category = null + recipesStore.nutritionFilters = { max_calories: null, max_sugar_g: null, max_carbs_g: null, max_sodium_mg: null } + constraintInput.value = '' + allergyInput.value = '' + excludeIngredientInput.value = '' + categoryInput.value = '' +} + // #46 — count of active nutrition filters so the summary is informative when collapsed const activeNutritionFilterCount = computed(() => Object.values(recipesStore.nutritionFilters ?? {}).filter((v) => v !== null).length @@ -1387,6 +1431,18 @@ watch( } /* Filter bar */ +.active-filter-bar { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--spacing-xs) var(--spacing-sm); + margin-bottom: var(--spacing-sm); + background: var(--color-bg-secondary); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + color: var(--color-text-secondary); +} + .filter-bar { display: flex; flex-direction: column;