feat(ui): convert filters to interactive modal overlay in stock view
Build and Push Fridger Container / Build & Push Fridger Image (push) Successful in 1m17s
Build and Push Fridger Container / Build & Push Fridger Image (push) Successful in 1m17s
This commit is contained in:
+59
-56
@@ -59,8 +59,6 @@ function handleInitialRoute() {
|
|||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path === '/manage' || path.startsWith('/manage')) {
|
if (path === '/manage' || path.startsWith('/manage')) {
|
||||||
setRoute('/manage');
|
setRoute('/manage');
|
||||||
} else if (path === '/filters' || path.startsWith('/filters')) {
|
|
||||||
setRoute('/filters');
|
|
||||||
} else {
|
} else {
|
||||||
setRoute('/');
|
setRoute('/');
|
||||||
}
|
}
|
||||||
@@ -72,48 +70,30 @@ function navigateTo(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setRoute(path) {
|
function setRoute(path) {
|
||||||
if (path === '/manage' || path.startsWith('/manage')) {
|
state.currentRoute = path === '/manage' ? '/manage' : '/';
|
||||||
state.currentRoute = '/manage';
|
|
||||||
} else if (path === '/filters' || path.startsWith('/filters')) {
|
|
||||||
state.currentRoute = '/filters';
|
|
||||||
} else {
|
|
||||||
state.currentRoute = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
const stockBtn = document.getElementById('nav-stock-btn');
|
const stockBtn = document.getElementById('nav-stock-btn');
|
||||||
const filtersBtn = document.getElementById('nav-filters-btn');
|
|
||||||
const manageBtn = document.getElementById('nav-manage-btn');
|
const manageBtn = document.getElementById('nav-manage-btn');
|
||||||
|
|
||||||
const stockPage = document.getElementById('stock-view-page');
|
const stockPage = document.getElementById('stock-view-page');
|
||||||
const filtersPage = document.getElementById('filters-view-page');
|
|
||||||
const managePage = document.getElementById('manage-view-page');
|
const managePage = document.getElementById('manage-view-page');
|
||||||
const subTitle = document.getElementById('page-subtitle');
|
const subTitle = document.getElementById('page-subtitle');
|
||||||
|
|
||||||
const activeClass = '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 bg-teal-500 text-white shadow-md active:scale-95 touch-manipulation min-h-[44px]';
|
const activeClass = 'flex items-center justify-center gap-2 px-4 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]';
|
||||||
const inactiveClass = '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]';
|
const inactiveClass = 'flex items-center justify-center gap-2 px-4 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]';
|
||||||
|
|
||||||
// Hide all pages first
|
|
||||||
stockPage.classList.add('hidden');
|
|
||||||
filtersPage.classList.add('hidden');
|
|
||||||
managePage.classList.add('hidden');
|
|
||||||
|
|
||||||
stockBtn.className = inactiveClass;
|
|
||||||
filtersBtn.className = inactiveClass;
|
|
||||||
manageBtn.className = inactiveClass;
|
|
||||||
|
|
||||||
if (state.currentRoute === '/') {
|
if (state.currentRoute === '/') {
|
||||||
stockBtn.className = activeClass;
|
stockBtn.className = activeClass;
|
||||||
|
manageBtn.className = inactiveClass;
|
||||||
stockPage.classList.remove('hidden');
|
stockPage.classList.remove('hidden');
|
||||||
|
managePage.classList.add('hidden');
|
||||||
subTitle.textContent = 'Current Stock';
|
subTitle.textContent = 'Current Stock';
|
||||||
renderStockView();
|
renderStockView();
|
||||||
} else if (state.currentRoute === '/filters') {
|
|
||||||
filtersBtn.className = activeClass;
|
|
||||||
filtersPage.classList.remove('hidden');
|
|
||||||
subTitle.textContent = 'Filter Stock';
|
|
||||||
renderFilterTabView();
|
|
||||||
} else {
|
} else {
|
||||||
manageBtn.className = activeClass;
|
manageBtn.className = activeClass;
|
||||||
|
stockBtn.className = inactiveClass;
|
||||||
managePage.classList.remove('hidden');
|
managePage.classList.remove('hidden');
|
||||||
|
stockPage.classList.add('hidden');
|
||||||
subTitle.textContent = 'Manager';
|
subTitle.textContent = 'Manager';
|
||||||
resetTabletManageStation();
|
resetTabletManageStation();
|
||||||
renderTabletProductPicker('');
|
renderTabletProductPicker('');
|
||||||
@@ -123,6 +103,29 @@ function setRoute(path) {
|
|||||||
initLucide();
|
initLucide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------
|
||||||
|
// Filter Overlay Modal Handlers
|
||||||
|
// ----------------------------------------------------
|
||||||
|
|
||||||
|
function openFilterOverlay() {
|
||||||
|
const modal = document.getElementById('filter-modal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
updateFilterUIState();
|
||||||
|
initLucide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeFilterOverlay() {
|
||||||
|
const modal = document.getElementById('filter-modal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
if (state.currentRoute === '/') {
|
||||||
|
renderStockView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// API Calls
|
// API Calls
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
@@ -173,8 +176,6 @@ async function loadItems() {
|
|||||||
state.items = await res.json();
|
state.items = await res.json();
|
||||||
if (state.currentRoute === '/') {
|
if (state.currentRoute === '/') {
|
||||||
renderStockView();
|
renderStockView();
|
||||||
} else if (state.currentRoute === '/filters') {
|
|
||||||
renderFilterTabView();
|
|
||||||
} else {
|
} else {
|
||||||
const query = document.getElementById('tablet-search-input')?.value || '';
|
const query = document.getElementById('tablet-search-input')?.value || '';
|
||||||
renderTabletProductPicker(query);
|
renderTabletProductPicker(query);
|
||||||
@@ -215,7 +216,7 @@ function clearSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// ROUTE 2: /filters (DEDICATED FILTERS TAB)
|
// FILTER OVERLAY STATE & SELECTION
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
function setStatusFilter(status) {
|
function setStatusFilter(status) {
|
||||||
@@ -253,17 +254,16 @@ function renderCategoryFilterCards() {
|
|||||||
<button
|
<button
|
||||||
onclick="setCategoryFilter('All')"
|
onclick="setCategoryFilter('All')"
|
||||||
data-filter-cat="All"
|
data-filter-cat="All"
|
||||||
class="filter-cat-card p-3 sm:p-4 rounded-2xl border text-left flex items-center gap-3 transition-all active:scale-95 touch-manipulation min-h-[64px] bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700"
|
class="filter-cat-card p-3 rounded-2xl border text-left flex items-center gap-2.5 transition-all active:scale-95 touch-manipulation min-h-[56px] bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700"
|
||||||
>
|
>
|
||||||
<div class="w-10 h-10 rounded-xl bg-teal-500/20 text-teal-300 flex items-center justify-center shrink-0">
|
<div class="w-8 h-8 rounded-xl bg-teal-500/20 text-teal-300 flex items-center justify-center shrink-0">
|
||||||
<i data-lucide="layout-grid" class="w-5 h-5"></i>
|
<i data-lucide="layout-grid" class="w-4 h-4"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex items-center justify-between gap-1">
|
<div class="flex items-center justify-between gap-1">
|
||||||
<h4 class="text-xs sm:text-sm font-extrabold text-white truncate">All Categories</h4>
|
<h4 class="text-xs font-bold text-white truncate">All Categories</h4>
|
||||||
<span id="cat-count-all" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-slate-400">0</span>
|
<span id="cat-count-all" class="text-[10px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-slate-400">0</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[10px] text-slate-400 truncate">View everything</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
@@ -273,17 +273,16 @@ function renderCategoryFilterCards() {
|
|||||||
<button
|
<button
|
||||||
onclick="setCategoryFilter('${escapeHtml(cat.id)}')"
|
onclick="setCategoryFilter('${escapeHtml(cat.id)}')"
|
||||||
data-filter-cat="${escapeHtml(cat.id)}"
|
data-filter-cat="${escapeHtml(cat.id)}"
|
||||||
class="filter-cat-card p-3 sm:p-4 rounded-2xl border text-left flex items-center gap-3 transition-all active:scale-95 touch-manipulation min-h-[64px] bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700"
|
class="filter-cat-card p-3 rounded-2xl border text-left flex items-center gap-2.5 transition-all active:scale-95 touch-manipulation min-h-[56px] bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700"
|
||||||
>
|
>
|
||||||
<div class="w-10 h-10 rounded-xl bg-slate-800 text-teal-400 flex items-center justify-center shrink-0">
|
<div class="w-8 h-8 rounded-xl bg-slate-800 text-teal-400 flex items-center justify-center shrink-0">
|
||||||
<i data-lucide="${escapeHtml(cat.icon || 'package')}" class="w-5 h-5"></i>
|
<i data-lucide="${escapeHtml(cat.icon || 'package')}" class="w-4 h-4"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex items-center justify-between gap-1">
|
<div class="flex items-center justify-between gap-1">
|
||||||
<h4 class="text-xs sm:text-sm font-extrabold text-white truncate">${escapeHtml(cat.name)}</h4>
|
<h4 class="text-xs font-bold text-white truncate">${escapeHtml(cat.name)}</h4>
|
||||||
<span id="cat-count-${escapeHtml(cat.id.replace(/[^a-zA-Z0-9]/g, ''))}" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-slate-400">0</span>
|
<span id="cat-count-${escapeHtml(cat.id.replace(/[^a-zA-Z0-9]/g, ''))}" class="text-[10px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-slate-400">0</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[10px] text-slate-400 truncate">${escapeHtml(cat.id)}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
@@ -293,10 +292,6 @@ function renderCategoryFilterCards() {
|
|||||||
initLucide();
|
initLucide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFilterTabView() {
|
|
||||||
updateFilterUIState();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFilterUIState() {
|
function updateFilterUIState() {
|
||||||
// 1. Update Pack State cards highlight & counts
|
// 1. Update Pack State cards highlight & counts
|
||||||
const allItems = state.allItems || [];
|
const allItems = state.allItems || [];
|
||||||
@@ -321,9 +316,9 @@ function updateFilterUIState() {
|
|||||||
const status = card.getAttribute('data-filter-status');
|
const status = card.getAttribute('data-filter-status');
|
||||||
const isSelected = state.filters.status === status;
|
const isSelected = state.filters.status === status;
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
card.className = 'filter-status-card flex-1 min-w-[140px] sm:min-w-[160px] p-4 rounded-2xl border-2 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/20 ring-2 ring-teal-500/30';
|
card.className = 'filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border-2 text-left flex flex-col justify-between space-y-2 transition-all active:scale-95 touch-manipulation bg-teal-500/20 border-teal-500 text-white shadow-lg shadow-teal-500/20 ring-2 ring-teal-500/30';
|
||||||
} else {
|
} else {
|
||||||
card.className = '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';
|
card.className = 'filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border text-left flex flex-col justify-between space-y-2 transition-all active:scale-95 touch-manipulation bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -346,24 +341,32 @@ function updateFilterUIState() {
|
|||||||
const cat = card.getAttribute('data-filter-cat');
|
const cat = card.getAttribute('data-filter-cat');
|
||||||
const isSelected = state.filters.category === cat;
|
const isSelected = state.filters.category === cat;
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
card.className = 'filter-cat-card p-3 sm:p-4 rounded-2xl border-2 text-left flex items-center gap-3 transition-all active:scale-95 touch-manipulation min-h-[64px] bg-teal-500/20 border-teal-500 text-white shadow-lg shadow-teal-500/20 ring-2 ring-teal-500/30';
|
card.className = 'filter-cat-card p-3 rounded-2xl border-2 text-left flex items-center gap-2.5 transition-all active:scale-95 touch-manipulation min-h-[56px] bg-teal-500/20 border-teal-500 text-white shadow-lg shadow-teal-500/20 ring-2 ring-teal-500/30';
|
||||||
} else {
|
} else {
|
||||||
card.className = 'filter-cat-card p-3 sm:p-4 rounded-2xl border text-left flex items-center gap-3 transition-all active:scale-95 touch-manipulation min-h-[64px] bg-slate-900 border-slate-800 text-slate-300 hover:border-slate-700';
|
card.className = 'filter-cat-card p-3 rounded-2xl border text-left flex items-center gap-2.5 transition-all active:scale-95 touch-manipulation min-h-[56px] bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Top Navigation Badge
|
// 3. Filter Trigger Button Badge on Stock Page
|
||||||
const navBadge = document.getElementById('nav-filter-badge');
|
|
||||||
let activeFilterCount = 0;
|
let activeFilterCount = 0;
|
||||||
if (state.filters.category !== 'All') activeFilterCount++;
|
if (state.filters.category !== 'All') activeFilterCount++;
|
||||||
if (state.filters.status !== 'all') activeFilterCount++;
|
if (state.filters.status !== 'all') activeFilterCount++;
|
||||||
|
|
||||||
if (navBadge) {
|
const triggerBtn = document.getElementById('filter-trigger-btn');
|
||||||
|
const stockFilterBadge = document.getElementById('stock-filter-badge');
|
||||||
|
|
||||||
|
if (stockFilterBadge) {
|
||||||
if (activeFilterCount > 0) {
|
if (activeFilterCount > 0) {
|
||||||
navBadge.textContent = activeFilterCount;
|
stockFilterBadge.textContent = activeFilterCount;
|
||||||
navBadge.classList.remove('hidden');
|
stockFilterBadge.classList.remove('hidden');
|
||||||
|
if (triggerBtn) {
|
||||||
|
triggerBtn.className = 'px-4 py-2.5 rounded-xl bg-teal-500/20 hover:bg-teal-500/30 text-teal-300 border border-teal-500/50 text-xs sm:text-sm font-bold flex items-center gap-2 shrink-0 min-h-[42px] touch-manipulation transition shadow-sm active:scale-95';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
navBadge.classList.add('hidden');
|
stockFilterBadge.classList.add('hidden');
|
||||||
|
if (triggerBtn) {
|
||||||
|
triggerBtn.className = 'px-4 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-2 shrink-0 min-h-[42px] touch-manipulation transition shadow-sm active:scale-95';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+83
-86
@@ -56,28 +56,17 @@
|
|||||||
<button
|
<button
|
||||||
id="nav-stock-btn"
|
id="nav-stock-btn"
|
||||||
onclick="navigateTo('/')"
|
onclick="navigateTo('/')"
|
||||||
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]"
|
class="flex items-center justify-center gap-2 px-4 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]"
|
||||||
>
|
>
|
||||||
<i data-lucide="layout-grid" class="w-4 h-4 sm:w-5 sm:h-5"></i>
|
<i data-lucide="layout-grid" class="w-4 h-4 sm:w-5 sm:h-5"></i>
|
||||||
<span>Stock</span>
|
<span>Current Stock</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- 2. Filters (/filters) -->
|
<!-- 2. Manager (/manage) -->
|
||||||
<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
|
<button
|
||||||
id="nav-manage-btn"
|
id="nav-manage-btn"
|
||||||
onclick="navigateTo('/manage')"
|
onclick="navigateTo('/manage')"
|
||||||
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]"
|
class="flex items-center justify-center gap-2 px-4 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]"
|
||||||
>
|
>
|
||||||
<i data-lucide="sliders-horizontal" class="w-4 h-4 sm:w-5 sm:h-5 text-teal-400"></i>
|
<i data-lucide="sliders-horizontal" class="w-4 h-4 sm:w-5 sm:h-5 text-teal-400"></i>
|
||||||
<span>Manager</span>
|
<span>Manager</span>
|
||||||
@@ -117,10 +106,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Stock Search & Active Filters Bar -->
|
<!-- Stock Search & Filter Trigger -->
|
||||||
<main class="flex-1 max-w-4xl mx-auto px-3 sm:px-6 py-4 w-full space-y-3">
|
<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">
|
<div class="space-y-2">
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2.5 items-center">
|
||||||
<div class="relative flex-1">
|
<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>
|
<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
|
<input
|
||||||
@@ -134,21 +123,34 @@
|
|||||||
<i data-lucide="x" class="w-4 h-4"></i>
|
<i data-lucide="x" class="w-4 h-4"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
<!-- Filter Trigger Button (Opens Filter Overlay) -->
|
||||||
|
<button
|
||||||
|
id="filter-trigger-btn"
|
||||||
|
onclick="openFilterOverlay()"
|
||||||
|
class="px-4 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-2 shrink-0 min-h-[42px] touch-manipulation transition shadow-sm active:scale-95"
|
||||||
|
>
|
||||||
|
<i data-lucide="filter" class="w-4 h-4 text-teal-400"></i>
|
||||||
<span>Filter</span>
|
<span>Filter</span>
|
||||||
|
<span id="stock-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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Active Filter Indicator Banner -->
|
<!-- 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 id="active-filter-indicator" class="hidden flex items-center justify-between gap-2 p-2 px-3 bg-teal-950/50 border border-teal-500/40 rounded-xl text-xs animate-scale-up">
|
||||||
<div class="flex items-center gap-2 min-w-0">
|
<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>
|
<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>
|
<span id="active-filter-text" class="text-teal-200 truncate font-medium">Filtered</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 shrink-0">
|
||||||
|
<button onclick="openFilterOverlay()" class="text-teal-300 hover:text-white text-xs font-bold underline">
|
||||||
|
Change
|
||||||
|
</button>
|
||||||
|
<span class="text-slate-600">•</span>
|
||||||
|
<button onclick="resetAllFilters()" class="text-slate-400 hover:text-rose-300 text-xs font-medium">
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button onclick="resetAllFilters()" class="text-teal-300 hover:text-white underline text-xs shrink-0 font-bold">
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -162,8 +164,8 @@
|
|||||||
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-slate-900 text-slate-500 flex items-center justify-center mx-auto mb-3 border border-slate-800 text-3xl">
|
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-slate-900 text-slate-500 flex items-center justify-center mx-auto mb-3 border border-slate-800 text-3xl">
|
||||||
🧊
|
🧊
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-lg font-bold text-white mb-1">No items in stock</h3>
|
<h3 class="text-lg font-bold text-white mb-1">No items match your filter</h3>
|
||||||
<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>
|
<p class="text-xs sm:text-sm text-slate-400 max-w-xs mx-auto mb-6">Try resetting filters or adding items via Manager.</p>
|
||||||
<div class="flex items-center justify-center gap-3">
|
<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">
|
<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
|
Reset Filters
|
||||||
@@ -179,49 +181,49 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ======================================================== -->
|
<!-- ======================================================== -->
|
||||||
<!-- 2. FILTERS VIEW: /filters -->
|
<!-- FILTER OVERLAY MODAL -->
|
||||||
<!-- ======================================================== -->
|
<!-- ======================================================== -->
|
||||||
<div id="filters-view-page" class="hidden flex-1 flex flex-col">
|
<div id="filter-modal" class="fixed inset-0 z-50 bg-black/80 backdrop-blur-md hidden flex items-center justify-center p-3 sm:p-4 overflow-y-auto">
|
||||||
|
<div class="bg-slate-900 border border-slate-800 rounded-3xl max-w-lg w-full p-5 sm:p-6 shadow-2xl space-y-5 my-8 animate-scale-up">
|
||||||
<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 -->
|
<!-- Top Title Bar -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-lg sm:text-xl font-extrabold text-white">Filter Stock</h2>
|
<h3 class="text-base sm:text-lg font-extrabold text-white">Filter Stock</h3>
|
||||||
<p class="text-xs sm:text-sm text-slate-400">Scroll and select pack states and categories</p>
|
<p class="text-xs text-slate-400">Scroll and select pack conditions and categories</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
onclick="resetAllFilters()"
|
||||||
|
class="px-3 py-1.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-bold transition active:scale-95 touch-manipulation"
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
<button onclick="closeFilterOverlay()" class="text-slate-400 hover:text-white p-2 rounded-xl bg-slate-800/60 touch-manipulation">
|
||||||
|
<i data-lucide="x" class="w-5 h-5"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- Section 1: Pack States (Scrollable cards) -->
|
<!-- Section 1: Pack States (Scrollable horizontal cards) -->
|
||||||
<div class="space-y-2.5">
|
<div class="space-y-2">
|
||||||
<div class="flex items-center justify-between">
|
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider block">Pack State & Condition</label>
|
||||||
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider">Pack States & Condition</label>
|
<div class="flex items-stretch gap-2.5 overflow-x-auto pb-1.5 scrollbar-none">
|
||||||
<span class="text-[11px] text-slate-500">Scroll horizontally →</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-stretch gap-3 overflow-x-auto pb-2 scrollbar-none pt-1">
|
|
||||||
<!-- All Pack States -->
|
<!-- All Pack States -->
|
||||||
<button
|
<button
|
||||||
onclick="setStatusFilter('all')"
|
onclick="setStatusFilter('all')"
|
||||||
data-filter-status="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"
|
class="filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border text-left flex flex-col justify-between space-y-2 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">
|
<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">
|
<span class="w-7 h-7 rounded-lg bg-teal-500/20 text-teal-300 flex items-center justify-center">
|
||||||
<i data-lucide="layers" class="w-4 h-4"></i>
|
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
|
||||||
</span>
|
</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>
|
<span id="filter-count-all" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-slate-300">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm sm:text-base font-extrabold text-white">All Stock</h4>
|
<h4 class="text-xs sm:text-sm font-extrabold text-white">All Stock</h4>
|
||||||
<p class="text-[11px] text-slate-400 mt-0.5">Everything in fridge</p>
|
<p class="text-[10px] text-slate-400">Everything</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -229,17 +231,17 @@
|
|||||||
<button
|
<button
|
||||||
onclick="setStatusFilter('full')"
|
onclick="setStatusFilter('full')"
|
||||||
data-filter-status="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"
|
class="filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border text-left flex flex-col justify-between space-y-2 transition-all active:scale-95 touch-manipulation bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between">
|
<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">
|
<span class="w-7 h-7 rounded-lg bg-emerald-500/20 text-emerald-400 flex items-center justify-center">
|
||||||
<i data-lucide="package-check" class="w-4 h-4"></i>
|
<i data-lucide="package-check" class="w-3.5 h-3.5"></i>
|
||||||
</span>
|
</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>
|
<span id="filter-count-full" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-emerald-300">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm sm:text-base font-extrabold text-white">Full Packs</h4>
|
<h4 class="text-xs sm:text-sm font-extrabold text-white">Full Packs</h4>
|
||||||
<p class="text-[11px] text-slate-400 mt-0.5">100% unopened items</p>
|
<p class="text-[10px] text-slate-400">Unopened</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -247,17 +249,17 @@
|
|||||||
<button
|
<button
|
||||||
onclick="setStatusFilter('opened')"
|
onclick="setStatusFilter('opened')"
|
||||||
data-filter-status="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"
|
class="filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border text-left flex flex-col justify-between space-y-2 transition-all active:scale-95 touch-manipulation bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between">
|
<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">
|
<span class="w-7 h-7 rounded-lg bg-indigo-500/20 text-indigo-400 flex items-center justify-center">
|
||||||
<i data-lucide="package-open" class="w-4 h-4"></i>
|
<i data-lucide="package-open" class="w-3.5 h-3.5"></i>
|
||||||
</span>
|
</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>
|
<span id="filter-count-opened" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-indigo-300">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm sm:text-base font-extrabold text-white">Opened</h4>
|
<h4 class="text-xs sm:text-sm font-extrabold text-white">Opened</h4>
|
||||||
<p class="text-[11px] text-slate-400 mt-0.5">In-use & partial packs</p>
|
<p class="text-[10px] text-slate-400">In-use & partial</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -265,47 +267,42 @@
|
|||||||
<button
|
<button
|
||||||
onclick="setStatusFilter('low')"
|
onclick="setStatusFilter('low')"
|
||||||
data-filter-status="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"
|
class="filter-status-card flex-1 min-w-[125px] p-3 rounded-2xl border text-left flex flex-col justify-between space-y-2 transition-all active:scale-95 touch-manipulation bg-slate-950 border-slate-800 text-slate-300 hover:border-slate-700"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between">
|
<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">
|
<span class="w-7 h-7 rounded-lg bg-amber-500/20 text-amber-400 flex items-center justify-center">
|
||||||
<i data-lucide="alert-circle" class="w-4 h-4"></i>
|
<i data-lucide="alert-circle" class="w-3.5 h-3.5"></i>
|
||||||
</span>
|
</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>
|
<span id="filter-count-low" class="text-[11px] font-bold px-1.5 py-0.5 rounded-md bg-slate-800 text-amber-300">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm sm:text-base font-extrabold text-white">Low Stock</h4>
|
<h4 class="text-xs sm:text-sm font-extrabold text-white">Low Stock</h4>
|
||||||
<p class="text-[11px] text-slate-400 mt-0.5">≤25% remaining</p>
|
<p class="text-[10px] text-slate-400">≤25% left</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 2: Categories (Scrollable touch grid) -->
|
<!-- Section 2: Categories (Scrollable touch grid) -->
|
||||||
<div class="space-y-2.5">
|
<div class="space-y-2">
|
||||||
<div class="flex items-center justify-between">
|
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider block">Category</label>
|
||||||
<label class="text-xs font-bold text-teal-400 uppercase tracking-wider">Categories</label>
|
<div id="filter-categories-container" class="grid grid-cols-2 sm:grid-cols-3 gap-2.5 max-h-[260px] overflow-y-auto p-1 scrollbar-none">
|
||||||
<span class="text-[11px] text-slate-500">Tap to filter</span>
|
<!-- Populated dynamically -->
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Floating Bottom Action Bar -->
|
<!-- Action: Done button -->
|
||||||
<div class="pt-2 sticky bottom-4 z-20">
|
<div class="pt-2 border-t border-slate-800">
|
||||||
<button
|
<button
|
||||||
onclick="navigateTo('/')"
|
onclick="closeFilterOverlay()"
|
||||||
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"
|
class="w-full py-3.5 rounded-2xl bg-teal-500 hover:bg-teal-400 text-white font-extrabold text-sm sm:text-base shadow-xl shadow-teal-500/25 active:scale-95 transition-all touch-manipulation flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
<i data-lucide="check" class="w-5 h-5"></i>
|
<i data-lucide="check" class="w-5 h-5"></i>
|
||||||
<span>View Filtered Stock (<span id="filter-total-count">0</span> items)</span>
|
<span>Show Matching Stock (<span id="filter-total-count">0</span> items)</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user