Removable ingredients in planner
This commit is contained in:
@@ -3,7 +3,7 @@ import { getFilterHTML, setupFilter } from './views/Filter.js?v=2';
|
||||
import { getRecipeDetailHTML, setupRecipeDetail } from './views/RecipeDetailV2.js?v=2';
|
||||
import { getMealPlannerHTML, setupMealPlanner } from './views/MealPlanner.js?v=2';
|
||||
import { getPantryHTML, refreshPantry, setupPantry } from './views/Pantry.js?v=2';
|
||||
import { getMealPlanEditorHTML, setupMealPlanEditor } from './ui/mealPlanEditor.js?v=2';
|
||||
import { getMealPlanEditorHTML, setupMealPlanEditor } from './ui/mealPlanEditor.js?v=3';
|
||||
|
||||
function getAppToastHTML() {
|
||||
return `
|
||||
|
||||
@@ -61,13 +61,13 @@ export function getMealPlanEditorHTML() {
|
||||
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-wider mt-3 mb-2">Pora posiłku</p>
|
||||
<div id="mpe-slot-chips" class="flex flex-wrap gap-1.5"></div>
|
||||
</div>
|
||||
<div id="mpe-nutrition-section" class="mb-4"></div>
|
||||
<div id="mpe-servings-row" class="flex items-center justify-between mb-4"></div>
|
||||
<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>
|
||||
<div id="mpe-add-area" class="mt-2"></div>
|
||||
</div>
|
||||
<div id="mpe-nutrition-section"></div>
|
||||
</div>
|
||||
<div class="shrink-0 px-5 pb-8 pt-3 border-t border-gray-100">
|
||||
<button id="mpe-confirm-btn" type="button" class="w-full bg-gray-900 hover:bg-black text-white py-3 rounded-xl font-semibold text-[13px] transition-colors flex items-center justify-center gap-2">
|
||||
@@ -230,9 +230,13 @@ export function setupMealPlanEditor() {
|
||||
if (!r) return;
|
||||
let html = '';
|
||||
|
||||
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>`;
|
||||
|
||||
for (const ing of r.ingredients) {
|
||||
const id = ing.ingredientId;
|
||||
const excl = S.excluded.has(id);
|
||||
if (S.excluded.has(id)) continue;
|
||||
|
||||
const eid = S.subs[id] || id;
|
||||
const eDef = INGREDIENTS[eid];
|
||||
const eName = eDef?.name || eid;
|
||||
@@ -243,34 +247,26 @@ export function setupMealPlanEditor() {
|
||||
const disp = base * S.servings;
|
||||
const modified = id in S.overrides;
|
||||
|
||||
const checkCls = excl
|
||||
? 'w-5 h-5 rounded-md border-2 border-gray-300 bg-white'
|
||||
: 'w-5 h-5 rounded-md border-2 border-gray-900 bg-gray-900';
|
||||
const checkIco = excl ? '' : '<i class="fas fa-check text-white text-[8px]"></i>';
|
||||
const rowBorder = excl ? 'border-gray-100' : swapped ? 'border-amber-200' : 'border-gray-200';
|
||||
const rowBg = excl ? 'bg-gray-50/50' : swapped ? 'bg-amber-50/30' : 'bg-white';
|
||||
const rowOp = excl ? 'opacity-50' : '';
|
||||
const nameCls = excl ? 'text-[12px] font-semibold text-gray-400 line-through' : 'text-[12px] font-semibold text-gray-900';
|
||||
const amtCls = excl ? 'text-gray-300' : 'text-gray-900';
|
||||
const unitCls = excl ? 'text-gray-300' : 'text-gray-500';
|
||||
const rowBorder = swapped ? 'border-amber-200' : 'border-gray-200';
|
||||
const rowBg = swapped ? 'bg-amber-50/30' : 'bg-white';
|
||||
|
||||
const shuffleBtn = hasAlts && !excl
|
||||
const shuffleBtn = hasAlts
|
||||
? `<button type="button" class="mpe-shuffle shrink-0 w-5 h-5 rounded-full ${swapped ? 'bg-amber-50 text-amber-500' : 'bg-gray-100 text-gray-400 hover:bg-gray-200'} flex items-center justify-center transition-colors" data-orig-id="${esc(id)}"><i class="fas fa-shuffle text-[8px]"></i></button>`
|
||||
: '';
|
||||
const modDot = modified && !excl ? '<span class="w-1.5 h-1.5 rounded-full bg-amber-400 shrink-0"></span>' : '';
|
||||
const modDot = modified ? '<span class="w-1.5 h-1.5 rounded-full bg-amber-400 shrink-0"></span>' : '';
|
||||
|
||||
html += `<div class="mpe-ing-row rounded-xl border ${rowBorder} ${rowBg} ${rowOp} p-2.5" data-orig-id="${esc(id)}" data-type="recipe">`;
|
||||
html += `<div class="flex items-center gap-2.5">`;
|
||||
html += `<button type="button" class="mpe-toggle ${checkCls} flex items-center justify-center shrink-0" data-orig-id="${esc(id)}">${checkIco}</button>`;
|
||||
html += `<div class="flex-1 min-w-0 flex items-center gap-1.5"><span class="${nameCls} truncate">${esc(eName)}</span>${shuffleBtn}</div>`;
|
||||
html += `<button type="button" class="mpe-edit-amt shrink-0 flex items-center gap-1 px-2 py-1 rounded-lg ${excl ? '' : 'hover:bg-gray-100'} transition-colors" data-orig-id="${esc(id)}" data-type="recipe" ${excl ? 'disabled' : ''}>`;
|
||||
html += `${modDot}<span class="text-[12px] font-semibold ${amtCls} tabular-nums">${fmtAmt(disp)}</span>`;
|
||||
html += `<span class="text-[11px] ${unitCls}">${esc(ing.unit)}</span></button>`;
|
||||
html += `<div class="mpe-ing-row rounded-xl border ${rowBorder} ${rowBg} p-2.5" data-orig-id="${esc(id)}" data-type="recipe">`;
|
||||
html += `<div class="flex items-center gap-2">`;
|
||||
html += `<div class="flex-1 min-w-0 flex items-center gap-1.5"><span class="text-[12px] font-semibold text-gray-900 truncate">${esc(eName)}</span>${shuffleBtn}</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-orig-id="${esc(id)}" data-type="recipe">`;
|
||||
html += `${modDot}<span class="text-[12px] font-semibold text-gray-900 tabular-nums">${fmtAmt(disp)}</span>`;
|
||||
html += `<span class="text-[11px] text-gray-500">${esc(ing.unit)}</span></button>`;
|
||||
html += removeBtn('mpe-remove-ing', `data-orig-id="${esc(id)}" data-type="recipe"`);
|
||||
html += `</div>`;
|
||||
|
||||
if (hasAlts && altOpen && !excl) {
|
||||
if (hasAlts && altOpen) {
|
||||
const opts = [id, ...ing.alternatives];
|
||||
html += '<div class="mt-2 ml-7 space-y-1">';
|
||||
html += '<div class="mt-2 ml-1 space-y-1">';
|
||||
for (const altId of opts) {
|
||||
const def = INGREDIENTS[altId];
|
||||
const name = def?.name || altId;
|
||||
@@ -293,17 +289,23 @@ export function setupMealPlanEditor() {
|
||||
const def = INGREDIENTS[a.ingredientId];
|
||||
const name = def?.name || a.ingredientId;
|
||||
const disp = a.amount * S.servings;
|
||||
html += `<div class="mpe-ing-row rounded-xl border border-emerald-200 bg-emerald-50/30 p-2.5" data-ing-id="${esc(a.ingredientId)}" data-type="added">
|
||||
<div class="flex items-center gap-2.5">
|
||||
<span class="shrink-0 w-5 h-5 rounded-md bg-emerald-100 flex items-center justify-center text-emerald-600"><i class="fas fa-plus text-[8px]"></i></span>
|
||||
<span class="flex-1 min-w-0 text-[12px] font-semibold text-gray-900 truncate">${esc(name)}</span>
|
||||
<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">
|
||||
<span class="text-[12px] font-semibold text-gray-900 tabular-nums">${fmtAmt(disp)}</span>
|
||||
<span class="text-[11px] text-gray-500">${esc(a.unit)}</span>
|
||||
</button>
|
||||
<button type="button" class="mpe-remove-added shrink-0 w-6 h-6 rounded-full border border-gray-200 text-gray-400 hover:text-red-600 hover:border-red-200 hover:bg-red-50 flex items-center justify-center transition-colors" data-ing-id="${esc(a.ingredientId)}"><i class="fas fa-times text-[8px]"></i></button>
|
||||
</div>
|
||||
</div>`;
|
||||
html += `<div class="mpe-ing-row rounded-xl border border-dashed border-gray-300 bg-white p-2.5" data-ing-id="${esc(a.ingredientId)}" data-type="added">`;
|
||||
html += `<div class="flex items-center gap-2">`;
|
||||
html += `<div class="flex-1 min-w-0 flex items-center gap-1.5"><span class="text-[12px] font-semibold text-gray-900 truncate">${esc(name)}</span><span class="text-[9px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-400 font-medium shrink-0">Dodany</span></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>`;
|
||||
html += removeBtn('mpe-remove-ing', `data-ing-id="${esc(a.ingredientId)}" data-type="added"`);
|
||||
html += `</div></div>`;
|
||||
}
|
||||
|
||||
if (S.excluded.size > 0) {
|
||||
const cnt = S.excluded.size;
|
||||
const label = cnt === 1 ? '1 składnik usunięty' : cnt < 5 ? `${cnt} składniki usunięte` : `${cnt} składników usuniętych`;
|
||||
html += `<div class="flex items-center justify-between py-2 px-1">`;
|
||||
html += `<span class="text-[11px] text-gray-400">${label}</span>`;
|
||||
html += `<button type="button" id="mpe-restore-all" class="text-[11px] font-semibold text-gray-500 hover:text-gray-900 transition-colors">Przywróć</button>`;
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
list.innerHTML = html;
|
||||
@@ -515,10 +517,19 @@ export function setupMealPlanEditor() {
|
||||
const ingSec = document.getElementById('mpe-ing-section');
|
||||
|
||||
ingSec?.addEventListener('click', (e) => {
|
||||
const toggle = e.target.closest('.mpe-toggle');
|
||||
if (toggle) {
|
||||
const id = toggle.dataset.origId;
|
||||
if (S.excluded.has(id)) S.excluded.delete(id); else S.excluded.add(id);
|
||||
const remove = e.target.closest('.mpe-remove-ing');
|
||||
if (remove) {
|
||||
if (remove.dataset.type === 'added') {
|
||||
S.added = S.added.filter((a) => a.ingredientId !== remove.dataset.ingId);
|
||||
} else {
|
||||
S.excluded.add(remove.dataset.origId);
|
||||
}
|
||||
renderIngredients(); renderNutrition();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.closest('#mpe-restore-all')) {
|
||||
S.excluded.clear();
|
||||
renderIngredients(); renderNutrition();
|
||||
return;
|
||||
}
|
||||
@@ -547,13 +558,6 @@ export function setupMealPlanEditor() {
|
||||
return;
|
||||
}
|
||||
|
||||
const removeAdded = e.target.closest('.mpe-remove-added');
|
||||
if (removeAdded) {
|
||||
S.added = S.added.filter((a) => a.ingredientId !== removeAdded.dataset.ingId);
|
||||
renderIngredients(); renderNutrition();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.closest('#mpe-add-btn')) {
|
||||
S.addOpen = true; S.addQuery = '';
|
||||
renderAddArea();
|
||||
|
||||
Reference in New Issue
Block a user