All checks were successful
Build and Deploy / build-and-push (push) Successful in 27s
202 lines
9.5 KiB
JavaScript
202 lines
9.5 KiB
JavaScript
export function getBottomNavHTML() {
|
|
return `
|
|
<nav id="app-bottom-nav" aria-label="Główna nawigacja">
|
|
<div id="app-bottom-nav-dock" class="bottom-dock">
|
|
<button type="button" id="recipe-nav-toggle" class="recipe-nav-toggle" aria-label="Otwórz menu" aria-expanded="false" aria-controls="app-bottom-nav-dock">
|
|
<i id="recipe-nav-toggle-icon" class="fas fa-book-open" aria-hidden="true"></i>
|
|
</button>
|
|
<div class="nav-slot">
|
|
<button type="button" data-tab="planner" id="nav-planner" class="nav-tab is-active" aria-label="Planer" aria-current="page">
|
|
<i class="far fa-calendar-alt" aria-hidden="true"></i>
|
|
<span class="nav-label">Planer</span>
|
|
</button>
|
|
</div>
|
|
<div class="nav-slot">
|
|
<button type="button" data-tab="recipes" id="nav-recipes" class="nav-tab" aria-label="Katalog">
|
|
<i class="fas fa-book-open" aria-hidden="true"></i>
|
|
<span class="nav-label">Katalog</span>
|
|
</button>
|
|
</div>
|
|
<div class="nav-slot">
|
|
<button type="button" data-tab="pantry" id="nav-pantry" class="nav-tab" aria-label="Spiżarnia">
|
|
<i class="fas fa-warehouse" aria-hidden="true"></i>
|
|
<span class="nav-label">Spiżarnia</span>
|
|
</button>
|
|
</div>
|
|
<div class="nav-slot" style="position:relative;">
|
|
<button type="button" data-tab="shopping" id="nav-shopping" class="nav-tab" aria-label="Zakupy">
|
|
<i class="fas fa-cart-shopping" aria-hidden="true"></i>
|
|
<span class="nav-label">Zakupy</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
`;
|
|
}
|
|
|
|
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'];
|
|
const COLLAPSED_TABS = new Set(['recipes', 'pantry']);
|
|
const COLLAPSED_TAB_ICON = { recipes: 'fa-book-open', pantry: 'fa-warehouse' };
|
|
const COLLAPSED_TAB_LABEL = { recipes: 'Otwórz menu katalogu', pantry: 'Otwórz menu spiżarni' };
|
|
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 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 collapsedDockWidth = controlSize;
|
|
const collapsedSlotWidth = Math.max(32, collapsedDockWidth - padLeft - padRight);
|
|
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('--recipe-dock-width', `${dockWidth}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 updateToggleForTab = (tab) => {
|
|
const icon = document.getElementById('recipe-nav-toggle-icon');
|
|
const button = document.getElementById('recipe-nav-toggle');
|
|
const nextIcon = COLLAPSED_TAB_ICON[tab];
|
|
if (icon && nextIcon) {
|
|
icon.className = `fas ${nextIcon}`;
|
|
}
|
|
if (button && COLLAPSED_TAB_LABEL[tab]) {
|
|
button.setAttribute('aria-label', COLLAPSED_TAB_LABEL[tab]);
|
|
}
|
|
};
|
|
|
|
const setRecipeMenuOpen = (open) => {
|
|
syncRecipeNavMetrics();
|
|
window.clearTimeout(collapseTimer);
|
|
isRecipeMenuOpen = open;
|
|
nav.classList.remove('is-nav-collapsing');
|
|
nav.classList.toggle('is-nav-menu-open', open);
|
|
document.documentElement.classList.toggle('is-nav-menu-open', open);
|
|
document.getElementById('recipe-nav-toggle')?.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
};
|
|
|
|
const apply = (tab) => {
|
|
const wasCollapsedTab = COLLAPSED_TABS.has(previousTab);
|
|
const isCollapsedTab = COLLAPSED_TABS.has(tab);
|
|
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-collapsed-tab', isCollapsedTab);
|
|
updateToggleForTab(tab);
|
|
syncRecipeNavMetrics();
|
|
setRecipeMenuOpen(false);
|
|
|
|
if (isCollapsedTab && (!wasCollapsedTab || tab !== previousTab)) {
|
|
nav.classList.add('is-nav-menu-open', 'is-nav-collapsing');
|
|
document.documentElement.classList.add('is-nav-menu-open');
|
|
document.getElementById('recipe-nav-toggle')?.setAttribute('aria-expanded', 'false');
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
nav.classList.remove('is-nav-menu-open');
|
|
document.documentElement.classList.remove('is-nav-menu-open');
|
|
collapseTimer = window.setTimeout(() => {
|
|
nav.classList.remove('is-nav-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.closePantrySearch?.();
|
|
window.closePantryFilter?.();
|
|
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-collapsed-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();
|
|
};
|
|
}
|