Filter popup improvement
This commit is contained in:
27
index.html
27
index.html
@@ -8,7 +8,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="apple-mobile-web-app-title" content="Recipe">
|
<meta name="apple-mobile-web-app-title" content="Recipe">
|
||||||
<title>Recipe App - Modular</title>
|
<title>Recipe App - Modular</title>
|
||||||
<link rel="manifest" href="./manifest.webmanifest?v=20260406-42">
|
<link rel="manifest" href="./manifest.webmanifest?v=20260406-51">
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="./icons/icon-192.png">
|
<link rel="icon" type="image/png" sizes="192x192" href="./icons/icon-192.png">
|
||||||
<link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
@@ -384,8 +384,6 @@
|
|||||||
}
|
}
|
||||||
#app-bottom-nav .bottom-dock {
|
#app-bottom-nav .bottom-dock {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 0;
|
|
||||||
isolation: isolate;
|
|
||||||
width: min(calc(100% - 2rem), 22.4rem);
|
width: min(calc(100% - 2rem), 22.4rem);
|
||||||
min-height: 3.7rem;
|
min-height: 3.7rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -399,26 +397,9 @@
|
|||||||
box-shadow:
|
box-shadow:
|
||||||
0 5px 10px rgba(0, 0, 0, 0.16),
|
0 5px 10px rgba(0, 0, 0, 0.16),
|
||||||
0 14px 22px rgba(0, 0, 0, 0.24),
|
0 14px 22px rgba(0, 0, 0, 0.24),
|
||||||
0 22px 34px rgba(0, 0, 0, 0.18),
|
0 22px 34px rgba(0, 0, 0, 0.18);
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
||||||
backdrop-filter: blur(24px);
|
|
||||||
-webkit-backdrop-filter: blur(24px);
|
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
#app-bottom-nav .bottom-dock::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 11%;
|
|
||||||
right: 11%;
|
|
||||||
bottom: -0.72rem;
|
|
||||||
height: 1.05rem;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: rgba(0, 0, 0, 0.36);
|
|
||||||
filter: blur(12px);
|
|
||||||
opacity: 0.9;
|
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
#app-bottom-nav .nav-tab,
|
#app-bottom-nav .nav-tab,
|
||||||
#app-bottom-nav .nav-action {
|
#app-bottom-nav .nav-action {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
@@ -528,7 +509,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const APP_ASSET_VERSION = '20260406-42';
|
const APP_ASSET_VERSION = '20260406-51';
|
||||||
const APP_VERSION_STORAGE_KEY = 'recipe-app-asset-version';
|
const APP_VERSION_STORAGE_KEY = 'recipe-app-asset-version';
|
||||||
const APP_VERSION_QUERY_KEY = 'appv';
|
const APP_VERSION_QUERY_KEY = 'appv';
|
||||||
|
|
||||||
@@ -562,7 +543,7 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
const appVersion = window.__APP_ASSET_VERSION__ || '20260406-42';
|
const appVersion = window.__APP_ASSET_VERSION__ || '20260406-51';
|
||||||
const recoveryKey = `recipe-app-recovery-${appVersion}`;
|
const recoveryKey = `recipe-app-recovery-${appVersion}`;
|
||||||
|
|
||||||
function renderBootstrapError(message) {
|
function renderBootstrapError(message) {
|
||||||
|
|||||||
@@ -491,7 +491,6 @@ export function setupFilter() {
|
|||||||
|
|
||||||
renderSlotChips();
|
renderSlotChips();
|
||||||
renderTagChips();
|
renderTagChips();
|
||||||
syncLiveFilters();
|
|
||||||
|
|
||||||
showFilterPanel();
|
showFilterPanel();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ function getFilteredRecipes() {
|
|||||||
function renderRecipeCard(recipe) {
|
function renderRecipeCard(recipe) {
|
||||||
const labels = slotLabelsFor(recipe);
|
const labels = slotLabelsFor(recipe);
|
||||||
return `
|
return `
|
||||||
<div onclick="openRecipeDetail('${escapeHtml(recipe.id)}')" class="rounded-xl overflow-hidden flex flex-col bg-[#393937] cursor-pointer transition-shadow" style="background:#393937 !important; border:none !important; box-shadow:none !important;">
|
<div data-recipe-id="${escapeHtml(recipe.id)}" onclick="openRecipeDetail('${escapeHtml(recipe.id)}')" class="recipe-card rounded-xl overflow-hidden flex flex-col bg-[#393937] cursor-pointer transition-shadow" style="background:#393937 !important; border:none !important; box-shadow:none !important;">
|
||||||
<div class="h-32 bg-[#d4d4d4] relative overflow-hidden">
|
<div class="h-32 bg-[#d4d4d4] relative overflow-hidden">
|
||||||
${recipe.image
|
${recipe.image
|
||||||
? `<img src="${escapeHtml(recipe.image)}" alt="${escapeHtml(recipe.title)}" class="w-full h-full object-cover">`
|
? `<img src="${escapeHtml(recipe.image)}" alt="${escapeHtml(recipe.title)}" class="w-full h-full object-cover">`
|
||||||
@@ -81,6 +81,17 @@ function renderRecipeCard(recipe) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEmptyStateHTML() {
|
||||||
|
return `
|
||||||
|
<div id="recipe-empty-state" class="hidden flex flex-col items-center justify-center py-16 text-center">
|
||||||
|
<div class="w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center mb-4">
|
||||||
|
<i class="fas fa-search text-2xl text-gray-300"></i>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm font-semibold text-gray-700">Brak wyników</p>
|
||||||
|
<p class="text-xs text-gray-500 mt-1 max-w-[220px] leading-relaxed">Zmień kryteria wyszukiwania lub filtry</p>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
function syncRecipeScrollShadow() {
|
function syncRecipeScrollShadow() {
|
||||||
const scroll = document.getElementById('recipe-scroll');
|
const scroll = document.getElementById('recipe-scroll');
|
||||||
const searchShell = document.getElementById('recipe-search-shell');
|
const searchShell = document.getElementById('recipe-search-shell');
|
||||||
@@ -94,26 +105,41 @@ function syncRecipeScrollShadow() {
|
|||||||
searchShell.style.boxShadow = SEARCH_SHELL_BASE_SHADOW;
|
searchShell.style.boxShadow = SEARCH_SHELL_BASE_SHADOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderGrid() {
|
function renderAllRecipeCards() {
|
||||||
const grid = document.getElementById('recipe-grid');
|
const grid = document.getElementById('recipe-grid');
|
||||||
if (!grid) return;
|
if (!grid) return;
|
||||||
|
|
||||||
const recipes = getFilteredRecipes();
|
grid.innerHTML = Object.values(RECIPES).map(renderRecipeCard).join('');
|
||||||
if (recipes.length === 0) {
|
}
|
||||||
grid.innerHTML = `
|
|
||||||
<div class="col-span-2 flex flex-col items-center justify-center py-16 text-center">
|
function syncVisibleRecipeCards() {
|
||||||
<div class="w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center mb-4">
|
const grid = document.getElementById('recipe-grid');
|
||||||
<i class="fas fa-search text-2xl text-gray-300"></i>
|
const emptyState = document.getElementById('recipe-empty-state');
|
||||||
</div>
|
if (!grid || !emptyState) return;
|
||||||
<p class="text-sm font-semibold text-gray-700">Brak wyników</p>
|
|
||||||
<p class="text-xs text-gray-500 mt-1 max-w-[220px] leading-relaxed">Zmień kryteria wyszukiwania lub filtry</p>
|
let visibleCount = 0;
|
||||||
</div>`;
|
grid.querySelectorAll('[data-recipe-id]').forEach((card) => {
|
||||||
requestAnimationFrame(syncRecipeScrollShadow);
|
const recipeId = card.getAttribute('data-recipe-id');
|
||||||
return;
|
const recipe = recipeId ? RECIPES[recipeId] : null;
|
||||||
|
const isVisible = Boolean(recipe && matchesFilters(recipe));
|
||||||
|
card.classList.toggle('hidden', !isVisible);
|
||||||
|
if (isVisible) visibleCount += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
grid.classList.toggle('hidden', visibleCount === 0);
|
||||||
|
emptyState.classList.toggle('hidden', visibleCount !== 0);
|
||||||
|
requestAnimationFrame(syncRecipeScrollShadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderGrid({ rebuild = false } = {}) {
|
||||||
|
const grid = document.getElementById('recipe-grid');
|
||||||
|
if (!grid) return;
|
||||||
|
|
||||||
|
if (rebuild || !grid.querySelector('[data-recipe-id]')) {
|
||||||
|
renderAllRecipeCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.innerHTML = recipes.map(renderRecipeCard).join('');
|
syncVisibleRecipeCards();
|
||||||
requestAnimationFrame(syncRecipeScrollShadow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRecipeListHTML() {
|
export function getRecipeListHTML() {
|
||||||
@@ -130,6 +156,7 @@ export function getRecipeListHTML() {
|
|||||||
|
|
||||||
<div id="recipe-scroll" class="relative flex-1 overflow-y-auto px-4 pt-20 pb-24 bg-[#2d2e2b]" style="background:#2d2e2b !important;">
|
<div id="recipe-scroll" class="relative flex-1 overflow-y-auto px-4 pt-20 pb-24 bg-[#2d2e2b]" style="background:#2d2e2b !important;">
|
||||||
<div id="recipe-grid" class="grid grid-cols-2 gap-3 bg-[#2d2e2b]" style="background:#2d2e2b !important;"></div>
|
<div id="recipe-grid" class="grid grid-cols-2 gap-3 bg-[#2d2e2b]" style="background:#2d2e2b !important;"></div>
|
||||||
|
${getEmptyStateHTML()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -149,11 +176,11 @@ export function getFilteredCount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function refreshRecipeList() {
|
export function refreshRecipeList() {
|
||||||
renderGrid();
|
renderGrid({ rebuild: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupRecipeList() {
|
export function setupRecipeList() {
|
||||||
renderGrid();
|
renderGrid({ rebuild: true });
|
||||||
|
|
||||||
document.getElementById('recipe-search-input')?.addEventListener('input', (e) => {
|
document.getElementById('recipe-search-input')?.addEventListener('input', (e) => {
|
||||||
filterState.query = e.target.value.trim();
|
filterState.query = e.target.value.trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user