Extract colors
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m10s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m10s
This commit is contained in:
@@ -18,7 +18,11 @@ function setupThemeToggle() {
|
||||
syncThemeToggleButton(btn, isDark);
|
||||
|
||||
const meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', isDark ? '#161513' : '#f3efe9');
|
||||
if (meta) {
|
||||
const varName = isDark ? '--sunken-deep-rgb' : '--app-bg-rgb';
|
||||
const rgb = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
|
||||
if (rgb) meta.setAttribute('content', `rgb(${rgb})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,11 @@ 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:#2f2f2d;"><i class="fas ${icon} text-sm" style="color:#8f8b84;"></i></div>`;
|
||||
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>`;
|
||||
}
|
||||
|
||||
function compactMetaText(text, tone = 'default') {
|
||||
const color = tone === 'success' ? '#6ee7b7' : tone === 'muted' ? '#9b978f' : '#d7d2c8';
|
||||
const color = tone === 'success' ? 'rgb(var(--success-rgb))' : tone === 'muted' ? 'rgb(var(--text-dim-rgb))' : 'rgb(var(--text-body-soft-rgb))';
|
||||
return `<span class="text-[10px] font-medium" style="color:${color};">${esc(text)}</span>`;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ export function getIngredientCardHTML({
|
||||
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);',
|
||||
cardClass = 'relative w-full max-w-xs rounded-2xl shadow-2xl overflow-hidden',
|
||||
cardStyle = 'background:#2d2e2b; pointer-events:auto; max-height:85vh; overflow-y:auto; transform:translateY(0.75rem); opacity:0; transition:transform 220ms ease, opacity 220ms ease;',
|
||||
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;',
|
||||
} = {}) {
|
||||
if (!idBase) throw new Error('getIngredientCardHTML requires idBase');
|
||||
return `
|
||||
@@ -162,24 +162,24 @@ export function getIngredientCardHTML({
|
||||
<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:#393937;">
|
||||
<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));">
|
||||
<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:#6d6c67;"></i>
|
||||
<i id="${idBase}-fallback-icon" class="fas fa-box-open text-2xl" style="color:rgb(var(--text-subdued-rgb));"></i>
|
||||
</div>
|
||||
</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:#393937; color:#ddd6ca;" aria-label="Wróć do składnika">
|
||||
<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">
|
||||
<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:#6ee7b7;"></p>
|
||||
<p id="${idBase}-category" class="text-[10px] font-semibold uppercase tracking-wider truncate" style="color:rgb(var(--success-rgb));"></p>
|
||||
</div>
|
||||
<h3 id="${idBase}-name" class="text-[15px] font-bold leading-snug mt-0.5" style="color:#ddd6ca;"></h3>
|
||||
<p id="${idBase}-subtitle" class="text-[11px] mt-0.5 hidden" style="color:#9b978f;"></p>
|
||||
<h3 id="${idBase}-name" class="text-[15px] font-bold leading-snug mt-0.5" style="color:rgb(var(--text-body-rgb));"></h3>
|
||||
<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:#393937; color:#ddd6ca;" aria-label="Zamknij">
|
||||
<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">
|
||||
<i class="fas fa-times text-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -319,24 +319,24 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const nutritionMeta = hint ? `${unitScope} • ${hint}` : unitScope;
|
||||
|
||||
wrap.innerHTML = `
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:#9b978f;">Wartości odżywcze</p>
|
||||
<p class="text-[10px] mb-1.5" style="color:#9b978f;">${esc(nutritionMeta)}</p>
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:rgb(var(--text-dim-rgb));">Wartości odżywcze</p>
|
||||
<p class="text-[10px] mb-1.5" style="color:rgb(var(--text-dim-rgb));">${esc(nutritionMeta)}</p>
|
||||
<div class="grid grid-cols-4 gap-1.5">
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:#393937;">
|
||||
<p class="text-[15px] font-bold tabular-nums leading-tight" style="color:#ddd6ca;">${nutrition.kcal}</p>
|
||||
<p class="text-[9px] font-medium" style="color:#9b978f;">kcal</p>
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold tabular-nums leading-tight" style="color:rgb(var(--text-body-rgb));">${nutrition.kcal}</p>
|
||||
<p class="text-[9px] font-medium" style="color:rgb(var(--text-dim-rgb));">kcal</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-blue-400 tabular-nums leading-tight">${formatQty(nutrition.protein)}g</p>
|
||||
<p class="text-[9px] font-medium" style="color:#9b978f;">białko</p>
|
||||
<p class="text-[9px] font-medium" style="color:rgb(var(--text-dim-rgb));">białko</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-amber-400 tabular-nums leading-tight">${formatQty(nutrition.fat)}g</p>
|
||||
<p class="text-[9px] font-medium" style="color:#9b978f;">tłuszcz</p>
|
||||
<p class="text-[9px] font-medium" style="color:rgb(var(--text-dim-rgb));">tłuszcz</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-1.5 text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-orange-400 tabular-nums leading-tight">${formatQty(nutrition.carbs)}g</p>
|
||||
<p class="text-[9px] font-medium" style="color:#9b978f;">węgl.</p>
|
||||
<p class="text-[9px] font-medium" style="color:rgb(var(--text-dim-rgb));">węgl.</p>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -364,35 +364,35 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const actionLabel = state.stockEditorOpen ? 'Anuluj' : 'Zmień';
|
||||
|
||||
wrap.innerHTML = `
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:#9b978f;">Zapas</p>
|
||||
<div class="rounded-2xl border px-3 py-3" style="background:#393937; border-color:#444442;">
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:rgb(var(--text-dim-rgb));">Zapas</p>
|
||||
<div class="rounded-2xl border px-3 py-3" style="background:rgb(var(--card-rgb)); border-color:rgb(var(--card-strong-rgb));">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[16px] font-bold tabular-nums" style="color:#6ee7b7;">${esc(stockValueLabel)}</p>
|
||||
${stockSubLabel ? `<p class="text-[11px] mt-1" style="color:#9b978f;">${esc(stockSubLabel)}</p>` : ''}
|
||||
<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 ? '#23221e' : '#2f2f2d'}; color:${state.stockEditorOpen ? '#f2efe8' : '#d7d2c8'};">
|
||||
<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))'};">
|
||||
${esc(actionLabel)}
|
||||
</button>
|
||||
</div>
|
||||
${state.stockEditorOpen ? `
|
||||
<div class="mt-3 pt-3 border-t" style="border-color:#444442;">
|
||||
<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:#2f2f2d; color:#d7d2c8;" data-dir="-1" aria-label="Zmniejsz szkic zapasu">
|
||||
<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">
|
||||
<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:#2f2f2d;">
|
||||
<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:#ddd6ca; 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:#9b978f;">${esc(draftInputUnit)}</span>
|
||||
<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;">
|
||||
<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:#2f2f2d; color:#d7d2c8;" data-dir="1" aria-label="Zwiększ szkic zapasu">
|
||||
<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">
|
||||
<i class="fas fa-plus text-xs"></i>
|
||||
</button>
|
||||
</div>
|
||||
${usesPackStep ? `<p class="text-[10px] mt-2 text-right" style="color:#9b978f;">${esc(formatQtyWithUnit(draftQty, def.pantryUnit))}</p>` : ''}
|
||||
${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:#9b978f;">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:#ddd6ca; color:#2d2e2b;">Zapisz</button>
|
||||
<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>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>`;
|
||||
@@ -473,37 +473,37 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const actionLabel = state.shopEditorOpen ? 'Anuluj' : (hasShoppingItem ? 'Zmień' : 'Dodaj');
|
||||
|
||||
wrap.innerHTML = `
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:#9b978f;">Lista zakupów</p>
|
||||
<div class="rounded-2xl border px-3 py-3" style="background:#393937; border-color:#444442;">
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:rgb(var(--text-dim-rgb));">Lista zakupów</p>
|
||||
<div class="rounded-2xl border px-3 py-3" style="background:rgb(var(--card-rgb)); border-color:rgb(var(--card-strong-rgb));">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[16px] font-bold tabular-nums" style="color:${hasShoppingItem ? '#ddd6ca' : '#9b978f'};">${esc(shopValueLabel)}</p>
|
||||
${shopSubLabel ? `<p class="text-[11px] mt-1" style="color:#9b978f;">${esc(shopSubLabel)}</p>` : ''}
|
||||
<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 ? '#23221e' : '#2f2f2d'}; color:${state.shopEditorOpen ? '#f2efe8' : '#d7d2c8'};">
|
||||
<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))'};">
|
||||
${esc(actionLabel)}
|
||||
</button>
|
||||
</div>
|
||||
${state.shopEditorOpen ? `
|
||||
<div class="mt-3 pt-3 border-t" style="border-color:#444442;">
|
||||
<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:#2f2f2d; color:#d7d2c8;" data-dir="-1" aria-label="Zmniejsz ilość na liście">
|
||||
<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">
|
||||
<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:#2f2f2d;">
|
||||
<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:#ddd6ca; 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:#9b978f;">${esc(shopInputUnit)}</span>
|
||||
<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;">
|
||||
<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:#2f2f2d; color:#d7d2c8;" data-dir="1" aria-label="Zwiększ ilość na liście">
|
||||
<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">
|
||||
<i class="fas fa-plus text-xs"></i>
|
||||
</button>
|
||||
</div>
|
||||
${usesPackStep ? `<p class="text-[10px] mt-2 text-right" style="color:#9b978f;">${esc(formatQtyWithUnit(draftQty, def.pantryUnit))}</p>` : ''}
|
||||
${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">
|
||||
${hasShoppingItem
|
||||
? '<button type="button" class="ingredient-card-shop-remove text-[11px] font-semibold" style="color:#9b978f;">Usuń z listy</button>'
|
||||
? '<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:#ddd6ca; color:#2d2e2b;">Zapisz</button>
|
||||
<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>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>`;
|
||||
@@ -611,24 +611,24 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const shoppingAmount = shoppingItem?.amount || 0;
|
||||
|
||||
const pantryLabel = pantryQty > 0 ? `${formatQty(pantryQty)} ${unit}` : '—';
|
||||
const pantryColor = pantryQty > 0 ? '#ddd6ca' : '#6d6c67';
|
||||
const pantryColor = pantryQty > 0 ? 'rgb(var(--text-body-rgb))' : 'rgb(var(--text-subdued-rgb))';
|
||||
const shoppingLabel = shoppingAmount > 0 ? `${formatQty(shoppingAmount)} ${unit}` : '';
|
||||
|
||||
return `<button type="button" class="ingredient-card-product-row w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-left transition-colors active:scale-[0.99]" style="background:#393937; border:1px solid transparent;" data-product-id="${esc(productId)}">
|
||||
return `<button type="button" class="ingredient-card-product-row w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-left transition-colors active:scale-[0.99]" style="background:rgb(var(--card-rgb)); border:1px solid transparent;" data-product-id="${esc(productId)}">
|
||||
${mediaHtml(product.image || def.image, icon)}
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="text-[13px] font-semibold truncate block" style="color:#ddd6ca;">${esc(product.name)}</span>
|
||||
${product.packLabel ? `<span class="text-[10px] block mt-0.5" style="color:#9b978f;">${esc(product.packLabel)}</span>` : ''}
|
||||
<span class="text-[13px] font-semibold truncate block" style="color:rgb(var(--text-body-rgb));">${esc(product.name)}</span>
|
||||
${product.packLabel ? `<span class="text-[10px] block mt-0.5" style="color:rgb(var(--text-dim-rgb));">${esc(product.packLabel)}</span>` : ''}
|
||||
</div>
|
||||
<div class="flex flex-col items-end gap-0.5 shrink-0 tabular-nums">
|
||||
<span class="text-[11px] font-semibold inline-flex items-center gap-1" style="color:${pantryColor};">
|
||||
<i class="fas fa-box text-[9px]" style="color:#8f8b84;"></i>${esc(pantryLabel)}
|
||||
<i class="fas fa-box text-[9px]" style="color:rgb(var(--text-faint-rgb));"></i>${esc(pantryLabel)}
|
||||
</span>
|
||||
${shoppingLabel ? `<span class="text-[11px] font-semibold inline-flex items-center gap-1" style="color:#ddd6ca;">
|
||||
<i class="fas fa-cart-shopping text-[9px]" style="color:#8f8b84;"></i>${esc(shoppingLabel)}
|
||||
${shoppingLabel ? `<span class="text-[11px] font-semibold inline-flex items-center gap-1" style="color:rgb(var(--text-body-rgb));">
|
||||
<i class="fas fa-cart-shopping text-[9px]" style="color:rgb(var(--text-faint-rgb));"></i>${esc(shoppingLabel)}
|
||||
</span>` : ''}
|
||||
</div>
|
||||
<i class="fas fa-chevron-right text-[10px] shrink-0" style="color:#8f8b84;"></i>
|
||||
<i class="fas fa-chevron-right text-[10px] shrink-0" style="color:rgb(var(--text-faint-rgb));"></i>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const kitchenItems = (kitchen && kitchen.type === 'kitchen') ? kitchen.items : [];
|
||||
|
||||
wrap.innerHTML = `
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:#9b978f;">Produkty</p>
|
||||
<p class="text-[9px] font-semibold uppercase tracking-wide mb-1.5" style="color:rgb(var(--text-dim-rgb));">Produkty</p>
|
||||
<div class="space-y-1.5">
|
||||
${products.map((product) => productRowHtml(state.ingredientId, product.id, pantry, kitchenItems)).join('')}
|
||||
</div>`;
|
||||
|
||||
@@ -19,7 +19,7 @@ export const CALENDAR_MONTHS_SHORT = [
|
||||
|
||||
export const CALENDAR_WEEKDAYS_SHORT = ['pn', 'wt', 'śr', 'cz', 'pt', 'so', 'nd'];
|
||||
export const CALENDAR_DAY_ATTR = 'data-calendar-day';
|
||||
export const CALENDAR_HANDLE_CLASS = 'block h-1 w-10 rounded-full bg-[#6d6c67]/75';
|
||||
export const CALENDAR_HANDLE_CLASS = 'block h-1 w-10 rounded-full bg-[rgb(var(--text-subdued-rgb))]/75';
|
||||
|
||||
function getCalendarDayHTML(day, meta, dayState, dayAttr, theme = {}) {
|
||||
const { mode, selectedDate } = meta;
|
||||
@@ -27,9 +27,9 @@ function getCalendarDayHTML(day, meta, dayState, dayAttr, theme = {}) {
|
||||
const showIndicator = !!dayState.showIndicator;
|
||||
const isDisabled = !!dayState.disabled;
|
||||
const isDimmed = !!dayState.dimmed && !isSelected;
|
||||
const defaultBg = '#2f2f2d';
|
||||
const defaultBorder = '#444442';
|
||||
const defaultText = '#d7d2c8';
|
||||
const defaultBg = 'rgb(var(--card-soft-rgb))';
|
||||
const defaultBorder = 'rgb(var(--card-strong-rgb))';
|
||||
const defaultText = 'rgb(var(--text-body-soft-rgb))';
|
||||
|
||||
let bg;
|
||||
let borderColor;
|
||||
@@ -37,12 +37,12 @@ function getCalendarDayHTML(day, meta, dayState, dayAttr, theme = {}) {
|
||||
let borderClass = 'border';
|
||||
|
||||
if (isSelected) {
|
||||
bg = theme.selectedBg || '#23221e';
|
||||
borderColor = theme.selectedBorder || '#787876';
|
||||
text = theme.selectedText || '#f2efe8';
|
||||
bg = theme.selectedBg || 'rgb(var(--sunken-rgb))';
|
||||
borderColor = theme.selectedBorder || 'rgb(var(--border-input-rgb))';
|
||||
text = theme.selectedText || 'rgb(var(--text-emphasis-rgb))';
|
||||
} else if (isDimmed) {
|
||||
bg = theme.dimmedBg ?? theme.bg ?? defaultBg;
|
||||
text = theme.dimText || '#7d7a74';
|
||||
text = theme.dimText || 'rgb(var(--text-faint-rgb))';
|
||||
borderClass = 'border-0';
|
||||
} else {
|
||||
bg = theme.bg || defaultBg;
|
||||
@@ -50,7 +50,7 @@ function getCalendarDayHTML(day, meta, dayState, dayAttr, theme = {}) {
|
||||
text = theme.text || defaultText;
|
||||
}
|
||||
|
||||
const dot = isSelected ? (theme.selectedDot || '#f2efe8') : (theme.dot || '#a59f92');
|
||||
const dot = isSelected ? (theme.selectedDot || 'rgb(var(--text-emphasis-rgb))') : (theme.dot || 'rgb(var(--text-faint-rgb))');
|
||||
const opacity = isDimmed ? String(theme.dimOpacity ?? 0.72) : '1';
|
||||
const borderStyle = isDimmed ? 'border:none;' : `border-color:${borderColor};`;
|
||||
const outerClass = `${mode === 'month' ? 'mx-auto ' : ''}flex h-[2.05rem] w-full min-w-0 max-w-full items-center justify-center rounded-full ${borderClass} text-xs font-medium transition-colors leading-tight overflow-hidden`;
|
||||
@@ -118,10 +118,10 @@ export function createCalendarTopbarHTML({
|
||||
todayId,
|
||||
nextId,
|
||||
wrapperClass = 'px-4 pt-4 pb-3 flex items-center justify-end',
|
||||
controlsStyle = 'background:#2f2f2d;border-color:#444442;',
|
||||
navButtonClass = 'shrink-0 w-7 h-full flex items-center justify-center rounded-full border-0 bg-transparent text-[#d7d2c8] transition-colors',
|
||||
todayButtonActiveClass = 'h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center rounded-full bg-transparent px-1.5 text-[10px] font-semibold leading-none tabular-nums text-[#d7d2c8] active:bg-transparent whitespace-nowrap',
|
||||
todayButtonDimClass = 'h-full shrink-0 inline-flex items-center justify-center rounded-full px-2 text-[10px] font-semibold leading-none text-[#7d7a74] cursor-default',
|
||||
controlsStyle = 'background:rgb(var(--card-soft-rgb));border-color:rgb(var(--card-strong-rgb));',
|
||||
navButtonClass = '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',
|
||||
todayButtonActiveClass = 'h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center rounded-full bg-transparent px-1.5 text-[10px] font-semibold leading-none tabular-nums text-[rgb(var(--text-body-soft-rgb))] active:bg-transparent whitespace-nowrap',
|
||||
todayButtonDimClass = 'h-full shrink-0 inline-flex items-center justify-center rounded-full px-2 text-[10px] font-semibold leading-none text-[rgb(var(--text-faint-rgb))] cursor-default',
|
||||
}) {
|
||||
return `
|
||||
<div class="${wrapperClass}">
|
||||
@@ -168,7 +168,7 @@ export function syncCalendarTodayButton(buttonEl, isOnToday, selectedDate, optio
|
||||
ariaLabelCurrent = 'Widok jest ustawiony na bieżący okres',
|
||||
} = options;
|
||||
const active = buttonEl.dataset.calActiveClass
|
||||
|| 'h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center rounded-full bg-transparent px-1.5 text-[10px] font-semibold leading-none tabular-nums text-[#d7d2c8] active:bg-transparent whitespace-nowrap';
|
||||
|| 'h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center rounded-full bg-transparent px-1.5 text-[10px] font-semibold leading-none tabular-nums text-[rgb(var(--text-body-soft-rgb))] active:bg-transparent whitespace-nowrap';
|
||||
if (selectedDate != null) {
|
||||
buttonEl.textContent = formatCalendarSelectedDate(selectedDate);
|
||||
}
|
||||
|
||||
@@ -37,21 +37,21 @@ const slotLabel = Object.fromEntries(MEAL_SLOTS.map((s) => [s.id, s.label]));
|
||||
export function getMealPlanEditorHTML() {
|
||||
return `
|
||||
<div id="mpe-overlay" class="absolute inset-0 z-[55] bg-black/45 hidden flex items-end" style="pointer-events:none">
|
||||
<div id="mpe-sheet" class="w-full bg-[#2d2e2b] rounded-t-3xl shadow-lg flex flex-col overflow-hidden" style="pointer-events:auto; background:#2d2e2b !important; background-image:none !important; backdrop-filter:none !important; height:100dvh; max-height:100dvh; transform:translateY(100%); transition:transform 300ms cubic-bezier(0.32,0.72,0,1)">
|
||||
<div class="shrink-0 px-5 pt-3 pb-2.5 border-b border-gray-100 bg-[#2d2e2b]" style="background:#2d2e2b !important; background-image:none !important;">
|
||||
<div id="mpe-sheet" class="w-full bg-[rgb(var(--app-bg-rgb))] rounded-t-3xl shadow-lg flex flex-col overflow-hidden" style="pointer-events:auto; background:rgb(var(--app-bg-rgb)) !important; background-image:none !important; backdrop-filter:none !important; height:100dvh; max-height:100dvh; transform:translateY(100%); transition:transform 300ms cubic-bezier(0.32,0.72,0,1)">
|
||||
<div class="shrink-0 px-5 pt-3 pb-2.5 border-b border-gray-100 bg-[rgb(var(--app-bg-rgb))]" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;">
|
||||
<div class="w-10 h-1 bg-gray-200 rounded-full mx-auto mb-3"></div>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<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:#dcd6cb !important; color:#2d2e2b !important; background-image:none !important; border-color:#dcd6cb !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(0,0,0,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>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mpe-cal-wrap" class="hidden relative z-[1] shrink-0 px-5 pt-3 pb-3 bg-[#2d2e2b]" style="background:#2d2e2b !important; background-image:none !important;">
|
||||
<div id="mpe-cal-wrap" class="hidden relative z-[1] shrink-0 px-5 pt-3 pb-3 bg-[rgb(var(--app-bg-rgb))]" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important;">
|
||||
<div id="mpe-cal-section" class="hidden">
|
||||
${createCalendarTopbarHTML({
|
||||
prevId: 'mpe-cal-prev',
|
||||
@@ -66,12 +66,12 @@ export function getMealPlanEditorHTML() {
|
||||
<div id="mpe-slot-chips" class="flex flex-wrap gap-1.5"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mpe-summary-wrap" class="relative z-[1] shrink-0 px-5 pb-3 bg-[#2d2e2b]" style="background:#2d2e2b !important; background-image:none !important;">
|
||||
<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>
|
||||
<div id="mpe-ing-scroll" class="flex-1 min-h-0 overflow-y-auto no-scrollbar px-5 bg-[#2d2e2b]" style="background:#2d2e2b !important; background-image:none !important; padding-bottom:calc(1.5rem + env(safe-area-inset-bottom));">
|
||||
<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">
|
||||
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-wider mb-2">Składniki</p>
|
||||
<div id="mpe-ing-list" class="space-y-1.5"></div>
|
||||
@@ -214,9 +214,9 @@ export function setupMealPlanEditor() {
|
||||
if (!r) return;
|
||||
el.innerHTML = MEAL_SLOTS.filter((s) => r.allowedSlots.includes(s.id)).map((s) => {
|
||||
const sel = s.id === S.slotId;
|
||||
const bg = sel ? '#23221e' : '#2f2f2d';
|
||||
const border = sel ? '#787876' : '#444442';
|
||||
const text = sel ? '#f2efe8' : '#d7d2c8';
|
||||
const bg = sel ? 'rgb(var(--sunken-rgb))' : 'rgb(var(--card-soft-rgb))';
|
||||
const border = sel ? 'rgb(var(--border-input-rgb))' : 'rgb(var(--card-strong-rgb))';
|
||||
const text = sel ? 'rgb(var(--text-emphasis-rgb))' : 'rgb(var(--text-body-soft-rgb))';
|
||||
return `<button type="button" class="mpe-slot-btn px-3 py-1.5 rounded-full border text-[12px] font-semibold transition-colors" data-slot-id="${s.id}" style="background:${bg} !important; background-image:none !important; box-shadow:none !important; border-color:${border} !important; color:${text} !important;">${esc(s.label)}</button>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -245,12 +245,12 @@ 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:#2f2f2d;border-color:#444442;box-shadow:0 2px 8px rgba(0,0,0,0.25);">
|
||||
<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-[#d7d2c8] transition-colors" aria-label="Zmniejsz liczbę porcji">
|
||||
<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);">
|
||||
<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>
|
||||
<span id="mpe-serv-count" class="flex-1 h-full inline-flex items-center justify-center px-0.5 text-[12px] font-semibold leading-none text-[#d7d2c8] tabular-nums">${S.servings}</span>
|
||||
<button type="button" id="mpe-serv-plus" class="shrink-0 w-7 h-full flex items-center justify-center rounded-full border-0 bg-transparent text-[#d7d2c8] transition-colors" aria-label="Zwiększ liczbę porcji">
|
||||
<span id="mpe-serv-count" class="flex-1 h-full inline-flex items-center justify-center px-0.5 text-[12px] font-semibold leading-none text-[rgb(var(--text-body-soft-rgb))] tabular-nums">${S.servings}</span>
|
||||
<button type="button" id="mpe-serv-plus" 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="Zwiększ liczbę porcji">
|
||||
<i class="fas fa-plus text-[10px]"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -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:#393937 !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:0 2px 8px rgba(0,0,0,0.25) !important; border:none !important;';
|
||||
|
||||
for (const ing of r.ingredients) {
|
||||
const id = ing.ingredientId;
|
||||
@@ -317,12 +317,12 @@ export function setupMealPlanEditor() {
|
||||
const isSel = eid === altId;
|
||||
const checkbox = `
|
||||
<span class="ml-auto self-center w-[18px] h-[18px] rounded-full shrink-0 flex items-center justify-center"
|
||||
style="border:1.5px solid #56534f; background:transparent;">
|
||||
${isSel ? '<i class="fas fa-check" style="color:#9b978f; font-size:8px; line-height:1; display:block; transform:translateY(0.5px);"></i>' : ''}
|
||||
style="border:1.5px solid rgba(var(--border-input-rgb), 0.58); background:transparent;">
|
||||
${isSel ? '<i class="fas fa-check" style="color:rgb(var(--text-dim-rgb)); font-size:8px; line-height:1; display:block; transform:translateY(0.5px);"></i>' : ''}
|
||||
</span>`;
|
||||
const n = nutFor(altId, disp, ing.unit);
|
||||
const nLine = n ? `<div class="text-[10px] text-gray-400 mt-0.5 tabular-nums">${n.kcal} kcal · ${n.protein}g B · ${n.fat}g T · ${n.carbs}g W</div>` : '';
|
||||
html += `<button type="button" class="mpe-alt-pick w-full text-left p-2.5 rounded-lg transition-all" style="background:#2f2f2d !important; background-image:none !important; border:none !important; box-shadow:none !important;" data-orig-id="${esc(id)}" data-alt-id="${esc(altId)}"><div class="flex items-center gap-3"><div class="min-w-0 flex-1"><div class="text-[11px] font-semibold text-gray-900">${esc(name)}</div>${nLine}</div>${checkbox}</div></button>`;
|
||||
html += `<button type="button" class="mpe-alt-pick w-full text-left p-2.5 rounded-lg transition-all" style="background:rgb(var(--card-soft-rgb)) !important; background-image:none !important; border:none !important; box-shadow:none !important;" data-orig-id="${esc(id)}" data-alt-id="${esc(altId)}"><div class="flex items-center gap-3"><div class="min-w-0 flex-1"><div class="text-[11px] font-semibold text-gray-900">${esc(name)}</div>${nLine}</div>${checkbox}</div></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -341,7 +341,7 @@ export function setupMealPlanEditor() {
|
||||
const addedBadge = addedProduct
|
||||
? `<div class="flex items-center gap-1 mt-0.5"><span class="text-[10px] text-emerald-400 truncate">${esc(addedProduct.name)}</span></div>`
|
||||
: '';
|
||||
html += `<div class="flex-1 min-w-0 mpe-open-product-card cursor-pointer" data-eid="${esc(a.ingredientId)}" data-pid="${esc(addedPid)}"><div class="flex items-center gap-1.5"><span class="text-[12px] font-semibold text-gray-900 truncate">${esc(name)}</span><span class="shrink-0 inline-flex items-center justify-center text-[#8f8b84]" title="Dodany składnik" aria-label="Dodany składnik"><i class="fas fa-plus text-[8px]"></i></span></div>${addedBadge}</div>`;
|
||||
html += `<div class="flex-1 min-w-0 mpe-open-product-card cursor-pointer" data-eid="${esc(a.ingredientId)}" data-pid="${esc(addedPid)}"><div class="flex items-center gap-1.5"><span class="text-[12px] font-semibold text-gray-900 truncate">${esc(name)}</span><span class="shrink-0 inline-flex items-center justify-center text-[rgb(var(--text-faint-rgb))]" title="Dodany składnik" aria-label="Dodany składnik"><i class="fas fa-plus text-[8px]"></i></span></div>${addedBadge}</div>`;
|
||||
html += `<button type="button" class="mpe-edit-amt shrink-0 flex items-center gap-1 px-2 py-1 rounded-lg hover:bg-gray-100 transition-colors" data-ing-id="${esc(a.ingredientId)}" data-type="added">`;
|
||||
html += `<span class="text-[12px] font-semibold text-gray-900 tabular-nums">${fmtAmt(disp)}</span>`;
|
||||
html += `<span class="text-[11px] text-gray-500">${esc(a.unit)}</span></button>`;
|
||||
@@ -365,7 +365,7 @@ export function setupMealPlanEditor() {
|
||||
const el = document.getElementById('mpe-add-area');
|
||||
if (!el) return;
|
||||
if (!S.addOpen) {
|
||||
el.innerHTML = `<button type="button" id="mpe-add-btn" class="w-full py-2 rounded-xl border border-dashed text-[12px] font-semibold transition-colors" style="border-color:#444442; color:#9b978f; background:transparent !important; box-shadow:none !important; -webkit-tap-highlight-color:transparent;"><i class="fas fa-plus text-[10px] mr-1.5 opacity-70"></i>Dodaj składnik</button>`;
|
||||
el.innerHTML = `<button type="button" id="mpe-add-btn" class="w-full py-2 rounded-xl border border-dashed text-[12px] font-semibold transition-colors" style="border-color:rgb(var(--card-strong-rgb)); color:rgb(var(--text-dim-rgb)); background:transparent !important; box-shadow:none !important; -webkit-tap-highlight-color:transparent;"><i class="fas fa-plus text-[10px] mr-1.5 opacity-70"></i>Dodaj składnik</button>`;
|
||||
return;
|
||||
}
|
||||
const recipe = RECIPES[S.recipeId];
|
||||
@@ -376,15 +376,15 @@ export function setupMealPlanEditor() {
|
||||
const q = S.addQuery.toLowerCase().trim();
|
||||
const avail = Object.values(INGREDIENTS).filter((i) => !usedIds.has(i.id) && (!q || i.name.toLowerCase().includes(q)));
|
||||
el.innerHTML = `
|
||||
<div class="rounded-xl p-3" style="background:#393937 !important; border:1px solid #444442;">
|
||||
<div class="rounded-xl p-3" style="background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--card-strong-rgb));">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<input type="text" id="mpe-add-search" class="flex-1 rounded-lg px-3 py-1.5 text-[12px] outline-none placeholder:text-[#8f8b84]" style="background:#2f2f2d !important; border:1px solid #444442; color:#ddd6ca;" placeholder="Szukaj składnika…" value="${esc(S.addQuery)}">
|
||||
<button type="button" id="mpe-add-cancel" class="text-[11px] font-semibold px-2 py-1 transition-colors" style="color:#9b978f;">Anuluj</button>
|
||||
<input type="text" id="mpe-add-search" class="flex-1 rounded-lg px-3 py-1.5 text-[12px] outline-none placeholder:text-[rgb(var(--text-faint-rgb))]" style="background:rgb(var(--card-soft-rgb)) !important; border:1px solid rgb(var(--card-strong-rgb)); color:rgb(var(--text-body-rgb));" placeholder="Szukaj składnika…" value="${esc(S.addQuery)}">
|
||||
<button type="button" id="mpe-add-cancel" class="text-[11px] font-semibold px-2 py-1 transition-colors" style="color:rgb(var(--text-dim-rgb));">Anuluj</button>
|
||||
</div>
|
||||
<div class="max-h-40 overflow-y-auto space-y-1 no-scrollbar" id="mpe-add-results">
|
||||
${avail.length === 0
|
||||
? '<p class="rounded-lg px-2.5 py-3 text-[11px] text-center" style="background:#2f2f2d !important; color:#9b978f;">Brak wyników</p>'
|
||||
: avail.slice(0, 20).map((i) => `<button type="button" class="mpe-add-pick w-full text-left px-3 py-3 rounded-lg transition-colors text-[12px] font-medium" style="background:#2f2f2d !important; color:#ddd6ca;" data-ing-id="${esc(i.id)}">${esc(i.name)}</button>`).join('')}
|
||||
? '<p class="rounded-lg px-2.5 py-3 text-[11px] text-center" style="background:rgb(var(--card-soft-rgb)) !important; color:rgb(var(--text-dim-rgb));">Brak wyników</p>'
|
||||
: avail.slice(0, 20).map((i) => `<button type="button" class="mpe-add-pick w-full text-left px-3 py-3 rounded-lg transition-colors text-[12px] font-medium" style="background:rgb(var(--card-soft-rgb)) !important; color:rgb(var(--text-body-rgb));" data-ing-id="${esc(i.id)}">${esc(i.name)}</button>`).join('')}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -400,8 +400,8 @@ export function setupMealPlanEditor() {
|
||||
const q = S.addQuery.toLowerCase().trim();
|
||||
const avail = Object.values(INGREDIENTS).filter((i) => !usedIds.has(i.id) && (!q || i.name.toLowerCase().includes(q)));
|
||||
results.innerHTML = avail.length === 0
|
||||
? '<p class="rounded-lg px-2.5 py-3 text-[11px] text-center" style="background:#2f2f2d !important; color:#9b978f;">Brak wyników</p>'
|
||||
: avail.slice(0, 20).map((i) => `<button type="button" class="mpe-add-pick w-full text-left px-3 py-3 rounded-lg transition-colors text-[12px] font-medium" style="background:#2f2f2d !important; color:#ddd6ca;" data-ing-id="${esc(i.id)}">${esc(i.name)}</button>`).join('');
|
||||
? '<p class="rounded-lg px-2.5 py-3 text-[11px] text-center" style="background:rgb(var(--card-soft-rgb)) !important; color:rgb(var(--text-dim-rgb));">Brak wyników</p>'
|
||||
: avail.slice(0, 20).map((i) => `<button type="button" class="mpe-add-pick w-full text-left px-3 py-3 rounded-lg transition-colors text-[12px] font-medium" style="background:rgb(var(--card-soft-rgb)) !important; color:rgb(var(--text-body-rgb));" data-ing-id="${esc(i.id)}">${esc(i.name)}</button>`).join('');
|
||||
}
|
||||
|
||||
function renderIngredients() {
|
||||
@@ -417,23 +417,23 @@ export function setupMealPlanEditor() {
|
||||
if (!el) return;
|
||||
const n = totalNutrition();
|
||||
el.innerHTML = `
|
||||
<div class="h-full pb-2 flex flex-col" style="background:#2d2e2b !important; background-image:none !important; box-shadow:none !important;">
|
||||
<div class="h-full pb-2 flex flex-col" style="background:rgb(var(--app-bg-rgb)) !important; background-image:none !important; box-shadow:none !important;">
|
||||
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-wider mb-2">Wartości odżywcze</p>
|
||||
<div class="flex-1 flex items-center">
|
||||
<div class="grid grid-cols-4 gap-1.5 w-full">
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-gray-100 tabular-nums leading-tight">${n.kcal}</p>
|
||||
<p class="text-[9px] text-gray-500 font-medium">kcal</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-blue-400 tabular-nums leading-tight">${n.protein}g</p>
|
||||
<p class="text-[9px] text-gray-500 font-medium">białko</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-amber-400 tabular-nums leading-tight">${n.fat}g</p>
|
||||
<p class="text-[9px] text-gray-500 font-medium">tłuszcz</p>
|
||||
</div>
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:#393937;">
|
||||
<div class="rounded-xl px-2 py-[0.5625rem] text-center" style="background:rgb(var(--card-rgb));">
|
||||
<p class="text-[15px] font-bold text-orange-400 tabular-nums leading-tight">${n.carbs}g</p>
|
||||
<p class="text-[9px] text-gray-500 font-medium">węglowodany</p>
|
||||
</div>
|
||||
@@ -753,7 +753,7 @@ export function setupMealPlanEditor() {
|
||||
const ingBase = S.overrides[origId] ?? recipeIng?.amount ?? 0;
|
||||
const ingDisp = ingBase * S.servings;
|
||||
|
||||
const checkmark = (sel) => `<span class="ml-auto self-center w-[18px] h-[18px] rounded-full shrink-0 flex items-center justify-center" style="border:1.5px solid #56534f; background:transparent;">${sel ? '<i class="fas fa-check" style="color:#9b978f; font-size:8px; line-height:1; display:block; transform:translateY(0.5px);"></i>' : ''}</span>`;
|
||||
const checkmark = (sel) => `<span class="ml-auto self-center w-[18px] h-[18px] rounded-full shrink-0 flex items-center justify-center" style="border:1.5px solid rgba(var(--border-input-rgb), 0.58); background:transparent;">${sel ? '<i class="fas fa-check" style="color:rgb(var(--text-dim-rgb)); font-size:8px; line-height:1; display:block; transform:translateY(0.5px);"></i>' : ''}</span>`;
|
||||
|
||||
let pickerHtml = '<div class="mpe-product-picker mt-2 ml-1 space-y-1">';
|
||||
for (const p of products) {
|
||||
@@ -766,7 +766,7 @@ export function setupMealPlanEditor() {
|
||||
const f = g / 100;
|
||||
const n = pNut ? { kcal: Math.round(pNut.kcal * f), protein: Math.round(pNut.protein * f * 10) / 10, fat: Math.round(pNut.fat * f * 10) / 10, carbs: Math.round(pNut.carbs * f * 10) / 10 } : null;
|
||||
const nLine = n ? `<div class="text-[10px] text-gray-400 mt-0.5 tabular-nums">${n.kcal} kcal · ${n.protein}g B · ${n.fat}g T · ${n.carbs}g W</div>` : '';
|
||||
pickerHtml += `<button type="button" class="mpe-prod-pick w-full text-left p-2.5 rounded-lg transition-all" style="background:#2f2f2d !important; background-image:none !important; border:none !important; box-shadow:none !important;" data-eid="${esc(eid)}" data-prod-id="${esc(p.id)}">
|
||||
pickerHtml += `<button type="button" class="mpe-prod-pick w-full text-left p-2.5 rounded-lg transition-all" style="background:rgb(var(--card-soft-rgb)) !important; background-image:none !important; border:none !important; box-shadow:none !important;" data-eid="${esc(eid)}" data-prod-id="${esc(p.id)}">
|
||||
<div class="flex items-center gap-3"><div class="min-w-0 flex-1"><div class="text-[11px] font-semibold text-gray-900">${esc(p.name)}</div>${nLine}</div>${checkmark(isSel)}</div>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
@@ -33,22 +33,22 @@ 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-[#393937] cursor-pointer text-left transition-shadow" style="background:#393937 !important; border:none !important; box-shadow:0 2px 8px rgba(0,0,0,0.28) !important;">
|
||||
<div class="recipe-browser-card-media h-32 bg-[#d4d4d4] relative overflow-hidden">
|
||||
<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;">
|
||||
<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">`
|
||||
: `<span class="absolute inset-0 flex items-center justify-center text-white font-medium text-xs">${escapeHtml(recipe.thumbLabel)}</span>`}
|
||||
</div>
|
||||
<div class="recipe-browser-card-body p-3 flex flex-col flex-1">
|
||||
<h3 class="recipe-browser-card-title text-sm font-medium underline decoration-1 underline-offset-2 text-[#f1ede4] mb-3 line-clamp-2">${escapeHtml(recipe.title)}</h3>
|
||||
<h3 class="recipe-browser-card-title text-sm font-medium underline decoration-1 underline-offset-2 text-[rgb(var(--text-primary-rgb))] mb-3 line-clamp-2">${escapeHtml(recipe.title)}</h3>
|
||||
<div class="recipe-browser-card-footer mt-auto">
|
||||
<div class="recipe-browser-card-meta flex items-center justify-between text-[11px] text-[#c2bcb2] font-medium mb-2">
|
||||
<div class="flex items-center gap-1"><i class="fas fa-clock text-[#8f8b84]" aria-hidden="true"></i><span>${recipe.minutes} min</span></div>
|
||||
<div class="flex items-center gap-1"><i class="fas fa-fire text-[#8f8b84]" aria-hidden="true"></i><span>${recipe.nutritionPerServing.kcal} kcal</span></div>
|
||||
<div class="recipe-browser-card-meta flex items-center justify-between text-[11px] text-[rgb(var(--text-muted-rgb))] font-medium mb-2">
|
||||
<div class="flex items-center gap-1"><i class="fas fa-clock text-[rgb(var(--text-faint-rgb))]" aria-hidden="true"></i><span>${recipe.minutes} min</span></div>
|
||||
<div class="flex items-center gap-1"><i class="fas fa-fire text-[rgb(var(--text-faint-rgb))]" aria-hidden="true"></i><span>${recipe.nutritionPerServing.kcal} kcal</span></div>
|
||||
</div>
|
||||
${labels.length > 0
|
||||
? `<div class="recipe-browser-card-labels flex flex-wrap gap-1">
|
||||
${labels.map((label) => `<span class="recipe-browser-card-label px-2 py-0.5 bg-[#2f2f2d] text-[#d7d2c8] text-[10px] rounded-md font-medium">${escapeHtml(label)}</span>`).join('')}
|
||||
${labels.map((label) => `<span class="recipe-browser-card-label px-2 py-0.5 bg-[rgb(var(--card-soft-rgb))] text-[rgb(var(--text-body-soft-rgb))] text-[10px] rounded-md font-medium">${escapeHtml(label)}</span>`).join('')}
|
||||
</div>`
|
||||
: ''}
|
||||
</div>
|
||||
@@ -71,14 +71,14 @@ export function getRecipeGridSectionHTML({
|
||||
scrollId,
|
||||
gridId,
|
||||
emptyStateId,
|
||||
scrollClassName = 'relative flex-1 overflow-y-auto px-4 pt-20 pb-24 bg-[#2d2e2b]',
|
||||
gridClassName = 'grid grid-cols-2 gap-3 bg-[#2d2e2b]',
|
||||
scrollClassName = 'relative flex-1 overflow-y-auto px-4 pt-20 pb-24 bg-[rgb(var(--app-bg-rgb))]',
|
||||
gridClassName = 'grid grid-cols-2 gap-3 bg-[rgb(var(--app-bg-rgb))]',
|
||||
emptyTitle = 'Brak wyników',
|
||||
emptyMessage = 'Zmień kryteria wyszukiwania lub filtry',
|
||||
} = {}) {
|
||||
return `
|
||||
<div id="${escapeHtml(scrollId)}" class="${scrollClassName}" style="background:#2d2e2b !important;">
|
||||
<div id="${escapeHtml(gridId)}" class="${gridClassName}" style="background:#2d2e2b !important;"></div>
|
||||
<div id="${escapeHtml(scrollId)}" class="${scrollClassName}" style="background:rgb(var(--app-bg-rgb)) !important;">
|
||||
<div id="${escapeHtml(gridId)}" class="${gridClassName}" style="background:rgb(var(--app-bg-rgb)) !important;"></div>
|
||||
${getEmptyStateHTML({
|
||||
emptyStateId,
|
||||
title: emptyTitle,
|
||||
|
||||
@@ -27,11 +27,11 @@ export function getRecipeSearchFieldHTML({
|
||||
const ariaLabel = inputAriaLabel || placeholder;
|
||||
|
||||
return `
|
||||
<div id="${escapeHtml(shellId)}" class="relative z-[1] mx-auto flex items-center w-full overflow-hidden" style="width:min(calc(100% - 0.5rem), 22.4rem); background:#393937 !important; border:1px solid #41423f !important; border-radius:999px !important; box-shadow:${RECIPE_SEARCH_SHELL_BASE_SHADOW} !important; transition:box-shadow 180ms ease;">
|
||||
<div id="${escapeHtml(shellId)}" class="relative z-[1] mx-auto flex items-center w-full overflow-hidden" style="width:min(calc(100% - 0.5rem), 22.4rem); background:rgb(var(--card-rgb)) !important; border:1px solid rgb(var(--border-card-rgb)) !important; border-radius:999px !important; box-shadow:${RECIPE_SEARCH_SHELL_BASE_SHADOW} !important; transition:box-shadow 180ms ease;">
|
||||
<input type="text" id="${escapeHtml(inputId)}" value="${escapeHtml(inputValue)}" placeholder="${escapeHtml(placeholder)}" aria-label="${escapeHtml(ariaLabel)}" class="w-full bg-transparent outline-none text-[15px] text-center py-[12px] ${inputPadding}" style="background:transparent !important; border:none !important; box-shadow:none !important; backdrop-filter:none !important;">
|
||||
${hasFilterButton
|
||||
? `
|
||||
<button id="${escapeHtml(filterButtonId)}"${actionAttr} class="absolute right-2 top-1/2 -translate-y-1/2 w-9 h-9 text-[#c9c3b8] hover:text-[#f0e8dc] flex items-center justify-center transition-colors" style="background:transparent !important; border:none !important; box-shadow:none !important;" aria-label="${escapeHtml(filterButtonLabel)}">
|
||||
<button id="${escapeHtml(filterButtonId)}"${actionAttr} class="absolute right-2 top-1/2 -translate-y-1/2 w-9 h-9 text-[rgb(var(--text-body-soft-rgb))] hover:text-[rgb(var(--text-emphasis-rgb))] flex items-center justify-center transition-colors" style="background:transparent !important; border:none !important; box-shadow:none !important;" aria-label="${escapeHtml(filterButtonLabel)}">
|
||||
<i class="fas fa-sliders-h" aria-hidden="true"></i>
|
||||
</button>`
|
||||
: ''}
|
||||
|
||||
Reference in New Issue
Block a user