Make ingredient cards flexible
Some checks failed
Build and Deploy / build-and-push (push) Failing after 1m21s

This commit is contained in:
2026-04-17 00:05:02 +02:00
parent 8ed15bbe36
commit f533db1743

View File

@@ -554,9 +554,10 @@ function classifyIngredients(searchQuery) {
name: def.name,
qty: getPantryTotal(id, pantry),
unit: def.pantryUnit,
icon: CATEGORY_ICONS[def.category] || 'fa-jar',
};
})
.sort((a, b) => a.name.localeCompare(b.name, 'pl'));
.sort((a, b) => a.name.length - b.name.length);
return { shortfalls, sufficient, notPlanned };
}
@@ -564,49 +565,53 @@ function classifyIngredients(searchQuery) {
/* ══════════════════════ TILE RENDERING ══════════════════════ */
function shortfallTileHtml(item) {
const dayCtx = formatDayContext(item.days);
const clamp = item.name.length > 25 ? ' min-w-0' : '';
return `
<button type="button" class="pv2-tile w-full text-left rounded-2xl flex items-center gap-3 px-3 py-3 transition-all active:scale-[0.99] mb-2" style="background:#393937; border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
<div class="w-10 h-10 rounded-xl flex items-center justify-center shrink-0" style="background:#2f2f2d;">
<i class="fas ${item.icon} text-[17px]" style="color:${SHORTFALL_ACCENT};"></i>
<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 6rem; background:#393937; border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
<div class="flex items-center gap-1.5 min-w-0">
<div class="w-6 h-6 rounded-md flex items-center justify-center shrink-0" style="background:#2f2f2d;">
<i class="fas ${item.icon} text-[11px]" style="color:${SHORTFALL_ACCENT};"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-[13px] font-normal leading-tight truncate mb-1.5" style="color:#ddd6ca;">${esc(item.name)}</p>
<div class="flex items-center gap-2">
<div class="flex-1 h-2 rounded-full overflow-hidden" style="background:#2a2a28;">
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:#ddd6ca;">${esc(item.name)}</p>
</div>
<div class="w-full flex flex-col gap-1">
<div class="w-full h-1 rounded-full overflow-hidden" style="background:#2a2a28;">
<div class="h-full rounded-full" style="width:${item.fillPct}%; background:${SHORTFALL_ACCENT};"></div>
</div>
<span class="text-[11px] font-semibold tabular-nums shrink-0" style="color:#ddd6ca;">${esc(formatQty(item.pantryQty))} <span class="font-medium text-[10px]" style="color:#9b978f;">/ ${esc(formatQty(item.needed))} ${esc(unitLabel(item.unit))}</span></span>
</div>
<span class="text-[10px] font-semibold tabular-nums" style="color:#ddd6ca;">${esc(formatQty(item.pantryQty))} <span class="font-medium" style="color:#9b978f;">/ ${esc(formatQty(item.needed))} ${esc(unitLabel(item.unit))}</span></span>
</div>
</button>`;
}
function sufficientTileHtml(item) {
const dayCtx = formatDayContext(item.days);
const clamp = item.name.length > 25 ? ' min-w-0' : '';
return `
<button type="button" class="pv2-tile w-full text-left rounded-2xl flex items-center gap-3 px-3 py-3 transition-all active:scale-[0.99] mb-2" style="background:#393937; border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
<div class="w-10 h-10 rounded-xl flex items-center justify-center shrink-0" style="background:#2f2f2d;">
<i class="fas ${item.icon} text-[17px]" style="color:#6ee7b7;"></i>
<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 6rem; background:#393937; border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
<div class="flex items-center gap-1.5 min-w-0">
<div class="w-6 h-6 rounded-md flex items-center justify-center shrink-0" style="background:#2f2f2d;">
<i class="fas ${item.icon} text-[11px]" style="color:#6ee7b7;"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-[13px] font-normal leading-tight truncate mb-1.5" style="color:#ddd6ca;">${esc(item.name)}</p>
<div class="flex items-center gap-2">
<div class="flex-1 h-2 rounded-full overflow-hidden" style="background:#2a2a28;">
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:#ddd6ca;">${esc(item.name)}</p>
</div>
<div class="w-full flex flex-col gap-1">
<div class="w-full h-1 rounded-full overflow-hidden" style="background:#2a2a28;">
<div class="h-full rounded-full" style="width:100%; background:#6ee7b7;"></div>
</div>
<span class="text-[11px] font-semibold tabular-nums shrink-0" style="color:#6ee7b7;">${esc(formatQty(item.pantryQty))} <span class="font-medium text-[10px]" style="color:#9b978f;">/ ${esc(formatQty(item.needed))} ${esc(unitLabel(item.unit))}</span></span>
</div>
<span class="text-[10px] font-semibold tabular-nums" style="color:#6ee7b7;">${esc(formatQty(item.pantryQty))} <span class="font-medium" style="color:#9b978f;">/ ${esc(formatQty(item.needed))} ${esc(unitLabel(item.unit))}</span></span>
</div>
</button>`;
}
function notPlannedChipHtml(item) {
const hasStock = item.qty > 0;
const clamp = item.name.length > 25 ? ' min-w-0' : '';
return `
<button type="button" class="pv2-tile rounded-xl px-3 py-2 flex items-center gap-2 transition-all active:scale-[0.98] overflow-hidden" style="background:#333331; border:none; box-shadow:0 1px 4px rgba(0,0,0,0.22); max-width:100%;" data-id="${esc(item.ingredientId)}">
<span class="text-[11px] font-normal truncate min-w-0" style="color:${hasStock ? '#b7ada1' : '#9b978f'};">${esc(item.name)}</span>
<span class="text-[11px] font-semibold tabular-nums shrink-0" style="color:${hasStock ? '#9b978f' : '#6d6c67'};">${esc(formatQty(item.qty))} ${esc(unitLabel(item.unit))}</span>
<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 6rem; background:#393937; border:none; box-shadow:0 2px 8px rgba(0,0,0,0.28);" data-id="${esc(item.ingredientId)}">
<div class="w-6 h-6 rounded-md flex items-center justify-center shrink-0" style="background:#2f2f2d;">
<i class="fas ${item.icon} text-[11px]" style="color:#7d7a74;"></i>
</div>
<p class="text-[11px] font-normal leading-tight truncate min-w-0" style="color:${hasStock ? '#b7ada1' : '#9b978f'};">${esc(item.name)}</p>
<span class="text-[10px] font-semibold tabular-nums shrink-0 ml-auto" style="color:${hasStock ? '#9b978f' : '#6d6c67'};">${esc(formatQty(item.qty))} ${esc(unitLabel(item.unit))}</span>
</button>`;
}
@@ -640,16 +645,18 @@ function renderBoard() {
if (shortfalls.length > 0) {
html += `<section class="mb-5">`;
html += sectionHeaderHtml('fa-exclamation', '#2f2f2d', SHORTFALL_ACCENT, 'Potrzebne', '#7B756D', shortfalls.length);
html += shortfalls.map(shortfallTileHtml).join('');
html += `</section>`;
html += `<div class="flex flex-wrap gap-2">`;
html += shortfalls.sort((a, b) => a.name.length - b.name.length).map(shortfallTileHtml).join('');
html += `</div></section>`;
}
// Section 2: W spiżarni (sufficient)
if (sufficient.length > 0) {
html += `<section class="mb-5">`;
html += sectionHeaderHtml('fa-check', '#1a2e22', '#6ee7b7', 'W spiżarni', '#7B756D', sufficient.length);
html += sufficient.map(sufficientTileHtml).join('');
html += `</section>`;
html += `<div class="flex flex-wrap gap-2">`;
html += sufficient.sort((a, b) => a.name.length - b.name.length).map(sufficientTileHtml).join('');
html += `</div></section>`;
}
// Section 3: Poza planem