From 7b0ece67503cd08740e5f020c38d4abf565ef301 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 30 Jan 2026 22:54:39 +0000 Subject: [PATCH] add list --- assets/css/custom.css | 37 +++++++++++++++++ assets/js/main.js | 94 ++++++++++++++++++++++++++++++++++++------- index.php | 4 +- 3 files changed, 119 insertions(+), 16 deletions(-) diff --git a/assets/css/custom.css b/assets/css/custom.css index ae9a54b..4e3b297 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -294,6 +294,43 @@ footer { padding: 20px 24px; } +/* Recipe Card Selection */ +.recipe-selection-card { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border: 2px solid transparent; +} + +.recipe-selection-card.selected { + border-color: var(--brand-primary); + box-shadow: 0 15px 45px rgba(45, 106, 79, 0.15); + background-color: #F7FAF9; +} + +.recipe-selection-card .select-recipe:checked { + background-color: var(--brand-primary); + border-color: var(--brand-primary); +} + +.recipe-controls { + border: 1px solid #EAEAEA; + transition: all 0.3s ease; +} + +.recipe-selection-card.selected .recipe-controls { + background-color: #ffffff !important; + border-color: var(--brand-primary); +} + +.recipe-selection-card .form-check-input { + width: 1.5em; + height: 1.5em; +} + +.recipe-selection-card .form-check-label { + cursor: pointer; + user-select: none; +} + /* Category Label */ .recipe-category-label { background-color: #E9F5EF; diff --git a/assets/js/main.js b/assets/js/main.js index 40a60e3..3a2bf09 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -5,6 +5,7 @@ const app = { confirmedRecipeProducts: [], checkedItems: [], additionalProducts: [], + selectedRecipeIds: [], user: null }, api: { @@ -18,6 +19,7 @@ const app = { app.state.checkedItems = data.user.shopping_list.checkedItems || []; app.state.additionalProducts = data.user.shopping_list.additionalProducts || []; app.state.confirmedRecipeProducts = data.user.shopping_list.confirmedRecipeProducts || []; + app.state.selectedRecipeIds = data.user.shopping_list.selectedRecipeIds || []; } } else { app.state.user = null; @@ -36,7 +38,8 @@ const app = { shopping_list: { checkedItems: app.state.checkedItems, additionalProducts: app.state.additionalProducts, - confirmedRecipeProducts: app.state.confirmedRecipeProducts + confirmedRecipeProducts: app.state.confirmedRecipeProducts, + selectedRecipeIds: app.state.selectedRecipeIds } }) }); @@ -141,9 +144,20 @@ const app = { }); const data = await response.json(); if (data.success) { + // Remove from selectedRecipeIds if present + const index = app.state.selectedRecipeIds.indexOf(id.toString()); + if (index > -1) { + app.state.selectedRecipeIds.splice(index, 1); + } + const indexNum = app.state.selectedRecipeIds.indexOf(Number(id)); + if (indexNum > -1) { + app.state.selectedRecipeIds.splice(indexNum, 1); + } + await app.api.getRecipes(); app.ui.renderRecipeCards(app.state.recipes); app.ui.updateShoppingList(); + app.api.saveShoppingList(); } else { alert('Failed to delete recipe: ' + data.error); } @@ -166,8 +180,10 @@ const app = { cardCol.setAttribute('data-id', recipe.id); cardCol.style.animationDelay = `${index * 0.1}s`; + const isSelected = app.state.selectedRecipeIds.includes(recipe.id.toString()) || app.state.selectedRecipeIds.includes(Number(recipe.id)); + const card = document.createElement('div'); - card.className = 'card h-100'; + card.className = `card h-100 recipe-selection-card ${isSelected ? 'selected' : ''}`; if (recipe.image_url) { const img = document.createElement('img'); @@ -183,10 +199,15 @@ const app = { const titleWrapper = document.createElement('div'); titleWrapper.className = 'd-flex justify-content-between align-items-start mb-2 gap-2'; - const title = document.createElement('h5'); - title.className = 'card-title mb-0'; - title.textContent = recipe.name; - titleWrapper.appendChild(title); + const selectionWrapper = document.createElement('div'); + selectionWrapper.className = 'form-check mb-0'; + selectionWrapper.innerHTML = ` + + + `; + titleWrapper.appendChild(selectionWrapper); if (recipe.category) { const categoryLabel = document.createElement('div'); @@ -199,19 +220,35 @@ const app = { } const text = document.createElement('p'); - text.className = 'card-text text-muted'; + text.className = 'card-text text-muted mb-3'; text.textContent = `${recipe.ingredients.length} ingredients`; + const controlsWrapper = document.createElement('div'); + controlsWrapper.className = 'recipe-controls mb-3 p-2 bg-light rounded'; + controlsWrapper.innerHTML = ` +
+
+ + +
+
+ + +
+
+ `; + const buttonGroup = document.createElement('div'); - buttonGroup.className = 'mt-auto pt-2'; + buttonGroup.className = 'mt-auto pt-2 d-flex gap-2'; buttonGroup.innerHTML = ` - - - + + + `; cardBody.appendChild(titleWrapper); cardBody.appendChild(text); + cardBody.appendChild(controlsWrapper); cardBody.appendChild(buttonGroup); card.appendChild(cardBody); cardCol.appendChild(card); @@ -223,6 +260,11 @@ const app = { // 1. Process recipe ingredients and calculate total based on per-recipe inputs app.state.recipes.forEach(recipe => { + // Only include if selected + if (!app.state.selectedRecipeIds.includes(recipe.id.toString()) && !app.state.selectedRecipeIds.includes(Number(recipe.id))) { + return; + } + const card = app.dom.recipeCardsContainer.querySelector(`[data-id="${recipe.id}"]`); if (!card) return; @@ -699,10 +741,34 @@ const app = { app.dom.recipeCardsContainer.addEventListener('click', function(e) { const target = e.target.closest('button'); - const card = e.target.closest('.col-12[data-id]'); - if (!card) return; + const checkbox = e.target.closest('.select-recipe'); + const cardCol = e.target.closest('.col-12[data-id]'); + if (!cardCol) return; - const recipeId = card.getAttribute('data-id'); + const recipeId = cardCol.getAttribute('data-id'); + + if (checkbox) { + const card = cardCol.querySelector('.card'); + if (checkbox.checked) { + if (!app.state.selectedRecipeIds.includes(recipeId)) { + app.state.selectedRecipeIds.push(recipeId); + } + card.classList.add('selected'); + } else { + const index = app.state.selectedRecipeIds.indexOf(recipeId); + if (index > -1) { + app.state.selectedRecipeIds.splice(index, 1); + } + const indexNum = app.state.selectedRecipeIds.indexOf(Number(recipeId)); + if (indexNum > -1) { + app.state.selectedRecipeIds.splice(indexNum, 1); + } + card.classList.remove('selected'); + } + app.ui.updateShoppingList(); + app.api.saveShoppingList(); + return; // Don't trigger other actions + } if (target && target.classList.contains('delete-recipe')) { if (confirm('Are you sure you want to delete this recipe?')) { diff --git a/index.php b/index.php index f6b4895..3696c5f 100644 --- a/index.php +++ b/index.php @@ -27,7 +27,7 @@ - + @@ -380,7 +380,7 @@ - +