Files
recipe-mockup/js/views/RecipeList.js

129 lines
3.9 KiB
JavaScript

import { RECIPES } from '../data/catalog.js?v=8';
import { getRecipeGridSectionHTML, renderRecipeGrid } from '../ui/recipeGrid.js';
import {
getRecipeSearchFieldHTML,
syncRecipeSearchShellShadow,
} from '../ui/recipeSearchField.js';
const DEFAULT_MIN_MINUTES = 5;
const DEFAULT_MAX_MINUTES = 120;
let filterState = {
query: '',
slots: [],
tags: [],
minMinutes: DEFAULT_MIN_MINUTES,
maxMinutes: DEFAULT_MAX_MINUTES,
};
function matchesFilters(recipe) {
const { query, slots, tags, minMinutes, maxMinutes } = filterState;
if (query) {
const q = query.toLowerCase();
const haystack = `${recipe.title} ${(recipe.tags || []).join(' ')}`.toLowerCase();
if (!haystack.includes(q)) return false;
}
if (slots.length > 0) {
if (!recipe.allowedSlots.some((s) => slots.includes(s))) return false;
}
if (tags.length > 0) {
const recipeTags = (recipe.tags || []).map((t) => t.toLowerCase());
if (!tags.some((t) => recipeTags.includes(t.toLowerCase()))) return false;
}
if (minMinutes > DEFAULT_MIN_MINUTES && recipe.minutes < minMinutes) return false;
if (maxMinutes < DEFAULT_MAX_MINUTES && recipe.minutes > maxMinutes) return false;
return true;
}
function getFilteredRecipes() {
return Object.values(RECIPES).filter(matchesFilters);
}
function syncRecipeScrollShadow() {
const searchShell = document.getElementById('recipe-search-shell');
syncRecipeSearchShellShadow(searchShell);
}
function renderGrid() {
const grid = document.getElementById('recipe-grid');
const emptyState = document.getElementById('recipe-empty-state');
if (!grid) return;
renderRecipeGrid({
gridEl: grid,
emptyStateEl: emptyState,
recipes: getFilteredRecipes(),
});
requestAnimationFrame(syncRecipeScrollShadow);
}
export function getRecipeListHTML() {
return `
<div id="main-view" class="flex flex-col h-full absolute inset-0 bg-[#2d2e2b] z-10" style="background:#2d2e2b !important;">
<div id="recipe-top-bar" class="pointer-events-none absolute inset-x-0 top-0 z-[12] px-4 pt-4" style="background:transparent !important; border:none !important;">
<div class="pointer-events-auto">
${getRecipeSearchFieldHTML({
shellId: 'recipe-search-shell',
inputId: 'recipe-search-input',
placeholder: 'Szukaj przepisów...',
filterButtonId: 'recipe-filter-btn',
filterButtonAction: 'openFilters()',
filterButtonLabel: 'Otwórz filtry',
})}
</div>
</div>
${getRecipeGridSectionHTML({
scrollId: 'recipe-scroll',
gridId: 'recipe-grid',
emptyStateId: 'recipe-empty-state',
scrollClassName: 'relative flex-1 overflow-y-auto px-4 pt-20 pb-24 bg-[#2d2e2b]',
gridClassName: 'grid grid-cols-2 gap-3 bg-[#2d2e2b]',
emptyTitle: 'Brak wyników',
emptyMessage: 'Zmień kryteria wyszukiwania lub filtry',
})}
</div>
`;
}
export function getFilterState() {
return filterState;
}
export function applyFilters(newState) {
Object.assign(filterState, newState);
renderGrid();
}
export function getFilteredCount() {
return getFilteredRecipes().length;
}
export function refreshRecipeList() {
renderGrid();
}
export function setupRecipeList() {
renderGrid();
document.getElementById('recipe-search-input')?.addEventListener('input', (e) => {
filterState.query = e.target.value.trim();
renderGrid();
});
document.getElementById('recipe-grid')?.addEventListener('click', (e) => {
const card = e.target.closest('.recipe-browser-card');
if (!card) return;
const recipeId = card.getAttribute('data-recipe-id');
if (recipeId) window.openRecipeDetail?.(recipeId);
});
document.getElementById('recipe-scroll')?.addEventListener('scroll', syncRecipeScrollShadow);
syncRecipeScrollShadow();
}