Reorganizacja górnych paneli i ujednolicenie stylu filtrów
- Kalendarz: data między strzałkami zamiast napisu "Dziś", nawigacja po prawej, mniejszy komponent dopasowany do wysokości dnia - MealPlanner/Pantry/RecipeList: spójne nagłówki z tytułem po lewej i kontrolkami po prawej - RecipeList: nowy top bar z przyciskami filtrów i wyszukiwania wzorowany na spiżarni - Filter popup: ujednolicony styl z popoverem spiżarni (ciemniejsze tło, jaśniejsze obramowanie, spójne chipy) - Usunięcie przyciemnienia otoczenia przy otwieraniu filtrów - Badge z liczbą aktywnych filtrów na przycisku, zachowujący stan po zamknięciu popupu - Usunięcie ikon kalendarza z pigułek w spiżarni Made-with: Cursor
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
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;
|
||||
|
||||
/** Jak w spiżarni — cień „pigówek” i powłoki wyszukiwania */
|
||||
const SEARCH_SHELL_SHADOW = '0 5px 10px rgba(0,0,0,0.16), 0 14px 22px rgba(0,0,0,0.24), 0 22px 34px rgba(0,0,0,0.18), inset 0 1px 0 rgba(255,255,255,0.04)';
|
||||
|
||||
let filterState = {
|
||||
query: '',
|
||||
slots: [],
|
||||
@@ -16,6 +15,9 @@ let filterState = {
|
||||
maxMinutes: DEFAULT_MAX_MINUTES,
|
||||
};
|
||||
|
||||
let isSearchExpanded = false;
|
||||
let recipeListDocListenersBound = false;
|
||||
|
||||
function matchesFilters(recipe) {
|
||||
const { query, slots, tags, minMinutes, maxMinutes } = filterState;
|
||||
|
||||
@@ -46,7 +48,51 @@ function getFilteredRecipes() {
|
||||
|
||||
function syncRecipeScrollShadow() {
|
||||
const searchShell = document.getElementById('recipe-search-shell');
|
||||
syncRecipeSearchShellShadow(searchShell);
|
||||
if (searchShell) {
|
||||
searchShell.style.boxShadow = SEARCH_SHELL_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
function syncRecipeTopbarUI() {
|
||||
const defaultRow = document.getElementById('recipe-default-row');
|
||||
const searchShell = document.getElementById('recipe-search-shell');
|
||||
|
||||
const showSearch = isSearchExpanded;
|
||||
|
||||
if (defaultRow) {
|
||||
defaultRow.style.opacity = showSearch ? '0' : '1';
|
||||
defaultRow.style.transform = showSearch ? 'translateY(-2px) scale(0.98)' : 'translateY(0) scale(1)';
|
||||
defaultRow.style.pointerEvents = showSearch ? 'none' : 'auto';
|
||||
}
|
||||
|
||||
if (searchShell) {
|
||||
searchShell.style.opacity = showSearch ? '1' : '0';
|
||||
searchShell.style.transform = showSearch ? 'translateY(0) scale(1)' : 'translateY(-2px) scale(0.98)';
|
||||
searchShell.style.pointerEvents = showSearch ? 'auto' : 'none';
|
||||
searchShell.style.boxShadow = SEARCH_SHELL_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
const input = document.getElementById('recipe-search-input');
|
||||
const hadQuery = Boolean(input?.value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
input.blur();
|
||||
}
|
||||
filterState.query = '';
|
||||
isSearchExpanded = false;
|
||||
syncRecipeTopbarUI();
|
||||
if (hadQuery) renderGrid();
|
||||
}
|
||||
|
||||
function openSearch() {
|
||||
isSearchExpanded = true;
|
||||
window.closeFilters?.();
|
||||
syncRecipeTopbarUI();
|
||||
window.requestAnimationFrame(() => {
|
||||
document.getElementById('recipe-search-input')?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
function renderGrid() {
|
||||
@@ -61,6 +107,7 @@ function renderGrid() {
|
||||
showSlotLabels: false,
|
||||
cardClassName: 'recipe-list-card',
|
||||
});
|
||||
syncRecipeTopbarUI();
|
||||
requestAnimationFrame(syncRecipeScrollShadow);
|
||||
}
|
||||
|
||||
@@ -68,15 +115,33 @@ 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 class="pointer-events-auto relative z-[1] mx-auto" style="width:min(calc(100% - 0.5rem), 22.4rem);">
|
||||
<div id="recipe-topbar" class="relative min-h-12">
|
||||
|
||||
<div id="recipe-default-row" class="flex min-h-12 items-center gap-2 transition-all duration-200" style="opacity:1; transform:translateY(0) scale(1);">
|
||||
<h1 class="min-w-0 flex-1 truncate" style="margin:0;padding:0;color:#f2efe8;font-family:var(--app-font);font-size:18px;font-weight:700;line-height:1.2;letter-spacing:-0.02em;">Katalog przepisów</h1>
|
||||
|
||||
<div id="recipe-filter-wrap" class="relative shrink-0">
|
||||
<button type="button" id="recipe-filter-btn" class="relative w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:#393937; border:1px solid #41423f; box-shadow:${SEARCH_SHELL_SHADOW}; color:#ddd6ca;" aria-label="Otwórz filtry">
|
||||
<i class="fas fa-sliders-h text-[12px]" aria-hidden="true"></i>
|
||||
<span id="recipe-filter-count" class="hidden absolute -top-1 -right-1 min-w-[1.1rem] h-[1.1rem] px-1 rounded-full text-[9px] font-bold leading-none items-center justify-center" style="background:#23221e; border:1px solid #787876; color:#f2efe8;"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" id="recipe-search-toggle" class="w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:#393937 !important; border:1px solid #41423f !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; color:#ddd6ca;" aria-label="Szukaj">
|
||||
<i class="fas fa-search text-[13px]" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="recipe-search-shell" class="absolute inset-0 flex items-center gap-2 rounded-full px-3 transition-all duration-200 pointer-events-none" style="background:#23221e !important; border:1px solid #787876 !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; opacity:0; transform:translateY(-2px) scale(0.98);">
|
||||
<i class="fas fa-search text-[13px] shrink-0" style="color:#9b978f;"></i>
|
||||
<input type="search" id="recipe-search-input" autocomplete="off" placeholder="Szukaj przepisów…"
|
||||
class="flex-1 min-w-0 h-full bg-transparent outline-none text-[15px] leading-none py-0" style="background:transparent !important; border:none !important; box-shadow:none !important; color:#ddd6ca; margin:0;">
|
||||
<button type="button" id="recipe-search-close" class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center transition-colors" style="background:#2f2f2d; border:none; color:#9b978f;">
|
||||
<i class="fas fa-xmark text-[13px]"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -84,7 +149,7 @@ export function getRecipeListHTML() {
|
||||
scrollId: 'recipe-scroll',
|
||||
gridId: 'recipe-grid',
|
||||
emptyStateId: 'recipe-empty-state',
|
||||
scrollClassName: 'relative flex-1 overflow-y-auto px-4 pt-24 pb-24 bg-[#2d2e2b]',
|
||||
scrollClassName: 'relative flex-1 overflow-y-auto px-4 pt-[5.35rem] pb-24 bg-[#2d2e2b]',
|
||||
gridClassName: 'grid grid-cols-3 gap-2 bg-[#2d2e2b]',
|
||||
emptyTitle: 'Brak wyników',
|
||||
emptyMessage: 'Zmień kryteria wyszukiwania lub filtry',
|
||||
@@ -117,6 +182,21 @@ export function setupRecipeList() {
|
||||
filterState.query = e.target.value.trim();
|
||||
renderGrid();
|
||||
});
|
||||
document.getElementById('recipe-search-input')?.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') closeSearch();
|
||||
});
|
||||
|
||||
document.getElementById('recipe-search-toggle')?.addEventListener('click', () => openSearch());
|
||||
document.getElementById('recipe-search-close')?.addEventListener('click', () => closeSearch());
|
||||
|
||||
document.getElementById('recipe-filter-btn')?.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
if (isSearchExpanded) {
|
||||
isSearchExpanded = false;
|
||||
syncRecipeTopbarUI();
|
||||
}
|
||||
window.openFilters?.('recipes');
|
||||
});
|
||||
|
||||
document.getElementById('recipe-grid')?.addEventListener('click', (e) => {
|
||||
const card = e.target.closest('.recipe-browser-card');
|
||||
@@ -127,4 +207,14 @@ export function setupRecipeList() {
|
||||
|
||||
document.getElementById('recipe-scroll')?.addEventListener('scroll', syncRecipeScrollShadow);
|
||||
syncRecipeScrollShadow();
|
||||
|
||||
if (!recipeListDocListenersBound) {
|
||||
recipeListDocListenersBound = true;
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'Escape' || !isSearchExpanded) return;
|
||||
if (!document.getElementById('main-view')?.classList.contains('hidden')) {
|
||||
closeSearch();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user