From ded24b53b4840d4c7ee7d558762f19d95c7ba13e Mon Sep 17 00:00:00 2001 From: ulfrxdev Date: Wed, 22 Apr 2026 21:57:23 +0200 Subject: [PATCH] Design changes to pantry --- js/ui/bottomNav.js | 1 + js/ui/calendarPopover.js | 101 ++++++++++++++++++++++++++++++++++++++- js/ui/filterPopover.js | 8 ++++ js/ui/ingredientCard.js | 61 ++++++++++++----------- js/views/Pantry.js | 47 ++++++------------ js/views/ShoppingList.js | 2 +- 6 files changed, 158 insertions(+), 62 deletions(-) diff --git a/js/ui/bottomNav.js b/js/ui/bottomNav.js index b5fb348..4f3c6ba 100644 --- a/js/ui/bottomNav.js +++ b/js/ui/bottomNav.js @@ -81,6 +81,7 @@ export function setupBottomNav({ refreshPantry, refreshShoppingList } = {}) { nav.style.setProperty('--recipe-dock-width', `${dockWidth}px`); nav.style.setProperty('--recipe-collapsed-dock-width', `${collapsedDockWidth}px`); nav.style.setProperty('--recipe-toggle-size', `${collapsedSlotWidth}px`); + document.documentElement.style.setProperty('--recipe-dock-width', `${dockWidth}px`); document.documentElement.style.setProperty('--catalog-menu-left', `${dockLeft}px`); document.documentElement.style.setProperty('--catalog-menu-width', `${collapsedDockWidth}px`); document.documentElement.style.setProperty('--catalog-filter-left', `${filterLeft}px`); diff --git a/js/ui/calendarPopover.js b/js/ui/calendarPopover.js index 4496426..3c7ce21 100644 --- a/js/ui/calendarPopover.js +++ b/js/ui/calendarPopover.js @@ -1,7 +1,8 @@ +const STYLE_ID = 'calendar-popover-liquid-styles'; const DEFAULT_POPOVER_CLASS = 'absolute left-0 right-0 top-full mt-2 z-[50] transition-all duration-200 pointer-events-none'; const DEFAULT_POPOVER_STYLE = 'opacity:0; transform:translateY(-6px) scale(0.98);'; -const DEFAULT_PANEL_CLASS = 'rounded-[1.35rem] py-3'; -const DEFAULT_PANEL_STYLE = 'background:rgb(var(--sunken-rgb)); border:1px solid rgb(var(--border-input-rgb)); box-shadow:var(--shadow-shell);'; +const DEFAULT_PANEL_CLASS = 'calendar-liquid-panel rounded-[1.35rem] py-3'; +const DEFAULT_PANEL_STYLE = 'background-image:none !important;'; const DEFAULT_OPEN_TRIGGER_STYLE = { background: 'rgb(var(--sunken-rgb))', @@ -13,6 +14,101 @@ const DEFAULT_CLOSED_TRIGGER_STYLE = { borderColor: 'rgb(var(--border-card-rgb))', }; +export function ensureCalendarPopoverStyles() { + if (typeof document === 'undefined') return; + if (document.getElementById(STYLE_ID)) return; + + const style = document.createElement('style'); + style.id = STYLE_ID; + style.textContent = ` + .calendar-liquid-panel { + background: rgba(255, 255, 255, 0.2) !important; + border: 1px solid rgba(255, 255, 255, 0.32) !important; + box-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.14), + 0 18px 38px rgba(var(--overlay-rgb), 0.18) !important; + backdrop-filter: blur(28px) saturate(180%); + -webkit-backdrop-filter: blur(28px) saturate(180%); + } + + .dark .calendar-liquid-panel { + background: rgba(255, 255, 255, 0.04) !important; + border: 1px solid rgba(255, 255, 255, 0.12) !important; + box-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.3), + 0 24px 54px rgba(0, 0, 0, 0.38) !important; + } + + .calendar-liquid-btn { + background: rgba(255, 255, 255, 0.16) !important; + border: 1px solid rgba(255, 255, 255, 0.24) !important; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.45), + inset 0 -1px 0 rgba(var(--overlay-rgb), 0.08), + 0 6px 14px rgba(var(--overlay-rgb), 0.14) !important; + backdrop-filter: blur(22px) saturate(165%); + -webkit-backdrop-filter: blur(22px) saturate(165%); + transition: background 180ms ease, border-color 180ms ease, transform 180ms ease; + } + + .calendar-liquid-btn:hover { + background: rgba(255, 255, 255, 0.22) !important; + transform: translateY(-1px); + } + + .dark .calendar-liquid-btn { + background: rgba(255, 255, 255, 0.06) !important; + border: 1px solid rgba(255, 255, 255, 0.12) !important; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.2), + inset 0 -1px 0 rgba(0, 0, 0, 0.2), + 0 8px 18px rgba(0, 0, 0, 0.28) !important; + } + + .dark .calendar-liquid-btn:hover { + background: rgba(255, 255, 255, 0.1) !important; + } + + .calendar-liquid-btn input, + .calendar-liquid-btn input:focus, + .calendar-liquid-btn input:active { + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + border: none !important; + box-shadow: none !important; + outline: none !important; + appearance: none !important; + -webkit-appearance: none !important; + -moz-appearance: textfield !important; + backdrop-filter: none !important; + -webkit-backdrop-filter: none !important; + filter: none !important; + } + + .calendar-liquid-btn input[type='number']::-webkit-outer-spin-button, + .calendar-liquid-btn input[type='number']::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + .calendar-liquid-btn input:-webkit-autofill, + .calendar-liquid-btn input:-webkit-autofill:hover, + .calendar-liquid-btn input:-webkit-autofill:focus { + -webkit-text-fill-color: rgb(var(--text-body-rgb)); + -webkit-box-shadow: 0 0 0 1000px transparent inset !important; + box-shadow: 0 0 0 1000px transparent inset !important; + transition: background-color 9999s ease-in-out 0s; + } + + `; + document.head.appendChild(style); +} + function byId(idOrElement) { if (!idOrElement) return null; if (typeof idOrElement === 'string') return document.getElementById(idOrElement); @@ -40,6 +136,7 @@ export function createCalendarPopoverHTML({ panelStyle = DEFAULT_PANEL_STYLE, wrapInPanel = true, }) { + ensureCalendarPopoverStyles(); const body = wrapInPanel ? `
${calendarHTML}
` : calendarHTML; diff --git a/js/ui/filterPopover.js b/js/ui/filterPopover.js index 7dff52d..b4a9606 100644 --- a/js/ui/filterPopover.js +++ b/js/ui/filterPopover.js @@ -48,6 +48,14 @@ export function ensureFilterPopoverStyles() { backdrop-filter: blur(28px) saturate(180%); -webkit-backdrop-filter: blur(28px) saturate(180%); } + + .filter-liquid-surface.filter-liquid-panel-soft { + --filter-liquid-panel-bg: rgba(var(--app-bg-rgb), 0.52); + } + + .dark .filter-liquid-surface.filter-liquid-panel-soft { + --filter-liquid-panel-bg: rgba(var(--app-bg-rgb), 0.6); + } `; document.head.appendChild(style); } diff --git a/js/ui/ingredientCard.js b/js/ui/ingredientCard.js index cea5641..0db82c5 100644 --- a/js/ui/ingredientCard.js +++ b/js/ui/ingredientCard.js @@ -19,6 +19,7 @@ import { updateKitchenItemAmount, } from '../services/pantryShopping.js?v=2'; import { showAppToast } from './toast.js'; +import { ensureCalendarPopoverStyles } from './calendarPopover.js'; const CATEGORY_ICONS = { pieczywo: 'fa-bread-slice', @@ -79,7 +80,7 @@ function mediaHtml(image, icon, sizeClass = 'w-9 h-9', radiusClass = 'rounded-lg const fit = image.endsWith('.svg') ? 'object-contain' : 'object-cover'; return ``; } - return `
`; + return `
`; } function compactMetaText(text, tone = 'default') { @@ -123,6 +124,11 @@ function formatPackCount(amount, packSize) { return `${formatPreciseQty((Number(amount) || 0) / Number(packSize))} opak.`; } +function parseQtyInput(value) { + const normalized = String(value ?? '').trim().replace(',', '.'); + return normalizeQty(Number(normalized) || 0); +} + function getQtyStepMeta(def, product = null) { const productPackSize = Number(product?.packSize); if (Number.isFinite(productPackSize) && productPackSize > 0) { @@ -152,17 +158,18 @@ 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(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;', + overlayStyle = 'pointer-events:none;', + cardClass = 'calendar-liquid-panel relative w-full max-w-xs rounded-2xl overflow-hidden', + cardStyle = 'pointer-events:auto; max-height:85vh; overflow-y:auto; transform:translateY(0.75rem); opacity:0; transition:transform 220ms ease, opacity 220ms ease;', } = {}) { if (!idBase) throw new Error('getIngredientCardHTML requires idBase'); + ensureCalendarPopoverStyles(); return `
-
+
@@ -170,7 +177,7 @@ export function getIngredientCardHTML({
-

@@ -179,7 +186,7 @@ export function getIngredientCardHTML({
-
@@ -371,28 +378,28 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze

${esc(stockValueLabel)}

${stockSubLabel ? `

${esc(stockSubLabel)}

` : ''}
-
${state.stockEditorOpen ? `
- -
${usesPackStep ? `

${esc(formatQtyWithUnit(draftQty, def.pantryUnit))}

` : ''}
- +
` : ''}
`; @@ -420,8 +427,8 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze wrap.querySelector('.ingredient-card-stock-input')?.addEventListener('input', (event) => { state.stockDraftQty = usesPackStep - ? normalizeQty((Number(event.target.value) || 0) * step) - : normalizeQty(event.target.value); + ? normalizeQty(parseQtyInput(event.target.value) * step) + : parseQtyInput(event.target.value); }); wrap.querySelector('.ingredient-card-stock-clear')?.addEventListener('click', () => { @@ -432,8 +439,8 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze wrap.querySelector('.ingredient-card-stock-save')?.addEventListener('click', () => { const input = wrap.querySelector('.ingredient-card-stock-input'); const nextQty = usesPackStep - ? normalizeQty((Number(input?.value) || 0) * step) - : normalizeQty(input?.value ?? state.stockDraftQty ?? qty); + ? normalizeQty(parseQtyInput(input?.value) * step) + : parseQtyInput(input?.value ?? state.stockDraftQty ?? qty); if (product) { setPantryProductQty(def.id, product.id, nextQty); } else { @@ -480,21 +487,21 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze

${esc(shopValueLabel)}

${shopSubLabel ? `

${esc(shopSubLabel)}

` : ''}
-
${state.shopEditorOpen ? `
- -
@@ -503,7 +510,7 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze ${hasShoppingItem ? '' : ''} - +
` : ''} `; @@ -531,8 +538,8 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze wrap.querySelector('.ingredient-card-shop-input')?.addEventListener('input', (event) => { state.shopDraftQty = usesPackStep - ? normalizeQty((Number(event.target.value) || 0) * step) - : normalizeQty(event.target.value); + ? normalizeQty(parseQtyInput(event.target.value) * step) + : parseQtyInput(event.target.value); }); wrap.querySelector('.ingredient-card-shop-remove')?.addEventListener('click', () => { @@ -549,8 +556,8 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze wrap.querySelector('.ingredient-card-shop-save')?.addEventListener('click', () => { const input = wrap.querySelector('.ingredient-card-shop-input'); const nextAmount = usesPackStep - ? normalizeQty((Number(input?.value) || 0) * step) - : normalizeQty(input?.value ?? state.shopDraftQty ?? defaultAmount); + ? normalizeQty(parseQtyInput(input?.value) * step) + : parseQtyInput(input?.value ?? state.shopDraftQty ?? defaultAmount); let toastText = null; if (shoppingItem) { updateKitchenItemAmount(KITCHEN_LIST_ID, shoppingItem.id, nextAmount); diff --git a/js/views/Pantry.js b/js/views/Pantry.js index c5d0485..92bef0e 100644 --- a/js/views/Pantry.js +++ b/js/views/Pantry.js @@ -74,7 +74,7 @@ const MONTHS_SHORT = ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'w const DEFAULT_HORIZON_DAYS = 7; const SHORTFALL_ACCENT = 'rgb(var(--danger-rgb))'; const PANTRY_CALENDAR_THEME = { - bg: 'rgb(var(--app-bg-rgb))', + bg: 'rgba(255,255,255,0.08)', border: 'rgb(var(--card-raised-rgb))', text: 'rgb(var(--text-body-soft-rgb))', dimText: 'rgb(var(--text-faint-rgb))', @@ -158,6 +158,7 @@ function photoStripMedia(image, icon, accentBg) { export function getPantryHTML() { return ` +