This commit is contained in:
111
index.html
111
index.html
@@ -23,42 +23,46 @@
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--app-font: 'Plus Jakarta Sans', 'Segoe UI', sans-serif;
|
||||
--app-bg-rgb: 243, 239, 233;
|
||||
--surface-rgb: 255, 255, 255;
|
||||
--surface-soft-rgb: 247, 242, 236;
|
||||
--surface-strong-rgb: 235, 229, 221;
|
||||
--line-rgb: 69, 58, 48;
|
||||
--text-primary-rgb: 28, 24, 21;
|
||||
--text-secondary-rgb: 102, 92, 83;
|
||||
--text-tertiary-rgb: 156, 146, 137;
|
||||
--warm-rgb: 183, 142, 88;
|
||||
--success-rgb: 98, 171, 132;
|
||||
--danger-rgb: 210, 116, 116;
|
||||
--app-bg-rgb: 243, 239, 233; /* #f3efe9 — warm cream base */
|
||||
--surface-rgb: 255, 255, 255; /* #ffffff — white panels (existing tokens) */
|
||||
--surface-soft-rgb: 249, 245, 238; /* #f9f5ee */
|
||||
--surface-strong-rgb: 235, 229, 220; /* #ebe5dc */
|
||||
--line-rgb: 69, 58, 48; /* #453a30 — divider base (warm brown) */
|
||||
--text-primary-rgb: 28, 24, 21; /* #1c1815 */
|
||||
--text-secondary-rgb: 102, 92, 83; /* #665c53 */
|
||||
--text-tertiary-rgb: 140, 130, 118; /* #8c8276 */
|
||||
--warm-rgb: 183, 142, 88; /* #b78e58 — caramel */
|
||||
--success-rgb: 47, 133, 82; /* #2f8552 — deep emerald (AA on white) */
|
||||
--danger-rgb: 187, 75, 75; /* #bb4b4b — deep rose (AA on white) */
|
||||
--panel-shadow: 0 18px 40px rgba(24, 17, 11, 0.08);
|
||||
--panel-shadow-strong: 0 24px 60px rgba(24, 17, 11, 0.16);
|
||||
--dock-shadow: 0 24px 56px rgba(24, 17, 11, 0.18);
|
||||
--highlight-top: rgba(111, 149, 255, 0.14);
|
||||
--highlight-bottom: rgba(97, 184, 180, 0.12);
|
||||
--highlight-top: transparent;
|
||||
--highlight-bottom: transparent;
|
||||
|
||||
/* Extended palette (placeholder light-mode values — light mode is WIP). */
|
||||
--card-rgb: 255, 255, 255;
|
||||
--card-soft-rgb: 250, 246, 240;
|
||||
--card-strong-rgb: 235, 229, 221;
|
||||
--card-raised-rgb: 252, 248, 242;
|
||||
--sunken-rgb: 247, 242, 236;
|
||||
--sunken-deep-rgb: 235, 229, 221;
|
||||
--border-card-rgb: 220, 212, 200;
|
||||
--border-input-rgb: 176, 164, 150;
|
||||
--text-emphasis-rgb: 14, 12, 10;
|
||||
--text-body-rgb: 48, 40, 33;
|
||||
--text-body-soft-rgb: 72, 62, 52;
|
||||
--text-muted-rgb: 112, 102, 91;
|
||||
--text-dim-rgb: 140, 130, 118;
|
||||
--text-faint-rgb: 156, 146, 137;
|
||||
--text-subdued-rgb: 176, 166, 154;
|
||||
--skeleton-rgb: 226, 220, 210;
|
||||
--on-accent-rgb: 255, 255, 255;
|
||||
--overlay-rgb: 24, 17, 11;
|
||||
/* Extended light palette — mirrors dark hierarchy: sunken < app-bg < card. */
|
||||
--card-rgb: 255, 255, 255; /* #ffffff — primary elevated card (raised via shadow) */
|
||||
--card-soft-rgb: 239, 233, 221; /* #efe9dd — nested/medium surface on white */
|
||||
--card-strong-rgb: 228, 219, 205; /* #e4dbcd — strong surface / stroke */
|
||||
--card-raised-rgb: 252, 249, 242; /* #fcf9f2 — subtle raise (chip on card) */
|
||||
--sunken-rgb: 235, 229, 217; /* #ebe5d9 — deep inputs / search shell */
|
||||
--sunken-deep-rgb: 219, 211, 196; /* #dbd3c4 — deepest well */
|
||||
--border-card-rgb: 224, 215, 200; /* #e0d7c8 — subtle card/dock border */
|
||||
--border-input-rgb: 180, 168, 150; /* #b4a896 — input / active border */
|
||||
--text-emphasis-rgb: 14, 12, 10; /* #0e0c0a — brightest interactive text */
|
||||
--text-body-rgb: 48, 40, 33; /* #302821 — primary body text (most common) */
|
||||
--text-body-soft-rgb: 72, 62, 52; /* #483e34 — body soft */
|
||||
--text-muted-rgb: 102, 92, 83; /* #665c53 — muted (matches --text-secondary) */
|
||||
--text-dim-rgb: 140, 130, 118; /* #8c8276 — dim / placeholder */
|
||||
--text-faint-rgb: 156, 146, 137; /* #9c9289 — faint icon color */
|
||||
--text-subdued-rgb: 176, 166, 154; /* #b0a69a — subdued */
|
||||
--skeleton-rgb: 226, 220, 210; /* #e2dcd2 — image loading placeholder */
|
||||
--on-accent-rgb: 255, 255, 255; /* white text on accent backgrounds */
|
||||
--overlay-rgb: 24, 17, 11; /* #18110b — scrim / shadow base (warm brown-black) */
|
||||
--shadow-card: 0 2px 8px rgba(24, 17, 11, 0.08);
|
||||
--shadow-shell: 0 5px 10px rgba(24, 17, 11, 0.08), 0 14px 22px rgba(24, 17, 11, 0.12), 0 22px 34px rgba(24, 17, 11, 0.10), inset 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
--icon-watermark: rgba(24, 17, 11, 0.08);
|
||||
--hover-overlay: rgba(24, 17, 11, 0.05);
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -99,6 +103,10 @@
|
||||
--skeleton-rgb: 212, 212, 212; /* #d4d4d4 — image loading placeholder */
|
||||
--on-accent-rgb: 26, 26, 26; /* #1a1a1a — text on bright accent backgrounds */
|
||||
--overlay-rgb: 0, 0, 0; /* scrim / shadow base */
|
||||
--shadow-card: 0 2px 8px rgba(0, 0, 0, 0.25);
|
||||
--shadow-shell: 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);
|
||||
--icon-watermark: rgba(255, 255, 255, 0.10);
|
||||
--hover-overlay: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
* { touch-action: manipulation; }
|
||||
@@ -124,7 +132,7 @@
|
||||
border-radius: 50%;
|
||||
background: rgb(var(--text-body-rgb));
|
||||
border: 2px solid rgba(var(--surface-rgb), 0.9);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.22);
|
||||
box-shadow: 0 8px 20px rgba(var(--overlay-rgb), 0.22);
|
||||
cursor: pointer;
|
||||
margin-top: -8px;
|
||||
}
|
||||
@@ -155,8 +163,12 @@
|
||||
.bg-gray-100 { background-color: rgba(var(--surface-soft-rgb), 0.92) !important; }
|
||||
.bg-gray-200 { background-color: rgba(var(--surface-strong-rgb), 0.94) !important; }
|
||||
.bg-gray-900 {
|
||||
background: rgb(var(--text-primary-rgb)) !important;
|
||||
box-shadow: 0 2px 8px rgba(var(--overlay-rgb), 0.14) !important;
|
||||
}
|
||||
.dark .bg-gray-900 {
|
||||
background: linear-gradient(180deg, rgba(var(--surface-strong-rgb), 1) 0%, rgba(var(--surface-soft-rgb), 1) 100%) !important;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 12px 28px rgba(0, 0, 0, 0.18) !important;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 12px 28px rgba(var(--overlay-rgb), 0.18) !important;
|
||||
}
|
||||
.border-gray-900 { border-color: rgba(var(--text-body-rgb), 0.42) !important; }
|
||||
.bg-white\/90 { background-color: rgba(var(--surface-rgb), 0.9) !important; }
|
||||
@@ -189,7 +201,8 @@
|
||||
.hover\:bg-gray-50:hover { background-color: rgba(var(--surface-soft-rgb), 0.94) !important; }
|
||||
.hover\:bg-gray-100:hover { background-color: rgba(var(--surface-strong-rgb), 0.94) !important; }
|
||||
.hover\:bg-white:hover { background-color: rgba(var(--surface-rgb), 0.98) !important; }
|
||||
.hover\:bg-black:hover { background-color: rgba(var(--surface-strong-rgb), 1) !important; }
|
||||
.hover\:bg-black:hover { background-color: rgb(var(--text-emphasis-rgb)) !important; }
|
||||
.dark .hover\:bg-black:hover { background-color: rgba(var(--surface-strong-rgb), 1) !important; }
|
||||
.hover\:bg-red-50:hover { background-color: rgba(var(--danger-rgb), 0.12) !important; }
|
||||
.hover\:text-gray-700:hover,
|
||||
.hover\:text-gray-900:hover,
|
||||
@@ -433,11 +446,8 @@
|
||||
background: rgb(var(--card-rgb)) !important;
|
||||
border: 1px solid rgb(var(--border-card-rgb)) !important;
|
||||
box-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),
|
||||
inset 0 2px 6px rgba(0, 0, 0, 0.16),
|
||||
var(--shadow-shell),
|
||||
inset 0 2px 6px rgba(var(--overlay-rgb), 0.16),
|
||||
inset 0 -1px 2px rgba(255, 255, 255, 0.02) !important;
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
@@ -450,7 +460,7 @@
|
||||
bottom: -0.72rem;
|
||||
height: 1.05rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(0, 0, 0, 0.36);
|
||||
background: rgba(var(--overlay-rgb), 0.36);
|
||||
filter: blur(12px);
|
||||
opacity: 0.9;
|
||||
z-index: -1;
|
||||
@@ -460,11 +470,8 @@
|
||||
background: rgb(var(--card-rgb)) !important;
|
||||
border: 1px solid rgba(var(--border-input-rgb), 0.62) !important;
|
||||
box-shadow:
|
||||
0 6px 12px rgba(0, 0, 0, 0.18),
|
||||
0 16px 24px rgba(0, 0, 0, 0.24),
|
||||
0 24px 36px rgba(0, 0, 0, 0.18),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.05),
|
||||
inset 0 2px 7px rgba(0, 0, 0, 0.18),
|
||||
var(--shadow-shell),
|
||||
inset 0 2px 7px rgba(var(--overlay-rgb), 0.18),
|
||||
inset 0 -1px 2px rgba(255, 255, 255, 0.03) !important;
|
||||
}
|
||||
#planner-picker-search {
|
||||
@@ -492,7 +499,7 @@
|
||||
box-shadow: none !important;
|
||||
}
|
||||
#planner-picker-filter-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.03) !important;
|
||||
background: var(--hover-overlay) !important;
|
||||
}
|
||||
#planner-picker-sheet,
|
||||
#planner-ing-sheet,
|
||||
@@ -546,10 +553,8 @@
|
||||
background: rgb(var(--card-rgb));
|
||||
border: 1px solid rgb(var(--border-card-rgb));
|
||||
box-shadow:
|
||||
inset 0 1px 8px rgba(0, 0, 0, 0.15),
|
||||
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 8px rgba(var(--overlay-rgb), 0.15),
|
||||
var(--shadow-shell);
|
||||
pointer-events: auto;
|
||||
}
|
||||
#app-bottom-nav .nav-slot {
|
||||
@@ -592,7 +597,7 @@
|
||||
#app-bottom-nav .nav-action:hover {
|
||||
transform: translateY(-1px);
|
||||
color: rgb(var(--text-primary-rgb));
|
||||
background: rgba(255, 255, 255, 0.04) !important;
|
||||
background: var(--hover-overlay) !important;
|
||||
}
|
||||
#app-bottom-nav .nav-tab.is-active {
|
||||
width: 100%;
|
||||
@@ -609,7 +614,7 @@
|
||||
#app-bottom-nav button:focus-visible {
|
||||
outline: none;
|
||||
box-shadow:
|
||||
0 0 0 3px rgba(255, 255, 255, 0.08),
|
||||
0 0 0 3px var(--hover-overlay),
|
||||
0 0 0 6px rgba(var(--text-body-rgb), 0.26) !important;
|
||||
}
|
||||
@media (max-width: 380px) {
|
||||
|
||||
@@ -152,7 +152,7 @@ function getQtyStepMeta(def, product = null) {
|
||||
export function getIngredientCardHTML({
|
||||
idBase,
|
||||
overlayClass = 'fixed inset-0 z-[70] hidden opacity-0 transition-opacity duration-200 flex items-center justify-center p-5',
|
||||
overlayStyle = 'pointer-events:none; background:rgba(0,0,0,0.5);',
|
||||
overlayStyle = 'pointer-events:none; background:rgba(var(--overlay-rgb),0.5);',
|
||||
cardClass = 'relative w-full max-w-xs rounded-2xl shadow-2xl overflow-hidden',
|
||||
cardStyle = 'background:rgb(var(--app-bg-rgb)); pointer-events:auto; max-height:85vh; overflow-y:auto; transform:translateY(0.75rem); opacity:0; transition:transform 220ms ease, opacity 220ms ease;',
|
||||
} = {}) {
|
||||
|
||||
@@ -45,7 +45,7 @@ export function getMealPlanEditorHTML() {
|
||||
<h2 id="mpe-title" class="text-[15px] font-bold text-gray-900 leading-tight"></h2>
|
||||
<p id="mpe-subtitle" class="text-[11px] text-gray-500 mt-0.5 truncate"></p>
|
||||
</div>
|
||||
<button id="mpe-confirm-btn" type="button" aria-label="Dodaj do planu" class="shrink-0 mt-0.5 border h-8 px-3 rounded-full font-semibold text-[12px] transition-colors inline-flex items-center justify-center gap-1.5" style="background:rgb(var(--text-body-rgb)) !important; color:rgb(var(--app-bg-rgb)) !important; background-image:none !important; border-color:rgb(var(--text-body-rgb)) !important; box-shadow:0 2px 10px rgba(0,0,0,0.18);">
|
||||
<button id="mpe-confirm-btn" type="button" aria-label="Dodaj do planu" class="shrink-0 mt-0.5 border h-8 px-3 rounded-full font-semibold text-[12px] transition-colors inline-flex items-center justify-center gap-1.5" style="background:rgb(var(--text-body-rgb)) !important; color:rgb(var(--app-bg-rgb)) !important; background-image:none !important; border-color:rgb(var(--text-body-rgb)) !important; box-shadow:0 2px 10px rgba(var(--overlay-rgb),0.18);">
|
||||
<i id="mpe-confirm-icon" class="fas fa-plus text-[10px]" aria-hidden="true"></i>
|
||||
<span id="mpe-confirm-label">Dodaj</span>
|
||||
</button>
|
||||
@@ -69,7 +69,7 @@ export function getMealPlanEditorHTML() {
|
||||
<div id="mpe-summary-wrap" class="relative z-[1] shrink-0 px-5 pb-3 bg-[rgb(var(--app-bg-rgb))]" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;">
|
||||
<div id="mpe-nutrition-section"></div>
|
||||
<div id="mpe-servings-row" class="mt-3"></div>
|
||||
<div id="mpe-top-shadow" class="pointer-events-none absolute inset-x-0 -bottom-3 h-3 opacity-0 transition-opacity duration-200" style="background:linear-gradient(to bottom, rgba(0,0,0,0.12), rgba(0,0,0,0.03), rgba(0,0,0,0));"></div>
|
||||
<div id="mpe-top-shadow" class="pointer-events-none absolute inset-x-0 -bottom-3 h-3 opacity-0 transition-opacity duration-200" style="background:linear-gradient(to bottom, rgba(var(--overlay-rgb),0.12), rgba(var(--overlay-rgb),0.03), rgba(var(--overlay-rgb),0));"></div>
|
||||
</div>
|
||||
<div id="mpe-ing-scroll" class="flex-1 min-h-0 overflow-y-auto no-scrollbar px-5 bg-[rgb(var(--app-bg-rgb))]" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important; padding-bottom:calc(1.5rem + env(safe-area-inset-bottom));">
|
||||
<div id="mpe-ing-section" class="mb-4">
|
||||
@@ -245,7 +245,7 @@ export function setupMealPlanEditor() {
|
||||
el.innerHTML = `
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-wider">Porcje</p>
|
||||
<div class="flex h-[2rem] w-[5.25rem] shrink-0 items-center gap-0.5 rounded-full border px-0.5" style="background:rgb(var(--card-soft-rgb));border-color:rgb(var(--card-strong-rgb));box-shadow:0 2px 8px rgba(0,0,0,0.25);">
|
||||
<div class="flex h-[2rem] w-[5.25rem] shrink-0 items-center gap-0.5 rounded-full border px-0.5" style="background:rgb(var(--card-soft-rgb));border-color:rgb(var(--card-strong-rgb));box-shadow:var(--shadow-card);">
|
||||
<button type="button" id="mpe-serv-minus" class="shrink-0 w-7 h-full flex items-center justify-center rounded-full border-0 bg-transparent text-[rgb(var(--text-body-soft-rgb))] transition-colors" aria-label="Zmniejsz liczbę porcji">
|
||||
<i class="fas fa-minus text-[10px]"></i>
|
||||
</button>
|
||||
@@ -269,7 +269,7 @@ export function setupMealPlanEditor() {
|
||||
const removeBtn = (cls, attrs) =>
|
||||
`<button type="button" class="${cls} shrink-0 w-6 h-6 rounded-full border border-gray-200 text-gray-300 hover:text-red-500 hover:border-red-200 hover:bg-red-50 flex items-center justify-center transition-colors" ${attrs}><i class="fas fa-minus text-[8px]"></i></button>`;
|
||||
const ingredientRowClass = 'mpe-ing-row rounded-xl px-3 py-3';
|
||||
const ingredientRowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:0 2px 8px rgba(0,0,0,0.25) !important; border:none !important;';
|
||||
const ingredientRowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:var(--shadow-card) !important; border:none !important;';
|
||||
|
||||
for (const ing of r.ingredients) {
|
||||
const id = ing.ingredientId;
|
||||
|
||||
@@ -33,7 +33,7 @@ function renderRecipeCard(recipe, { showSlotLabels = true, cardClassName = '' }
|
||||
const className = ['recipe-browser-card', cardClassName].filter(Boolean).join(' ');
|
||||
|
||||
return `
|
||||
<button type="button" data-recipe-id="${escapeHtml(recipe.id)}" class="${className} rounded-xl overflow-hidden flex flex-col bg-[rgb(var(--card-rgb))] cursor-pointer text-left transition-shadow" style="background:rgb(var(--card-rgb)) !important; border:none !important; box-shadow:0 2px 8px rgba(0,0,0,0.28) !important;">
|
||||
<button type="button" data-recipe-id="${escapeHtml(recipe.id)}" class="${className} rounded-xl overflow-hidden flex flex-col bg-[rgb(var(--card-rgb))] cursor-pointer text-left transition-shadow" style="background:rgb(var(--card-rgb)) !important; border:none !important; box-shadow:var(--shadow-card) !important;">
|
||||
<div class="recipe-browser-card-media h-32 bg-[rgb(var(--skeleton-rgb))] relative overflow-hidden">
|
||||
${recipe.image
|
||||
? `<img src="${escapeHtml(recipe.image)}" alt="${escapeHtml(recipe.title)}" class="w-full h-full object-cover">`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const RECIPE_SEARCH_SHELL_BASE_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), inset 0 2px 6px rgba(0,0,0,0.16), inset 0 -1px 2px rgba(255,255,255,0.02)';
|
||||
'var(--shadow-shell), inset 0 2px 6px rgba(var(--overlay-rgb),0.16), inset 0 -1px 2px rgba(255,255,255,0.02)';
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s)
|
||||
|
||||
@@ -12,7 +12,6 @@ const FILTER_TEXT_MUTED = 'rgb(var(--text-muted-rgb))';
|
||||
const FILTER_TEXT_ACTIVE = 'rgb(var(--text-emphasis-rgb))';
|
||||
const FILTER_TRACK = 'rgb(var(--card-rgb))';
|
||||
const FILTER_TRACK_FILL = 'rgba(var(--border-input-rgb), 0.58)';
|
||||
const FILTER_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)';
|
||||
const PREP_TIME_MIN = 5;
|
||||
const PREP_TIME_MAX = 120;
|
||||
const PREP_TIME_STEP = 5;
|
||||
@@ -74,13 +73,13 @@ export function getFilterHTML() {
|
||||
border-radius: 9999px;
|
||||
border: 1px solid rgba(var(--text-emphasis-rgb),0.16);
|
||||
background: ${FILTER_TRACK_FILL};
|
||||
box-shadow: 0 0 0 1px rgba(0,0,0,0.12);
|
||||
box-shadow: 0 0 0 1px rgba(var(--overlay-rgb),0.12);
|
||||
touch-action: none;
|
||||
outline: none;
|
||||
}
|
||||
</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="background:${FILTER_SURFACE} !important; background-image:none !important; border:1px solid ${FILTER_BORDER} !important; opacity:0; transform:translateY(-0.5rem) scale(0.98); transform-origin:top center; transition:${FILTER_PANEL_TRANSITION}; box-shadow:${FILTER_SHADOW}; width:min(calc(100% - 1.5rem), 22rem);">
|
||||
<div id="filter-panel" class="absolute flex flex-col overflow-hidden rounded-[1.35rem]" style="background:${FILTER_SURFACE} !important; background-image:none !important; border:1px solid ${FILTER_BORDER} !important; opacity:0; transform:translateY(-0.5rem) scale(0.98); transform-origin:top center; transition:${FILTER_PANEL_TRANSITION}; box-shadow:var(--shadow-shell); 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>
|
||||
@@ -180,7 +179,7 @@ function getChipStyle(active) {
|
||||
const color = active ? FILTER_TEXT_ACTIVE : FILTER_TEXT_SECONDARY;
|
||||
const borderRule = active ? `border:1px solid ${FILTER_BORDER};` : 'border:none;';
|
||||
const shadow = active
|
||||
? 'box-shadow:inset 0 1px 0 rgba(255,255,255,0.04), 0 0 0 1px rgba(0,0,0,0.08);'
|
||||
? 'box-shadow:inset 0 1px 0 rgba(255,255,255,0.04), 0 0 0 1px rgba(var(--overlay-rgb),0.08);'
|
||||
: '';
|
||||
return `background:${background}; ${borderRule} color:${color}; ${shadow}`;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ export function getMealPlannerHTML() {
|
||||
</div>
|
||||
|
||||
<div id="planner-ing-backdrop" class="absolute inset-0 z-[55] bg-black/45 hidden opacity-0 transition-opacity duration-200" aria-hidden="true"></div>
|
||||
<div id="planner-ing-sheet" class="absolute left-0 right-0 bottom-0 z-[60] rounded-t-3xl shadow-[0_-10px_40px_rgba(0,0,0,0.12)] flex flex-col will-change-transform" style="visibility: hidden; height: auto; max-height: calc(100vh - env(safe-area-inset-top) - 1rem); transform: ${PLANNER_SHEET_OFF_TRANSFORM}; transition: transform 300ms cubic-bezier(0.32, 0.72, 0, 1); background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;" role="dialog" aria-labelledby="planner-ing-title" aria-modal="true">
|
||||
<div id="planner-ing-sheet" class="absolute left-0 right-0 bottom-0 z-[60] rounded-t-3xl shadow-[0_-10px_40px_rgba(var(--overlay-rgb),0.12)] flex flex-col will-change-transform" style="visibility: hidden; height: auto; max-height: calc(100vh - env(safe-area-inset-top) - 1rem); transform: ${PLANNER_SHEET_OFF_TRANSFORM}; transition: transform 300ms cubic-bezier(0.32, 0.72, 0, 1); background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;" role="dialog" aria-labelledby="planner-ing-title" aria-modal="true">
|
||||
<div class="shrink-0 px-4 pt-3 pb-2 border-b border-[rgb(var(--card-strong-rgb))] touch-none cursor-grab active:cursor-grabbing select-none" data-planner-sheet-drag-zone aria-label="Przeciągnij w dół, by zamknąć">
|
||||
<div class="w-10 h-1 bg-[rgb(var(--text-subdued-rgb))]/75 rounded-full mx-auto mb-2.5" aria-hidden="true"></div>
|
||||
<h2 id="planner-ing-title" class="text-[15px] font-bold text-[rgb(var(--text-body-rgb))] leading-tight pr-2">Składniki i spiżarnia</h2>
|
||||
@@ -501,7 +501,7 @@ function renderDayContent(state, onMealRemoved = null) {
|
||||
: 0;
|
||||
const entryAction = isPendingDelete
|
||||
? `<button type="button" class="planner-cancel-pending-remove rounded-full p-[1.5px] transition-transform hover:scale-[1.02] active:scale-[0.98]" style="background:${getPendingMealRemovalButtonStyle(remainingProgress)};" data-pending-delete-progress data-day-key="${selectedDayKey}" data-slot-id="${slot.id}" data-entry-id="${eid}" aria-label="Anuluj usunięcie posiłku">
|
||||
<span class="flex h-7 w-7 items-center justify-center rounded-full bg-[rgb(var(--card-raised-rgb))] text-[rgb(var(--text-body-rgb))] shadow-[0_1px_2px_rgba(0,0,0,0.28)]">
|
||||
<span class="flex h-7 w-7 items-center justify-center rounded-full bg-[rgb(var(--card-raised-rgb))] text-[rgb(var(--text-body-rgb))] shadow-[0_1px_2px_rgba(var(--overlay-rgb),0.28)]">
|
||||
<i class="fas fa-rotate-left text-[10px]" aria-hidden="true"></i>
|
||||
</span>
|
||||
</button>`
|
||||
@@ -513,7 +513,7 @@ function renderDayContent(state, onMealRemoved = null) {
|
||||
<div class="pointer-events-none absolute inset-0 flex items-center justify-end px-4" style="${backgroundStyle}">
|
||||
${backgroundLabel}
|
||||
</div>
|
||||
<div class="relative z-[1] rounded-lg p-2 planner-open-recipe cursor-pointer" style="background:${isPendingDelete ? 'rgba(var(--app-bg-rgb),0.76)' : 'rgb(var(--app-bg-rgb))'}; box-shadow:inset 0 1px 3px rgba(0,0,0,0.3); transform:${isPendingDelete ? 'translateX(0) scale(0.988)' : 'translateX(0)'}; transition:transform 180ms cubic-bezier(0.22, 1, 0.36, 1), opacity 180ms ease, background-color 180ms ease; touch-action:pan-y; opacity:1;" data-planner-swipe-card data-slot-id="${slot.id}" data-entry-id="${eid}" data-recipe-id="${escapeHtml(recipe.id)}">
|
||||
<div class="relative z-[1] rounded-lg p-2 planner-open-recipe cursor-pointer" style="background:${isPendingDelete ? 'rgba(var(--app-bg-rgb),0.76)' : 'rgb(var(--app-bg-rgb))'}; box-shadow:inset 0 1px 3px rgba(var(--overlay-rgb),0.3); transform:${isPendingDelete ? 'translateX(0) scale(0.988)' : 'translateX(0)'}; transition:transform 180ms cubic-bezier(0.22, 1, 0.36, 1), opacity 180ms ease, background-color 180ms ease; touch-action:pan-y; opacity:1;" data-planner-swipe-card data-slot-id="${slot.id}" data-entry-id="${eid}" data-recipe-id="${escapeHtml(recipe.id)}">
|
||||
<div class="relative flex items-start justify-between gap-2">
|
||||
<div class="flex items-center gap-2 min-w-0" style="${contentToneStyle}">
|
||||
<div class="w-8 h-8 rounded-lg bg-[rgb(var(--card-raised-rgb))] overflow-hidden shrink-0">
|
||||
@@ -545,7 +545,7 @@ function renderDayContent(state, onMealRemoved = null) {
|
||||
: '';
|
||||
|
||||
const filledCard = `
|
||||
<div class="rounded-xl bg-[rgb(var(--card-rgb))] overflow-hidden" style="background:rgb(var(--card-rgb)) !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}">
|
||||
<div class="rounded-xl bg-[rgb(var(--card-rgb))] overflow-hidden" style="background:rgb(var(--card-rgb)) !important; box-shadow:var(--shadow-card);" data-slot-id="${slot.id}">
|
||||
<div class="flex items-center gap-2 px-3 py-2.5 bg-[rgb(var(--card-rgb))]" style="background:rgb(var(--card-rgb)) !important;">
|
||||
<i class="fas ${slot.icon} w-7 text-center text-[13px] text-[rgb(var(--text-dim-rgb))] shrink-0" aria-hidden="true"></i>
|
||||
<span class="text-[13px] font-semibold text-[rgb(var(--text-body-rgb))] truncate min-w-0">${slot.label}</span>
|
||||
@@ -559,7 +559,7 @@ function renderDayContent(state, onMealRemoved = null) {
|
||||
if (entries.length > 0) return filledCard;
|
||||
|
||||
return `
|
||||
<div class="rounded-xl bg-[rgb(var(--card-rgb))] overflow-hidden" style="background:rgb(var(--card-rgb)) !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}">
|
||||
<div class="rounded-xl bg-[rgb(var(--card-rgb))] overflow-hidden" style="background:rgb(var(--card-rgb)) !important; box-shadow:var(--shadow-card);" data-slot-id="${slot.id}">
|
||||
<div class="flex items-center gap-2 px-3 py-2.5">
|
||||
<i class="fas ${slot.icon} w-7 text-center text-[13px] text-[rgb(var(--text-dim-rgb))] shrink-0" aria-hidden="true"></i>
|
||||
<span class="text-[13px] font-semibold text-[rgb(var(--text-body-rgb))] truncate min-w-0">${slot.label}</span>
|
||||
@@ -1157,7 +1157,7 @@ export function setupMealPlanner() {
|
||||
const calBar = document.getElementById('planner-cal-bar');
|
||||
if (plannerScroll && calBar) {
|
||||
const shadow = document.createElement('div');
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(0,0,0,0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(var(--overlay-rgb),0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
calBar.appendChild(shadow);
|
||||
plannerScroll.addEventListener('scroll', () => {
|
||||
shadow.style.opacity = plannerScroll.scrollTop > 2 ? '1' : '0';
|
||||
|
||||
@@ -53,7 +53,7 @@ function filterChipStyle(active) {
|
||||
const color = active ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))';
|
||||
const borderRule = active ? 'border:1px solid rgb(var(--border-input-rgb));' : 'border:none;';
|
||||
const shadow = active
|
||||
? 'box-shadow:inset 0 1px 0 rgba(255,255,255,0.04), 0 0 0 1px rgba(0,0,0,0.08);'
|
||||
? 'box-shadow:inset 0 1px 0 rgba(255,255,255,0.04), 0 0 0 1px rgba(var(--overlay-rgb),0.08);'
|
||||
: '';
|
||||
return `background:${background}; ${borderRule} color:${color}; ${shadow}`;
|
||||
}
|
||||
@@ -78,7 +78,6 @@ const PANTRY_SECTION_FILTERS = [
|
||||
const DAY_NAMES_SHORT = ['nd.', 'pon.', 'wt.', 'śr.', 'czw.', 'pt.', 'sob.'];
|
||||
const MONTHS_SHORT = ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'];
|
||||
|
||||
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)';
|
||||
const DEFAULT_HORIZON_DAYS = 7;
|
||||
const PANTRY_CALENDAR_DAY_ATTR = 'data-pantry-calendar-day';
|
||||
const SHORTFALL_ACCENT = 'rgb(var(--danger-rgb))';
|
||||
@@ -162,8 +161,8 @@ function photoStripMedia(image, icon, accentBg) {
|
||||
<img src="${esc(image)}" alt="" class="absolute inset-0 w-full h-full object-cover">
|
||||
</div>`;
|
||||
}
|
||||
return `<div class="w-[4.5rem] shrink-0 flex items-center justify-center self-stretch" style="background:rgb(var(--card-raised-rgb));">
|
||||
<i class="fas ${icon} text-[22px]" style="color:rgba(255,255,255,0.10);"></i>
|
||||
return `<div class="w-[4.5rem] shrink-0 flex items-center justify-center self-stretch" style="background:rgb(var(--card-soft-rgb));">
|
||||
<i class="fas ${icon} text-[22px]" style="color:var(--icon-watermark);"></i>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -181,19 +180,19 @@ export function getPantryHTML() {
|
||||
<h1 class="flex-1 min-w-0 truncate" style="margin:0;padding:0;color:rgb(var(--text-emphasis-rgb));font-family:var(--app-font);font-size:18px;font-weight:700;line-height:1.2;letter-spacing:-0.02em;">Zapasy</h1>
|
||||
|
||||
<div id="pantry-horizon-wrap" class="relative shrink">
|
||||
<button type="button" id="pantry-horizon-compact" class="min-w-0 max-w-[12rem] h-10 rounded-full flex items-center gap-1.5 px-2.5 transition-all" style="background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important;">
|
||||
<button type="button" id="pantry-horizon-compact" class="min-w-0 max-w-[12rem] h-10 rounded-full flex items-center gap-1.5 px-2.5 transition-all" style="background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:var(--shadow-shell) !important;">
|
||||
<span id="pantry-horizon-compact-label" class="min-w-0 flex-1 text-left text-[13px] font-normal truncate" style="color:rgb(var(--text-body-rgb));"></span>
|
||||
<i id="pantry-horizon-chevron" class="fas fa-chevron-down text-[10px] shrink-0 transition-transform duration-200" style="color:rgb(var(--text-dim-rgb));"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="pantry-filter-wrap" class="relative shrink-0">
|
||||
<button type="button" id="pantry-filter-toggle" class="relative w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:${SEARCH_SHELL_SHADOW}; color:rgb(var(--text-body-rgb));">
|
||||
<button type="button" id="pantry-filter-toggle" class="relative w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:var(--shadow-shell); color:rgb(var(--text-body-rgb));">
|
||||
<i class="fas fa-sliders-h text-[12px]"></i>
|
||||
<span id="pantry-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:rgb(var(--sunken-rgb)); border:1px solid rgb(var(--border-input-rgb)); color:rgb(var(--text-emphasis-rgb));"></span>
|
||||
</button>
|
||||
|
||||
<div id="pantry-filter-popover" class="absolute right-0 top-full mt-2 w-[19rem] max-w-[calc(100vw-2rem)] rounded-[1.35rem] px-3 py-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; opacity:0; transform:translateY(-6px) scale(0.98);">
|
||||
<div id="pantry-filter-popover" class="absolute right-0 top-full mt-2 w-[19rem] max-w-[calc(100vw-2rem)] rounded-[1.35rem] px-3 py-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:var(--shadow-shell) !important; opacity:0; transform:translateY(-6px) scale(0.98);">
|
||||
<div class="flex items-center justify-between gap-3 px-0.5 pb-3">
|
||||
<p class="text-[11px] font-semibold leading-none" style="color:rgb(var(--text-emphasis-rgb));">Filtry</p>
|
||||
<button type="button" id="pantry-filter-clear" class="h-8 px-2 rounded-full text-[11px] font-semibold transition-colors" style="background:transparent; border:none; color:rgb(var(--text-muted-rgb));">
|
||||
@@ -204,13 +203,13 @@ export function getPantryHTML() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="pantry-search-toggle" class="w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; color:rgb(var(--text-body-rgb));">
|
||||
<button type="button" id="pantry-search-toggle" class="w-11 h-11 rounded-full shrink-0 flex items-center justify-center transition-all duration-200" style="background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:var(--shadow-shell) !important; color:rgb(var(--text-body-rgb));">
|
||||
<i class="fas fa-search text-[13px]"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="pantry-calendar-popover" class="absolute left-0 right-0 top-full mt-2 rounded-[1.35rem] px-3 py-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; opacity:0; transform:translateY(-6px) scale(0.98);">
|
||||
<div id="pantry-calendar-popover" class="absolute left-0 right-0 top-full mt-2 rounded-[1.35rem] px-3 py-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:var(--shadow-shell) !important; opacity:0; transform:translateY(-6px) scale(0.98);">
|
||||
${createCalendarTopbarHTML({
|
||||
prevId: 'pantry-cal-prev',
|
||||
todayId: 'pantry-cal-today',
|
||||
@@ -231,7 +230,7 @@ export function getPantryHTML() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pantry-search-shell" class="absolute inset-0 flex items-center gap-2 rounded-full px-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; opacity:0; transform:translateY(-2px) scale(0.98);">
|
||||
<div id="pantry-search-shell" class="absolute inset-0 flex items-center gap-2 rounded-full px-3 transition-all duration-200 pointer-events-none" style="background:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:var(--shadow-shell) !important; opacity:0; transform:translateY(-2px) scale(0.98);">
|
||||
<i class="fas fa-search text-[13px] shrink-0" style="color:rgb(var(--text-dim-rgb));"></i>
|
||||
<input type="search" id="pantry-search" autocomplete="off" placeholder="Szukaj w spiżarni…"
|
||||
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:rgb(var(--text-body-rgb)); margin:0;">
|
||||
@@ -562,7 +561,7 @@ function tileIconHtml(item) {
|
||||
function shortfallTileHtml(item) {
|
||||
const clamp = item.name.length > 25 ? ' min-w-0' : '';
|
||||
return `
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex flex-col gap-2 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex flex-col gap-2 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:var(--shadow-card);" data-id="${esc(item.ingredientId)}">
|
||||
<div class="flex items-center gap-1.5 min-w-0">
|
||||
${tileIconHtml(item)}
|
||||
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:rgb(var(--text-body-rgb));">${esc(item.name)}</p>
|
||||
@@ -579,7 +578,7 @@ function shortfallTileHtml(item) {
|
||||
function sufficientTileHtml(item) {
|
||||
const clamp = item.name.length > 25 ? ' min-w-0' : '';
|
||||
return `
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex flex-col gap-2 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex flex-col gap-2 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:var(--shadow-card);" data-id="${esc(item.ingredientId)}">
|
||||
<div class="flex items-center gap-1.5 min-w-0">
|
||||
${tileIconHtml(item)}
|
||||
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:rgb(var(--text-body-rgb));">${esc(item.name)}</p>
|
||||
@@ -597,7 +596,7 @@ function notPlannedChipHtml(item) {
|
||||
const hasStock = item.qty > 0;
|
||||
const clamp = item.name.length > 25 ? ' min-w-0' : '';
|
||||
return `
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex items-center gap-1.5 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
|
||||
<button type="button" class="pv2-tile text-left rounded-2xl flex items-center gap-1.5 px-2.5 py-2${clamp} transition-all active:scale-[0.98]" style="flex:1 0 auto; min-width:6rem; max-width:100%; background:rgb(var(--card-rgb)); border:none; box-shadow:var(--shadow-card);" data-id="${esc(item.ingredientId)}">
|
||||
${tileIconHtml(item)}
|
||||
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:${hasStock ? 'rgb(var(--text-muted-rgb))' : 'rgb(var(--text-dim-rgb))'};">${esc(item.name)}</p>
|
||||
<span class="text-[10px] font-semibold tabular-nums shrink-0 ml-auto" style="color:${hasStock ? 'rgb(var(--text-dim-rgb))' : 'rgb(var(--text-subdued-rgb))'};">${esc(formatQty(item.qty))} ${esc(unitLabel(item.unit))}</span>
|
||||
@@ -710,7 +709,7 @@ export function setupPantry() {
|
||||
const topbarOuter = document.getElementById('pantry-topbar-outer');
|
||||
if (pantryScroll && topbarOuter) {
|
||||
const shadow = document.createElement('div');
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(0,0,0,0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(var(--overlay-rgb),0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
topbarOuter.appendChild(shadow);
|
||||
pantryScroll.addEventListener('scroll', () => {
|
||||
shadow.style.opacity = pantryScroll.scrollTop > 2 ? '1' : '0';
|
||||
|
||||
@@ -33,10 +33,10 @@ export function getRecipeDetailHTML() {
|
||||
return `
|
||||
<div id="recipe-detail-view" class="absolute inset-0 bg-[rgb(var(--app-bg-rgb))] z-30 transition-all duration-300 ease-in-out translate-x-full opacity-0 pointer-events-none overflow-hidden" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;">
|
||||
<div class="absolute top-0 w-full p-3.5 flex justify-between z-40 mt-3">
|
||||
<button id="rd-back-btn" onclick="closeRecipeDetail()" class="w-9 h-9 rounded-full flex items-center justify-center transition-opacity opacity-95 hover:opacity-100" style="background:rgba(var(--card-rgb),0.93) !important; backdrop-filter:none !important; box-shadow:0 4px 9px rgba(0,0,0,0.33) !important; color:rgb(var(--text-body-rgb)) !important; transition:box-shadow 180ms ease, background-color 180ms ease, opacity 180ms ease;">
|
||||
<button id="rd-back-btn" onclick="closeRecipeDetail()" class="w-9 h-9 rounded-full flex items-center justify-center transition-opacity opacity-95 hover:opacity-100" style="background:rgba(var(--card-rgb),0.93) !important; backdrop-filter:none !important; box-shadow:0 4px 9px rgba(var(--overlay-rgb),0.33) !important; color:rgb(var(--text-body-rgb)) !important; transition:box-shadow 180ms ease, background-color 180ms ease, opacity 180ms ease;">
|
||||
<i class="fas fa-arrow-left text-[13px]"></i>
|
||||
</button>
|
||||
<button id="rd-add-to-planner-btn" class="h-9 px-3 rounded-full flex items-center justify-center gap-1.5 transition-opacity opacity-95 hover:opacity-100 text-[12px] font-semibold" style="background:rgba(var(--card-rgb),0.93) !important; backdrop-filter:none !important; box-shadow:0 3px 8px rgba(0,0,0,0.28) !important; color:rgb(var(--text-body-rgb)) !important; transition:box-shadow 180ms ease, background-color 180ms ease, opacity 180ms ease;">
|
||||
<button id="rd-add-to-planner-btn" class="h-9 px-3 rounded-full flex items-center justify-center gap-1.5 transition-opacity opacity-95 hover:opacity-100 text-[12px] font-semibold" style="background:rgba(var(--card-rgb),0.93) !important; backdrop-filter:none !important; box-shadow:0 3px 8px rgba(var(--overlay-rgb),0.28) !important; color:rgb(var(--text-body-rgb)) !important; transition:box-shadow 180ms ease, background-color 180ms ease, opacity 180ms ease;">
|
||||
<i class="fas fa-calendar-plus text-[11px]"></i> Zaplanuj
|
||||
</button>
|
||||
</div>
|
||||
@@ -48,7 +48,7 @@ export function getRecipeDetailHTML() {
|
||||
<span id="rd-hero-label" class="absolute inset-0 z-10 flex items-center justify-center font-medium text-[15px]" style="color:rgb(var(--text-body-rgb));"></span>
|
||||
</div>
|
||||
|
||||
<div id="rd-content-body" class="bg-[rgb(var(--app-bg-rgb))] rounded-t-3xl -mt-6 relative z-30 pt-6 min-h-screen" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important; box-shadow:0 -8px 20px rgba(0,0,0,0.35) !important;">
|
||||
<div id="rd-content-body" class="bg-[rgb(var(--app-bg-rgb))] rounded-t-3xl -mt-6 relative z-30 pt-6 min-h-screen" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important; box-shadow:0 -8px 20px rgba(var(--overlay-rgb),0.35) !important;">
|
||||
<div class="mb-3 px-5">
|
||||
<div class="flex justify-between items-start mb-2.5">
|
||||
<h1 id="rd-title" class="text-xl font-bold leading-tight" style="color:rgb(var(--text-body-rgb));"></h1>
|
||||
@@ -258,7 +258,7 @@ function renderNutritionSummary(recipe) {
|
||||
: `
|
||||
<div class="mt-3 flex items-center justify-between gap-3">
|
||||
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-wider">Porcje</p>
|
||||
<div class="flex h-[2rem] w-[5.25rem] shrink-0 items-center gap-0.5 rounded-full border px-0.5" style="background:rgb(var(--card-soft-rgb));border-color:rgb(var(--card-strong-rgb));box-shadow:0 2px 8px rgba(0,0,0,0.25);">
|
||||
<div class="flex h-[2rem] w-[5.25rem] shrink-0 items-center gap-0.5 rounded-full border px-0.5" style="background:rgb(var(--card-soft-rgb));border-color:rgb(var(--card-strong-rgb));box-shadow:var(--shadow-card);">
|
||||
<button type="button" id="rd-serv-minus" class="shrink-0 w-7 h-full flex items-center justify-center rounded-full border-0 bg-transparent text-[rgb(var(--text-body-soft-rgb))] transition-colors" aria-label="Zmniejsz liczbę porcji">
|
||||
<i class="fas fa-minus text-[10px]"></i>
|
||||
</button>
|
||||
@@ -306,7 +306,7 @@ function renderIngredients(recipe) {
|
||||
const items = buildVisibleIngredients(recipe);
|
||||
const rows = items.map((item) => {
|
||||
const rowClass = 'rd-ing-row rounded-xl px-3 py-3 w-full text-left cursor-pointer transition-colors active:scale-[0.99]';
|
||||
const rowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:0 2px 8px rgba(0,0,0,0.25) !important; border:none !important;';
|
||||
const rowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:var(--shadow-card) !important; border:none !important;';
|
||||
const productBadge = item.productName
|
||||
? `<div class="flex items-center gap-1 mt-0.5"><span class="text-[10px] text-emerald-400 truncate">${escapeHtml(item.productName)}</span></div>`
|
||||
: '';
|
||||
@@ -364,7 +364,7 @@ function renderIngredients(recipe) {
|
||||
const scaledAmount = ing.amount * currentServings;
|
||||
const isExpanded = expandedAlternatives.has(origId);
|
||||
const rowClass = 'rd-ing-row rounded-xl px-3 py-3';
|
||||
const rowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:0 2px 8px rgba(0,0,0,0.25) !important; border:none !important;';
|
||||
const rowStyle = 'background:rgb(var(--card-rgb)) !important; background-image:none !important; box-shadow:var(--shadow-card) !important; border:none !important;';
|
||||
|
||||
const toggleBtn = hasAlts
|
||||
? `<button type="button" class="rd-alt-toggle shrink-0 w-5 h-5 flex items-center justify-center transition-colors text-gray-400 hover:text-gray-300" style="background:transparent !important; box-shadow:none !important;" data-original-id="${escapeHtml(origId)}" aria-label="Wybierz zamiennik składnika"><i class="fas fa-shuffle text-[10px]"></i></button>`
|
||||
@@ -506,7 +506,7 @@ export function setupRecipeDetail() {
|
||||
const effectiveShadowY = isRoundButton ? shadowY + 1 : shadowY;
|
||||
const effectiveShadowBlur = isRoundButton ? shadowBlur + 1 : shadowBlur;
|
||||
const effectiveShadowAlpha = isRoundButton ? shadowAlpha + 0.05 : shadowAlpha;
|
||||
button.style.boxShadow = `0 ${effectiveShadowY}px ${effectiveShadowBlur}px rgba(0,0,0,${effectiveShadowAlpha})`;
|
||||
button.style.boxShadow = `0 ${effectiveShadowY}px ${effectiveShadowBlur}px rgba(var(--overlay-rgb),${effectiveShadowAlpha})`;
|
||||
button.style.background = `rgba(var(--card-rgb),${backgroundAlpha})`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ import { getRecipeGridSectionHTML, renderRecipeGrid } from '../ui/recipeGrid.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: [],
|
||||
@@ -49,7 +46,7 @@ function getFilteredRecipes() {
|
||||
function syncRecipeScrollShadow() {
|
||||
const searchShell = document.getElementById('recipe-search-shell');
|
||||
if (searchShell) {
|
||||
searchShell.style.boxShadow = SEARCH_SHELL_SHADOW;
|
||||
searchShell.style.boxShadow = 'var(--shadow-shell)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +66,7 @@ function syncRecipeTopbarUI() {
|
||||
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;
|
||||
searchShell.style.boxShadow = 'var(--shadow-shell)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,18 +119,18 @@ export function getRecipeListHTML() {
|
||||
<h1 class="min-w-0 flex-1 truncate" style="margin:0;padding:0;color:rgb(var(--text-emphasis-rgb));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:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:${SEARCH_SHELL_SHADOW}; color:rgb(var(--text-body-rgb));" aria-label="Otwórz filtry">
|
||||
<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:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:var(--shadow-shell); color:rgb(var(--text-body-rgb));" 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:rgb(var(--sunken-rgb)); border:1px solid rgb(var(--border-input-rgb)); color:rgb(var(--text-emphasis-rgb));"></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:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; color:rgb(var(--text-body-rgb));" aria-label="Szukaj">
|
||||
<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:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; box-shadow:var(--shadow-shell) !important; color:rgb(var(--text-body-rgb));" 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:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:${SEARCH_SHELL_SHADOW} !important; opacity:0; transform:translateY(-2px) scale(0.98);">
|
||||
<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:rgb(var(--sunken-rgb)) !important; border:1px solid rgb(var(--border-input-rgb)) !important; box-shadow:var(--shadow-shell) !important; opacity:0; transform:translateY(-2px) scale(0.98);">
|
||||
<i class="fas fa-search text-[13px] shrink-0" style="color:rgb(var(--text-dim-rgb));"></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:rgb(var(--text-body-rgb)); margin:0;">
|
||||
@@ -209,7 +206,7 @@ export function setupRecipeList() {
|
||||
const recipeTopBar = document.getElementById('recipe-top-bar');
|
||||
if (recipeScroll && recipeTopBar) {
|
||||
const shadow = document.createElement('div');
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(0,0,0,0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
shadow.style.cssText = 'position:absolute;left:0;right:0;bottom:-8px;height:8px;background:linear-gradient(to bottom,rgba(var(--overlay-rgb),0.25),transparent);opacity:0;transition:opacity 0.2s;pointer-events:none;';
|
||||
recipeTopBar.appendChild(shadow);
|
||||
recipeScroll.addEventListener('scroll', () => {
|
||||
shadow.style.opacity = recipeScroll.scrollTop > 2 ? '1' : '0';
|
||||
|
||||
@@ -36,7 +36,6 @@ function stepForUnit(unit) {
|
||||
return (unit === 'szt.' || unit === 'szt') ? 1 : 10;
|
||||
}
|
||||
|
||||
const SL_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)';
|
||||
|
||||
const CATEGORY_ICONS = {
|
||||
pieczywo: 'fa-bread-slice',
|
||||
@@ -126,14 +125,14 @@ export function getShoppingListHTML() {
|
||||
<!-- title row + pill (position:relative anchors the popup) -->
|
||||
<div class="flex items-center gap-2 mb-3" style="position:relative;">
|
||||
<h1 class="flex-1 text-[18px] font-bold" style="color:rgb(var(--text-emphasis-rgb));">Lista zakupów</h1>
|
||||
<button type="button" id="sl-range-pill" class="min-w-0 max-w-[10rem] h-10 rounded-full flex items-center gap-1.5 px-2.5 transition-all shrink" style="background:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:${SL_SHADOW};">
|
||||
<button type="button" id="sl-range-pill" class="min-w-0 max-w-[10rem] h-10 rounded-full flex items-center gap-1.5 px-2.5 transition-all shrink" style="background:rgb(var(--card-rgb)); border:1px solid rgb(var(--border-card-rgb)); box-shadow:var(--shadow-shell);">
|
||||
<span id="sl-range-label" class="min-w-0 flex-1 text-left text-[13px] font-normal truncate" style="color:rgb(var(--text-body-rgb));"></span>
|
||||
<i id="sl-range-chevron" class="fas fa-chevron-down text-[10px] shrink-0 transition-transform duration-200" style="color:rgb(var(--text-dim-rgb));"></i>
|
||||
</button>
|
||||
|
||||
<!-- popup calendar (absolute, overlays content below) -->
|
||||
<div id="sl-calendar-popup" style="position:absolute; top:calc(100% + 0.5rem); left:0; right:0; z-index:50; pointer-events:none; opacity:0; transform:translateY(-6px) scale(0.98); transition: opacity 0.2s ease, transform 0.2s ease;">
|
||||
<div class="rounded-[1.35rem] px-3 py-3" style="background:rgb(var(--sunken-rgb)); border:1px solid rgb(var(--border-input-rgb)); box-shadow:${SL_SHADOW};">
|
||||
<div class="rounded-[1.35rem] px-3 py-3" style="background:rgb(var(--sunken-rgb)); border:1px solid rgb(var(--border-input-rgb)); box-shadow:var(--shadow-shell);">
|
||||
<!-- month nav topbar -->
|
||||
<div class="pb-3 flex items-center justify-end gap-3">
|
||||
<div class="flex h-[2.05rem] min-w-0 max-w-[min(100%,20rem)] items-center gap-px rounded-full border px-0.5" style="background:rgb(var(--app-bg-rgb)); border-color:rgb(var(--card-raised-rgb));">
|
||||
@@ -358,7 +357,7 @@ function activeItemHtml(item) {
|
||||
const stepAmt = isExpanded ? expandedAmount : Math.max(step, Math.round(item.shortfall / step) * step);
|
||||
|
||||
return `
|
||||
<div class="sl-swipe-wrap relative rounded-xl mb-1.5 overflow-hidden" style="background:rgb(var(--success-rgb)); box-shadow:0 2px 8px rgba(0,0,0,0.28);">
|
||||
<div class="sl-swipe-wrap relative rounded-xl mb-1.5 overflow-hidden" style="background:rgb(var(--success-rgb)); box-shadow:var(--shadow-card);">
|
||||
<div class="sl-swipe-bg-buy absolute inset-0 flex items-center pr-5 justify-end">
|
||||
<i class="fas fa-check text-white text-lg"></i>
|
||||
</div>
|
||||
@@ -402,7 +401,7 @@ function boughtItemHtml(entry) {
|
||||
: `<div class="w-8 h-8 rounded-lg flex items-center justify-center shrink-0 opacity-50" style="background:rgb(var(--card-soft-rgb));"><i class="fas ${icon} text-xs" style="color:rgb(var(--text-faint-rgb));"></i></div>`;
|
||||
|
||||
return `
|
||||
<div class="sl-swipe-wrap relative rounded-xl mb-1.5 overflow-hidden" style="background:rgb(var(--danger-rgb)); box-shadow:0 2px 8px rgba(0,0,0,0.28);">
|
||||
<div class="sl-swipe-wrap relative rounded-xl mb-1.5 overflow-hidden" style="background:rgb(var(--danger-rgb)); box-shadow:var(--shadow-card);">
|
||||
<div class="sl-swipe-bg-undo absolute inset-0 flex items-center pl-5 justify-start">
|
||||
<i class="fas fa-rotate-left text-white text-lg"></i>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user