Apply liquid glass to pantry view
All checks were successful
Build and Deploy / build-and-push (push) Successful in 30s

This commit is contained in:
2026-04-22 19:49:29 +02:00
parent 120959365e
commit b9538a35b6
5 changed files with 251 additions and 201 deletions

View File

@@ -1,13 +1,16 @@
import { RECIPES } from '../data/catalog.js?v=9';
import { RECIPES, CATEGORY_LABELS } from '../data/catalog.js?v=9';
import { MEAL_SLOTS } from '../planner/mealSlots.js';
import { applyFilters, getFilterState } from './RecipeList.js';
import { ensureFilterPopoverStyles, filterChipStyle } from '../ui/filterPopover.js?v=1';
const PANTRY_CATEGORY_ORDER = ['pieczywo', 'nabial', 'mieso_ryby', 'warzywa', 'owoce', 'suche', 'przyprawy', 'inne'];
const PANTRY_SECTION_FILTERS = [
{ id: 'shortfalls', label: 'Potrzebne' },
{ id: 'sufficient', label: 'W spiżarni' },
{ id: 'notPlanned', label: 'Poza planem' },
];
const FILTER_PANEL_TRANSITION = 'opacity 180ms ease, transform 180ms ease';
const FILTER_SURFACE = 'var(--filter-liquid-panel-bg)';
const FILTER_SURFACE_SOFT = 'var(--filter-liquid-chip-bg)';
const FILTER_BORDER = 'var(--filter-liquid-border)';
const FILTER_CHIP_ACTIVE_BG = 'var(--filter-liquid-chip-active-bg)';
const FILTER_TEXT_SECONDARY = 'var(--filter-liquid-text-secondary)';
const FILTER_TEXT_MUTED = 'var(--filter-liquid-text-muted)';
const FILTER_TEXT_ACTIVE = 'var(--filter-liquid-text-active)';
const FILTER_TRACK = 'var(--filter-liquid-track-bg)';
@@ -57,52 +60,10 @@ function collectAllTags() {
export function getFilterHTML() {
return `
<style id="filter-view-styles">
#filter-view {
--filter-liquid-panel-bg: rgba(var(--app-bg-rgb), 0.78);
--filter-liquid-panel-shine: none;
--filter-liquid-border: rgba(255, 255, 255, 0.32);
--filter-liquid-chip-bg: rgba(var(--surface-rgb), 0.68);
--filter-liquid-chip-active-bg: rgba(var(--surface-rgb), 0.92);
--filter-liquid-track-bg: rgba(var(--overlay-rgb), 0.16);
--filter-liquid-accent-bg: rgba(255, 255, 255, 0.72);
--filter-liquid-text-active: rgb(var(--text-emphasis-rgb));
--filter-liquid-text-secondary: rgb(var(--text-body-soft-rgb));
--filter-liquid-text-muted: rgb(var(--text-muted-rgb));
--filter-liquid-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.6),
inset 0 -1px 0 rgba(var(--overlay-rgb), 0.06),
0 8px 20px rgba(var(--overlay-rgb), 0.16),
0 22px 52px rgba(var(--overlay-rgb), 0.24);
}
.dark #filter-view {
--filter-liquid-panel-bg: rgba(var(--app-bg-rgb), 0.82);
--filter-liquid-border: rgba(255, 255, 255, 0.12);
--filter-liquid-chip-bg: rgba(255, 255, 255, 0.08);
--filter-liquid-chip-active-bg: rgba(255, 255, 255, 0.16);
--filter-liquid-track-bg: rgba(255, 255, 255, 0.1);
--filter-liquid-accent-bg: rgba(255, 255, 255, 0.32);
--filter-liquid-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.24),
inset 0 -1px 0 rgba(0, 0, 0, 0.22),
0 10px 24px rgba(0, 0, 0, 0.36),
0 26px 60px rgba(0, 0, 0, 0.46);
}
#filter-view.filter-open {
pointer-events: auto;
}
#filter-panel {
isolation: isolate;
background: ${FILTER_SURFACE} !important;
background-image: none !important;
border: 1px solid ${FILTER_BORDER} !important;
box-shadow: var(--filter-liquid-shadow) !important;
backdrop-filter: blur(28px) saturate(180%);
-webkit-backdrop-filter: blur(28px) saturate(180%);
}
#filter-panel::before {
display: none;
}
@@ -141,8 +102,8 @@ export function getFilterHTML() {
0 4px 12px rgba(0,0,0,0.34);
}
</style>
<div id="filter-view" class="absolute inset-0 z-[70] hidden opacity-0 transition-opacity duration-150" style="pointer-events:none; background:transparent !important; background-image:none !important;" aria-hidden="true">
<div id="filter-panel" class="absolute flex flex-col overflow-hidden rounded-[1.35rem]" style="opacity:0; transform:translateY(0.65rem) scale(0.98); transform-origin:bottom center; transition:${FILTER_PANEL_TRANSITION}; width:min(calc(100% - 1.5rem), 22rem);">
<div id="filter-view" class="filter-liquid-surface absolute inset-0 z-[70] hidden opacity-0 transition-opacity duration-150" style="pointer-events:none; background:transparent !important; background-image:none !important;" aria-hidden="true">
<div id="filter-panel" class="filter-liquid-panel absolute flex flex-col overflow-hidden rounded-[1.35rem]" style="opacity:0; transform:translateY(0.65rem) scale(0.98); transform-origin:bottom center; transition:${FILTER_PANEL_TRANSITION}; width:min(calc(100% - 1.5rem), 22rem);">
<div class="shrink-0 px-3 pt-3 pb-2 flex items-center justify-between gap-3">
<p class="text-[11px] font-semibold leading-none" style="color:${FILTER_TEXT_ACTIVE};">Filtry</p>
<button id="filter-clear-btn" type="button" class="h-8 px-2 rounded-full text-[11px] font-semibold transition-colors" style="background:transparent; border:none; color:${FILTER_TEXT_MUTED};">Wyczyść</button>
@@ -237,16 +198,6 @@ function formatTimeRangeSummary(minMinutes, maxMinutes) {
return `${formatTimeValue(minMinutes)} - ${formatTimeValue(maxMinutes)}`;
}
function getChipStyle(active) {
const background = active ? FILTER_CHIP_ACTIVE_BG : FILTER_SURFACE_SOFT;
const color = active ? FILTER_TEXT_ACTIVE : FILTER_TEXT_SECONDARY;
const borderRule = active ? `border:1px solid ${FILTER_BORDER};` : 'border:none;';
const shadow = active
? 'box-shadow:0 1px 2px rgba(var(--overlay-rgb),0.08);'
: 'box-shadow:none;';
return `background:${background}; ${borderRule} color:${color}; ${shadow}`;
}
function clampTimeValue(value) {
return Math.min(Math.max(value, PREP_TIME_MIN), PREP_TIME_MAX);
}
@@ -399,7 +350,7 @@ function renderSlotChips() {
wrap.innerHTML = MEAL_SLOTS.map((slot) => {
const active = localSlots.includes(slot.id);
return `<button type="button" data-filter-slot="${escapeHtml(slot.id)}" class="px-3 py-2 rounded-full text-[11px] font-semibold transition-colors" style="${getChipStyle(active)}">${escapeHtml(slot.label)}</button>`;
return `<button type="button" data-filter-slot="${escapeHtml(slot.id)}" class="px-3 py-2 rounded-full text-[11px] font-semibold transition-colors" style="${filterChipStyle(active)}">${escapeHtml(slot.label)}</button>`;
}).join('');
wrap.querySelectorAll('[data-filter-slot]').forEach((btn) => {
@@ -421,7 +372,7 @@ function renderTagChips() {
const allTags = collectAllTags();
wrap.innerHTML = allTags.map((tag) => {
const active = localTags.includes(tag.toLowerCase());
return `<button type="button" data-filter-tag="${escapeHtml(tag)}" class="px-3 py-2 rounded-full text-[11px] font-semibold transition-colors" style="${getChipStyle(active)}">${escapeHtml(tag)}</button>`;
return `<button type="button" data-filter-tag="${escapeHtml(tag)}" class="px-3 py-2 rounded-full text-[11px] font-semibold transition-colors" style="${filterChipStyle(active)}">${escapeHtml(tag)}</button>`;
}).join('');
wrap.querySelectorAll('[data-filter-tag]').forEach((btn) => {
@@ -488,6 +439,7 @@ function syncLiveFilters() {
}
export function setupFilter() {
ensureFilterPopoverStyles();
const rangeTrack = document.getElementById('prep-time-range-fill')?.parentElement;
const minHandle = document.getElementById('prep-time-min-handle');
const maxHandle = document.getElementById('prep-time-max-handle');