feat(ui): add dedicated Filters tab with scrollable categories and pack state cards
Build and Push Fridger Container / Build & Push Fridger Image (push) Successful in 1m23s

This commit is contained in:
2026-10-11 00:00:59 +02:00
parent 81b80d3bc5
commit 3d89aab10e
2 changed files with 360 additions and 54 deletions
+171 -21
View File
@@ -56,17 +56,28 @@
<button
id="nav-stock-btn"
onclick="navigateTo('/')"
class="flex items-center justify-center gap-2 px-3.5 sm:px-6 py-2.5 sm:py-3 rounded-xl text-xs sm:text-sm font-bold transition-all bg-teal-500 text-white shadow-md active:scale-95 touch-manipulation min-h-[44px]"
class="flex items-center justify-center gap-2 px-3 sm:px-5 py-2.5 sm:py-3 rounded-xl text-xs sm:text-sm font-bold transition-all bg-teal-500 text-white shadow-md active:scale-95 touch-manipulation min-h-[44px]"
>
<i data-lucide="layout-grid" class="w-4 h-4 sm:w-5 sm:h-5"></i>
<span>Current Stock</span>
<span>Stock</span>
</button>
<!-- 2. Manager (/manage) -->
<!-- 2. Filters (/filters) -->
<button
id="nav-filters-btn"
onclick="navigateTo('/filters')"
class="relative flex items-center justify-center gap-1.5 sm:gap-2 px-3 sm:px-5 py-2.5 sm:py-3 rounded-xl text-xs sm:text-sm font-bold transition-all text-slate-300 hover:text-white hover:bg-slate-800/80 active:scale-95 touch-manipulation min-h-[44px]"
>
<i data-lucide="filter" class="w-4 h-4 sm:w-5 sm:h-5 text-teal-400"></i>
<span>Filters</span>
<span id="nav-filter-badge" class="hidden px-1.5 py-0.5 text-[10px] font-black rounded-full bg-teal-500 text-white leading-none">0</span>
</button>
<!-- 3. Manager (/manage) -->
<button
id="nav-manage-btn"
onclick="navigateTo('/manage')"
class="flex items-center justify-center gap-2 px-3.5 sm:px-6 py-2.5 sm:py-3 rounded-xl text-xs sm:text-sm font-bold transition-all text-slate-300 hover:text-white hover:bg-slate-800/80 active:scale-95 touch-manipulation min-h-[44px]"
class="flex items-center justify-center gap-2 px-3 sm:px-5 py-2.5 sm:py-3 rounded-xl text-xs sm:text-sm font-bold transition-all text-slate-300 hover:text-white hover:bg-slate-800/80 active:scale-95 touch-manipulation min-h-[44px]"
>
<i data-lucide="sliders-horizontal" class="w-4 h-4 sm:w-5 sm:h-5 text-teal-400"></i>
<span>Manager</span>
@@ -106,10 +117,10 @@
</div>
</section>
<!-- Stock Search & Filters -->
<!-- Stock Search & Active Filters Bar -->
<main class="flex-1 max-w-4xl mx-auto px-3 sm:px-6 py-4 w-full space-y-3">
<div class="space-y-2.5">
<div class="flex flex-col sm:flex-row gap-2.5 items-stretch sm:items-center justify-between">
<div class="space-y-2">
<div class="flex gap-2 items-center">
<div class="relative flex-1">
<i data-lucide="search" class="w-4 h-4 text-slate-400 absolute left-3.5 top-1/2 -translate-y-1/2"></i>
<input
@@ -123,22 +134,26 @@
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
<div class="flex items-center gap-1.5 overflow-x-auto pb-0.5 text-xs sm:text-sm font-medium scrollbar-none">
<button onclick="setStatusFilter('all')" data-status-btn="all" class="status-chip active px-3.5 py-2 rounded-xl bg-slate-800 border border-slate-700 text-white font-bold min-h-[38px] touch-manipulation">All</button>
<button onclick="setStatusFilter('full')" data-status-btn="full" class="status-chip px-3.5 py-2 rounded-xl bg-slate-900 border border-slate-800 text-slate-400 hover:text-slate-200 min-h-[38px] touch-manipulation">Full Packs</button>
<button onclick="setStatusFilter('opened')" data-status-btn="opened" class="status-chip px-3.5 py-2 rounded-xl bg-slate-900 border border-slate-800 text-indigo-400 hover:text-indigo-300 min-h-[38px] touch-manipulation">Opened</button>
<button onclick="setStatusFilter('low')" data-status-btn="low" class="status-chip px-3.5 py-2 rounded-xl bg-slate-900 border border-slate-800 text-amber-400 hover:text-amber-300 min-h-[38px] touch-manipulation">&le;25% Low</button>
</div>
<button onclick="navigateTo('/filters')" class="px-3.5 py-2.5 rounded-xl bg-slate-900 hover:bg-slate-800 text-slate-300 border border-slate-800 text-xs sm:text-sm font-bold flex items-center gap-1.5 shrink-0 min-h-[42px] touch-manipulation">
<i data-lucide="sliders" class="w-4 h-4 text-teal-400"></i>
<span>Filter</span>
</button>
</div>
<div id="category-filter-bar" class="flex items-center gap-1.5 overflow-x-auto pb-1 scrollbar-none text-xs sm:text-sm font-medium">
<!-- Injected by JS -->
<!-- Active Filter Indicator Banner -->
<div id="active-filter-indicator" class="hidden flex items-center justify-between gap-2 p-2 px-3 bg-teal-950/40 border border-teal-500/30 rounded-xl text-xs">
<div class="flex items-center gap-2 min-w-0">
<i data-lucide="filter" class="w-3.5 h-3.5 text-teal-400 shrink-0"></i>
<span id="active-filter-text" class="text-teal-200 truncate font-medium">Filtering by Category: Dairy & Cheese</span>
</div>
<button onclick="resetAllFilters()" class="text-teal-300 hover:text-white underline text-xs shrink-0 font-bold">
Reset
</button>
</div>
</div>
<!-- Current Stock Grid (Display only) -->
<div id="stock-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3.5 sm:gap-4 pt-2">
<div id="stock-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3.5 sm:gap-4 pt-1">
<!-- Rendered items -->
</div>
@@ -148,12 +163,147 @@
🧊
</div>
<h3 class="text-lg font-bold text-white mb-1">No items in stock</h3>
<p class="text-xs sm:text-sm text-slate-400 max-w-xs mx-auto mb-6">Use Manager to scan or add items.</p>
<button onclick="navigateTo('/manage')" class="px-6 py-3 rounded-xl bg-teal-500 hover:bg-teal-400 text-white text-sm font-bold flex items-center gap-2 shadow-lg shadow-teal-500/20 active:scale-95 touch-manipulation mx-auto">
<i data-lucide="sliders-horizontal" class="w-5 h-5"></i>
<span>Go to Manager (/manage)</span>
<p class="text-xs sm:text-sm text-slate-400 max-w-xs mx-auto mb-6">No matching items found with the current filters.</p>
<div class="flex items-center justify-center gap-3">
<button onclick="resetAllFilters()" class="px-4 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs sm:text-sm font-bold active:scale-95 touch-manipulation">
Reset Filters
</button>
<button onclick="navigateTo('/manage')" class="px-5 py-2.5 rounded-xl bg-teal-500 hover:bg-teal-400 text-white text-xs sm:text-sm font-bold flex items-center gap-2 shadow-lg shadow-teal-500/20 active:scale-95 touch-manipulation">
<i data-lucide="sliders-horizontal" class="w-4 h-4"></i>
<span>Go to Manager</span>
</button>
</div>
</div>
</main>
</div>
<!-- ======================================================== -->
<!-- 2. FILTERS VIEW: /filters -->
<!-- ======================================================== -->
<div id="filters-view-page" class="hidden flex-1 flex flex-col">
<main class="flex-1 max-w-3xl mx-auto px-3 sm:px-6 py-4 sm:py-6 w-full space-y-6">
<!-- Top Title Bar -->
<div class="flex items-center justify-between">
<div>
<h2 class="text-lg sm:text-xl font-extrabold text-white">Filter Stock</h2>
<p class="text-xs sm:text-sm text-slate-400">Scroll and select pack states and categories</p>
</div>
<button
onclick="resetAllFilters()"
class="px-3.5 py-2 rounded-xl bg-slate-900 hover:bg-slate-800 text-slate-400 hover:text-white border border-slate-800 text-xs sm:text-sm font-bold transition active:scale-95 touch-manipulation"
>
Reset All
</button>
</div>
<!-- Section 1: Pack States (Scrollable cards) -->
<div class="space-y-2.5">
<div class="flex items-center justify-between">
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider">Pack States & Condition</label>
<span class="text-[11px] text-slate-500">Scroll horizontally &rarr;</span>
</div>
<div class="flex items-stretch gap-3 overflow-x-auto pb-2 scrollbar-none pt-1">
<!-- All Pack States -->
<button
onclick="setStatusFilter('all')"
data-filter-status="all"
class="filter-status-card flex-1 min-w-[140px] sm:min-w-[160px] p-4 rounded-2xl border text-left flex flex-col justify-between space-y-3 transition-all active:scale-95 touch-manipulation bg-teal-500/20 border-teal-500 text-white shadow-lg shadow-teal-500/10"
>
<div class="flex items-center justify-between">
<span class="w-8 h-8 rounded-xl bg-teal-500/20 text-teal-300 flex items-center justify-center">
<i data-lucide="layers" class="w-4 h-4"></i>
</span>
<span id="filter-count-all" class="text-xs font-bold px-2 py-0.5 rounded-md bg-slate-800 text-slate-300">0</span>
</div>
<div>
<h4 class="text-sm sm:text-base font-extrabold text-white">All Stock</h4>
<p class="text-[11px] text-slate-400 mt-0.5">Everything in fridge</p>
</div>
</button>
<!-- Full Packs -->
<button
onclick="setStatusFilter('full')"
data-filter-status="full"
class="filter-status-card flex-1 min-w-[140px] sm:min-w-[160px] p-4 rounded-2xl border text-left flex flex-col justify-between space-y-3 transition-all active:scale-95 touch-manipulation bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700"
>
<div class="flex items-center justify-between">
<span class="w-8 h-8 rounded-xl bg-emerald-500/20 text-emerald-400 flex items-center justify-center">
<i data-lucide="package-check" class="w-4 h-4"></i>
</span>
<span id="filter-count-full" class="text-xs font-bold px-2 py-0.5 rounded-md bg-slate-800 text-emerald-300">0</span>
</div>
<div>
<h4 class="text-sm sm:text-base font-extrabold text-white">Full Packs</h4>
<p class="text-[11px] text-slate-400 mt-0.5">100% unopened items</p>
</div>
</button>
<!-- Opened / In Use -->
<button
onclick="setStatusFilter('opened')"
data-filter-status="opened"
class="filter-status-card flex-1 min-w-[140px] sm:min-w-[160px] p-4 rounded-2xl border text-left flex flex-col justify-between space-y-3 transition-all active:scale-95 touch-manipulation bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700"
>
<div class="flex items-center justify-between">
<span class="w-8 h-8 rounded-xl bg-indigo-500/20 text-indigo-400 flex items-center justify-center">
<i data-lucide="package-open" class="w-4 h-4"></i>
</span>
<span id="filter-count-opened" class="text-xs font-bold px-2 py-0.5 rounded-md bg-slate-800 text-indigo-300">0</span>
</div>
<div>
<h4 class="text-sm sm:text-base font-extrabold text-white">Opened</h4>
<p class="text-[11px] text-slate-400 mt-0.5">In-use & partial packs</p>
</div>
</button>
<!-- Low Stock -->
<button
onclick="setStatusFilter('low')"
data-filter-status="low"
class="filter-status-card flex-1 min-w-[140px] sm:min-w-[160px] p-4 rounded-2xl border text-left flex flex-col justify-between space-y-3 transition-all active:scale-95 touch-manipulation bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700"
>
<div class="flex items-center justify-between">
<span class="w-8 h-8 rounded-xl bg-amber-500/20 text-amber-400 flex items-center justify-center">
<i data-lucide="alert-circle" class="w-4 h-4"></i>
</span>
<span id="filter-count-low" class="text-xs font-bold px-2 py-0.5 rounded-md bg-slate-800 text-amber-300">0</span>
</div>
<div>
<h4 class="text-sm sm:text-base font-extrabold text-white">Low Stock</h4>
<p class="text-[11px] text-slate-400 mt-0.5">&le;25% remaining</p>
</div>
</button>
</div>
</div>
<!-- Section 2: Categories (Scrollable touch grid) -->
<div class="space-y-2.5">
<div class="flex items-center justify-between">
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider">Categories</label>
<span class="text-[11px] text-slate-500">Tap to filter</span>
</div>
<div id="filter-categories-container" class="grid grid-cols-2 sm:grid-cols-3 gap-2.5 max-h-[380px] overflow-y-auto p-1 scrollbar-none">
<!-- Populated dynamically with Category Cards -->
</div>
</div>
<!-- Floating Bottom Action Bar -->
<div class="pt-2 sticky bottom-4 z-20">
<button
onclick="navigateTo('/')"
class="w-full py-4 rounded-2xl bg-teal-500 hover:bg-teal-400 text-white font-extrabold text-base sm:text-lg shadow-2xl shadow-teal-500/30 active:scale-95 transition-all touch-manipulation flex items-center justify-center gap-2"
>
<i data-lucide="check" class="w-5 h-5"></i>
<span>View Filtered Stock (<span id="filter-total-count">0</span> items)</span>
</button>
</div>
</main>
</div>