export function getBottomNavHTML() { return ` `; } export function setupBottomNav({ refreshPantry, refreshShoppingList } = {}) { const main = document.getElementById('main-view'); const planner = document.getElementById('planner-view'); const pantry = document.getElementById('pantry-view'); const shopping = document.getElementById('shopping-view'); const nav = document.getElementById('app-bottom-nav'); if (!main || !planner || !pantry || !shopping || !nav) return; const TABS = ['recipes', 'planner', 'pantry', 'shopping']; let isRecipeMenuOpen = false; let previousTab = 'planner'; let collapseTimer = null; const syncRecipeNavMetrics = () => { const rootFontSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize) || 16; const navStyles = window.getComputedStyle(nav); const navPadLeft = parseFloat(navStyles.paddingLeft) || 0; const navPadRight = parseFloat(navStyles.paddingRight) || 0; const navContentWidth = nav.clientWidth - navPadLeft - navPadRight; const isCompact = window.matchMedia('(max-width: 380px)').matches; const dockInset = (isCompact ? 1.6 : 2.4) * rootFontSize; const dockMax = (isCompact ? 22.5 : 24.5) * rootFontSize; const dockWidth = Math.min(navContentWidth - dockInset, dockMax); if (dockWidth <= 0) return; const padLeft = (isCompact ? 0.38 : 0.42) * rootFontSize; const padRight = (isCompact ? 0.38 : 0.42) * rootFontSize; const columnGap = (isCompact ? 0.05 : 0.06) * rootFontSize; const slotWidth = Math.max(44, (dockWidth - padLeft - padRight - (columnGap * 3)) / 4); const collapsedSlotWidth = Math.max(42, Math.min(slotWidth, isCompact ? 44 : 46)); const collapsedDockWidth = collapsedSlotWidth + padLeft + padRight; const dockLeft = navPadLeft + ((navContentWidth - dockWidth) / 2); const controlSize = (isCompact ? 2.95 : 3.05) * rootFontSize; const expandedDockHeight = (isCompact ? 3.48 : 3.72) * rootFontSize; const controlGap = 0.5 * rootFontSize; const controlsLift = Math.max(0, (expandedDockHeight - controlSize) / 2); const filterLeft = Math.max( dockLeft + collapsedDockWidth + controlGap, dockLeft + dockWidth - padRight - controlSize, ); const searchRight = Math.max(16, nav.clientWidth - filterLeft + controlGap); nav.style.setProperty('--recipe-dock-width', `${dockWidth}px`); nav.style.setProperty('--recipe-collapsed-dock-width', `${collapsedDockWidth}px`); nav.style.setProperty('--recipe-toggle-size', `${collapsedSlotWidth}px`); document.documentElement.style.setProperty('--catalog-menu-left', `${dockLeft}px`); document.documentElement.style.setProperty('--catalog-menu-width', `${collapsedDockWidth}px`); document.documentElement.style.setProperty('--catalog-filter-left', `${filterLeft}px`); document.documentElement.style.setProperty('--catalog-search-right', `${searchRight}px`); document.documentElement.style.setProperty('--recipe-control-size', `${controlSize}px`); document.documentElement.style.setProperty('--recipe-controls-lift', `${controlsLift}px`); }; const setRecipeMenuOpen = (open) => { syncRecipeNavMetrics(); window.clearTimeout(collapseTimer); isRecipeMenuOpen = open; nav.classList.remove('is-recipes-collapsing'); nav.classList.toggle('is-recipes-menu-open', open); document.documentElement.classList.toggle('is-recipes-menu-open', open); document.getElementById('recipe-nav-toggle')?.setAttribute('aria-expanded', open ? 'true' : 'false'); }; const apply = (tab) => { const wasRecipeTab = previousTab === 'recipes'; main.classList.toggle('hidden', tab !== 'recipes'); planner.classList.toggle('hidden', tab !== 'planner'); pantry.classList.toggle('hidden', tab !== 'pantry'); shopping.classList.toggle('hidden', tab !== 'shopping'); nav.classList.toggle('is-recipes-tab', tab === 'recipes'); syncRecipeNavMetrics(); setRecipeMenuOpen(false); if (tab === 'recipes' && !wasRecipeTab) { nav.classList.add('is-recipes-menu-open', 'is-recipes-collapsing'); document.documentElement.classList.add('is-recipes-menu-open'); document.getElementById('recipe-nav-toggle')?.setAttribute('aria-expanded', 'false'); requestAnimationFrame(() => { requestAnimationFrame(() => { requestAnimationFrame(() => { nav.classList.remove('is-recipes-menu-open'); document.documentElement.classList.remove('is-recipes-menu-open'); collapseTimer = window.setTimeout(() => { nav.classList.remove('is-recipes-collapsing'); }, 500); }); }); }); } if (tab === 'pantry' && typeof refreshPantry === 'function') refreshPantry(); if (tab === 'shopping' && typeof refreshShoppingList === 'function') refreshShoppingList(); nav.querySelectorAll('.nav-tab[data-tab]').forEach((btn) => { const id = btn.getAttribute('data-tab'); if (btn.hasAttribute('disabled')) return; if (TABS.includes(id)) { const isActive = id === tab; btn.classList.toggle('is-active', isActive); if (isActive) btn.setAttribute('aria-current', 'page'); else btn.removeAttribute('aria-current'); } }); window.dispatchEvent(new CustomEvent('app-tab-change', { detail: { tab } })); previousTab = tab; }; nav.addEventListener('click', (e) => { const toggle = e.target.closest('#recipe-nav-toggle'); if (toggle) { e.stopPropagation(); setRecipeMenuOpen(!isRecipeMenuOpen); window.closeRecipeSearch?.(); window.closeFilters?.(); return; } const btn = e.target.closest('.nav-tab[data-tab]'); if (!btn || btn.hasAttribute('disabled')) return; const tab = btn.getAttribute('data-tab'); if (TABS.includes(tab)) apply(tab); }); document.addEventListener('click', (e) => { if (!isRecipeMenuOpen || !nav.classList.contains('is-recipes-tab')) return; if (e.composedPath().includes(nav)) return; setRecipeMenuOpen(false); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && isRecipeMenuOpen) setRecipeMenuOpen(false); }); window.addEventListener('resize', syncRecipeNavMetrics); apply('planner'); window.switchAppTab = (tab) => { if (TABS.includes(tab)) apply(tab); }; window.refreshStockViews = () => { if (typeof refreshPantry === 'function') refreshPantry(); }; }