Design changes to pantry
All checks were successful
Build and Deploy / build-and-push (push) Successful in 27s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 27s
This commit is contained in:
@@ -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 `<img src="${esc(image)}" alt="" class="${sizeClass} ${radiusClass} ${fit} shrink-0">`;
|
||||
}
|
||||
return `<div class="${sizeClass} ${radiusClass} flex items-center justify-center shrink-0" style="background:rgb(var(--card-soft-rgb));"><i class="fas ${icon} text-sm" style="color:rgb(var(--text-faint-rgb));"></i></div>`;
|
||||
return `<div class="${sizeClass} ${radiusClass} flex items-center justify-center shrink-0" style="background:transparent;"><i class="fas ${icon} text-sm" style="color:rgb(var(--text-faint-rgb));"></i></div>`;
|
||||
}
|
||||
|
||||
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 `
|
||||
<div id="${idBase}-overlay" class="${overlayClass}" style="${overlayStyle}">
|
||||
<div id="${idBase}" class="${cardClass}" style="${cardStyle}">
|
||||
<div class="relative px-4 pt-4 pb-2">
|
||||
<div class="flex items-start gap-3 pr-10">
|
||||
<div id="${idBase}-hero" class="relative w-20 h-20 rounded-2xl flex items-center justify-center shrink-0 overflow-hidden" style="background:rgb(var(--card-rgb));">
|
||||
<div id="${idBase}-hero" class="relative w-20 h-20 rounded-2xl flex items-center justify-center shrink-0 overflow-hidden" style="background:transparent;">
|
||||
<img id="${idBase}-img" class="w-full h-full hidden" alt="" />
|
||||
<div id="${idBase}-fallback" class="absolute inset-0 flex items-center justify-center">
|
||||
<i id="${idBase}-fallback-icon" class="fas fa-box-open text-2xl" style="color:rgb(var(--text-subdued-rgb));"></i>
|
||||
@@ -170,7 +177,7 @@ export function getIngredientCardHTML({
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 pt-0.5">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<button type="button" id="${idBase}-back" class="hidden w-5 h-5 rounded-full items-center justify-center shrink-0" style="background:rgb(var(--card-rgb)); color:rgb(var(--text-body-rgb));" aria-label="Wróć do składnika">
|
||||
<button type="button" id="${idBase}-back" class="calendar-liquid-btn hidden w-5 h-5 rounded-full items-center justify-center shrink-0" style="color:rgb(var(--text-body-rgb));" aria-label="Wróć do składnika">
|
||||
<i class="fas fa-chevron-left text-[9px]"></i>
|
||||
</button>
|
||||
<p id="${idBase}-category" class="text-[10px] font-semibold uppercase tracking-wider truncate" style="color:rgb(var(--success-rgb));"></p>
|
||||
@@ -179,7 +186,7 @@ export function getIngredientCardHTML({
|
||||
<p id="${idBase}-subtitle" class="text-[11px] mt-0.5 hidden" style="color:rgb(var(--text-dim-rgb));"></p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="${idBase}-close" class="absolute top-3 right-3 w-8 h-8 rounded-full flex items-center justify-center" style="background:rgb(var(--card-rgb)); color:rgb(var(--text-body-rgb));" aria-label="Zamknij">
|
||||
<button type="button" id="${idBase}-close" class="calendar-liquid-btn absolute top-3 right-3 w-8 h-8 rounded-full flex items-center justify-center" style="color:rgb(var(--text-body-rgb));" aria-label="Zamknij">
|
||||
<i class="fas fa-times text-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -371,28 +378,28 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
<p class="text-[16px] font-bold tabular-nums" style="color:rgb(var(--success-rgb));">${esc(stockValueLabel)}</p>
|
||||
${stockSubLabel ? `<p class="text-[11px] mt-1" style="color:rgb(var(--text-dim-rgb));">${esc(stockSubLabel)}</p>` : ''}
|
||||
</div>
|
||||
<button type="button" class="ingredient-card-stock-toggle inline-flex items-center rounded-full px-2.5 py-1 text-[10px] font-semibold shrink-0" style="background:${state.stockEditorOpen ? 'rgb(var(--sunken-rgb))' : 'rgb(var(--card-soft-rgb))'}; color:${state.stockEditorOpen ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))'};">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-stock-toggle inline-flex items-center rounded-full px-2.5 py-1 text-[10px] font-semibold shrink-0" style="color:${state.stockEditorOpen ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))'};">
|
||||
${esc(actionLabel)}
|
||||
</button>
|
||||
</div>
|
||||
${state.stockEditorOpen ? `
|
||||
<div class="mt-3 pt-3 border-t" style="border-color:rgb(var(--card-strong-rgb));">
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" class="ingredient-card-stock-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="background:rgb(var(--card-soft-rgb)); color:rgb(var(--text-body-soft-rgb));" data-dir="-1" aria-label="Zmniejsz szkic zapasu">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-stock-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="color:rgb(var(--text-body-soft-rgb));" data-dir="-1" aria-label="Zmniejsz szkic zapasu">
|
||||
<i class="fas fa-minus text-xs"></i>
|
||||
</button>
|
||||
<label class="flex-1 rounded-xl px-3 py-2 flex items-center justify-center gap-2" style="background:rgb(var(--card-soft-rgb));">
|
||||
<input type="number" min="0" step="${usesPackStep ? '1' : step}" value="${draftInputValue}" class="ingredient-card-stock-input w-20 bg-transparent text-center text-[14px] font-semibold tabular-nums outline-none appearance-none" style="color:rgb(var(--text-body-rgb)); background:transparent !important; border:none !important; box-shadow:none !important; -webkit-appearance:none; -moz-appearance:textfield;">
|
||||
<label class="calendar-liquid-btn flex-1 rounded-xl px-3 py-2 flex items-center justify-center gap-2">
|
||||
<input type="text" inputmode="decimal" value="${draftInputValue}" class="ingredient-card-stock-input w-20 bg-transparent text-center text-[14px] font-semibold tabular-nums outline-none appearance-none" style="color:rgb(var(--text-body-rgb)); background:transparent !important; border:none !important; box-shadow:none !important; -webkit-appearance:none; -moz-appearance:textfield;">
|
||||
<span class="text-[12px] font-medium shrink-0" style="color:rgb(var(--text-dim-rgb));">${esc(draftInputUnit)}</span>
|
||||
</label>
|
||||
<button type="button" class="ingredient-card-stock-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="background:rgb(var(--card-soft-rgb)); color:rgb(var(--text-body-soft-rgb));" data-dir="1" aria-label="Zwiększ szkic zapasu">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-stock-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="color:rgb(var(--text-body-soft-rgb));" data-dir="1" aria-label="Zwiększ szkic zapasu">
|
||||
<i class="fas fa-plus text-xs"></i>
|
||||
</button>
|
||||
</div>
|
||||
${usesPackStep ? `<p class="text-[10px] mt-2 text-right" style="color:rgb(var(--text-dim-rgb));">${esc(formatQtyWithUnit(draftQty, def.pantryUnit))}</p>` : ''}
|
||||
<div class="flex items-center justify-between gap-3 mt-3">
|
||||
<button type="button" class="ingredient-card-stock-clear text-[11px] font-semibold" style="color:rgb(var(--text-dim-rgb));">Wyzeruj</button>
|
||||
<button type="button" class="ingredient-card-stock-save inline-flex items-center rounded-full px-3 py-1.5 text-[11px] font-semibold" style="background:rgb(var(--text-body-rgb)); color:rgb(var(--app-bg-rgb));">Zapisz</button>
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-stock-save inline-flex items-center rounded-full px-3 py-1.5 text-[11px] font-semibold" style="color:rgb(var(--text-emphasis-rgb));">Zapisz</button>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>`;
|
||||
@@ -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
|
||||
<p class="text-[16px] font-bold tabular-nums" style="color:${hasShoppingItem ? 'rgb(var(--text-body-rgb))' : 'rgb(var(--text-dim-rgb))'};">${esc(shopValueLabel)}</p>
|
||||
${shopSubLabel ? `<p class="text-[11px] mt-1" style="color:rgb(var(--text-dim-rgb));">${esc(shopSubLabel)}</p>` : ''}
|
||||
</div>
|
||||
<button type="button" class="ingredient-card-shop-toggle inline-flex items-center rounded-full px-2.5 py-1 text-[10px] font-semibold shrink-0" style="background:${state.shopEditorOpen ? 'rgb(var(--sunken-rgb))' : 'rgb(var(--card-soft-rgb))'}; color:${state.shopEditorOpen ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))'};">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-shop-toggle inline-flex items-center rounded-full px-2.5 py-1 text-[10px] font-semibold shrink-0" style="color:${state.shopEditorOpen ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))'};">
|
||||
${esc(actionLabel)}
|
||||
</button>
|
||||
</div>
|
||||
${state.shopEditorOpen ? `
|
||||
<div class="mt-3 pt-3 border-t" style="border-color:rgb(var(--card-strong-rgb));">
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" class="ingredient-card-shop-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="background:rgb(var(--card-soft-rgb)); color:rgb(var(--text-body-soft-rgb));" data-dir="-1" aria-label="Zmniejsz ilość na liście">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-shop-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="color:rgb(var(--text-body-soft-rgb));" data-dir="-1" aria-label="Zmniejsz ilość na liście">
|
||||
<i class="fas fa-minus text-xs"></i>
|
||||
</button>
|
||||
<label class="flex-1 rounded-xl px-3 py-2 flex items-center justify-center gap-2" style="background:rgb(var(--card-soft-rgb));">
|
||||
<input type="number" min="0" step="${usesPackStep ? '1' : defaultAmount}" value="${shopInputValue}" class="ingredient-card-shop-input w-20 bg-transparent text-center text-[14px] font-semibold tabular-nums outline-none appearance-none" style="color:rgb(var(--text-body-rgb)); background:transparent !important; border:none !important; box-shadow:none !important; -webkit-appearance:none; -moz-appearance:textfield;">
|
||||
<label class="calendar-liquid-btn flex-1 rounded-xl px-3 py-2 flex items-center justify-center gap-2">
|
||||
<input type="text" inputmode="decimal" value="${shopInputValue}" class="ingredient-card-shop-input w-20 bg-transparent text-center text-[14px] font-semibold tabular-nums outline-none appearance-none" style="color:rgb(var(--text-body-rgb)); background:transparent !important; border:none !important; box-shadow:none !important; -webkit-appearance:none; -moz-appearance:textfield;">
|
||||
<span class="text-[12px] font-medium shrink-0" style="color:rgb(var(--text-dim-rgb));">${esc(shopInputUnit)}</span>
|
||||
</label>
|
||||
<button type="button" class="ingredient-card-shop-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="background:rgb(var(--card-soft-rgb)); color:rgb(var(--text-body-soft-rgb));" data-dir="1" aria-label="Zwiększ ilość na liście">
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-shop-step w-9 h-9 rounded-xl flex items-center justify-center shrink-0" style="color:rgb(var(--text-body-soft-rgb));" data-dir="1" aria-label="Zwiększ ilość na liście">
|
||||
<i class="fas fa-plus text-xs"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -503,7 +510,7 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
${hasShoppingItem
|
||||
? '<button type="button" class="ingredient-card-shop-remove text-[11px] font-semibold" style="color:rgb(var(--text-dim-rgb));">Usuń z listy</button>'
|
||||
: '<span></span>'}
|
||||
<button type="button" class="ingredient-card-shop-save inline-flex items-center rounded-full px-3 py-1.5 text-[11px] font-semibold" style="background:rgb(var(--text-body-rgb)); color:rgb(var(--app-bg-rgb));">Zapisz</button>
|
||||
<button type="button" class="calendar-liquid-btn ingredient-card-shop-save inline-flex items-center rounded-full px-3 py-1.5 text-[11px] font-semibold" style="color:rgb(var(--text-emphasis-rgb));">Zapisz</button>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>`;
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user