diff --git a/images/ingredients/banany.jpg b/images/ingredients/banany.jpg new file mode 100644 index 0000000..2e2d4b3 Binary files /dev/null and b/images/ingredients/banany.jpg differ diff --git a/images/ingredients/borowki_amerykanskie.jpg b/images/ingredients/borowki_amerykanskie.jpg new file mode 100644 index 0000000..81bc213 Binary files /dev/null and b/images/ingredients/borowki_amerykanskie.jpg differ diff --git a/images/ingredients/czosnek.jpg b/images/ingredients/czosnek.jpg new file mode 100644 index 0000000..7e27809 Binary files /dev/null and b/images/ingredients/czosnek.jpg differ diff --git a/images/ingredients/hummus.jpg b/images/ingredients/hummus.jpg new file mode 100644 index 0000000..657a4ce Binary files /dev/null and b/images/ingredients/hummus.jpg differ diff --git a/images/ingredients/jagody.jpg b/images/ingredients/jagody.jpg new file mode 100644 index 0000000..ad557b3 Binary files /dev/null and b/images/ingredients/jagody.jpg differ diff --git a/images/ingredients/jajko.jpg b/images/ingredients/jajko.jpg new file mode 100644 index 0000000..6fbc2c4 Binary files /dev/null and b/images/ingredients/jajko.jpg differ diff --git a/images/ingredients/losos_wedzony.jpg b/images/ingredients/losos_wedzony.jpg new file mode 100644 index 0000000..317998b Binary files /dev/null and b/images/ingredients/losos_wedzony.jpg differ diff --git a/images/ingredients/makaron_suchy.jpg b/images/ingredients/makaron_suchy.jpg new file mode 100644 index 0000000..21ca0d9 Binary files /dev/null and b/images/ingredients/makaron_suchy.jpg differ diff --git a/images/ingredients/migdaly.jpg b/images/ingredients/migdaly.jpg new file mode 100644 index 0000000..629303c Binary files /dev/null and b/images/ingredients/migdaly.jpg differ diff --git a/images/ingredients/ogorek.jpg b/images/ingredients/ogorek.jpg new file mode 100644 index 0000000..32895eb Binary files /dev/null and b/images/ingredients/ogorek.jpg differ diff --git a/images/ingredients/oliwa.jpg b/images/ingredients/oliwa.jpg new file mode 100644 index 0000000..2ea844a Binary files /dev/null and b/images/ingredients/oliwa.jpg differ diff --git a/images/ingredients/papryka_czerwona.jpg b/images/ingredients/papryka_czerwona.jpg new file mode 100644 index 0000000..eb16d43 Binary files /dev/null and b/images/ingredients/papryka_czerwona.jpg differ diff --git a/images/ingredients/pomidor.jpg b/images/ingredients/pomidor.jpg new file mode 100644 index 0000000..5a02209 Binary files /dev/null and b/images/ingredients/pomidor.jpg differ diff --git a/images/ingredients/pomidorki_koktajlowe.jpg b/images/ingredients/pomidorki_koktajlowe.jpg new file mode 100644 index 0000000..356a5b0 Binary files /dev/null and b/images/ingredients/pomidorki_koktajlowe.jpg differ diff --git a/images/ingredients/truskawki.jpg b/images/ingredients/truskawki.jpg new file mode 100644 index 0000000..18232e2 Binary files /dev/null and b/images/ingredients/truskawki.jpg differ diff --git a/js/data/catalog.js b/js/data/catalog.js index c318336..e835793 100644 --- a/js/data/catalog.js +++ b/js/data/catalog.js @@ -19,8 +19,8 @@ export const CATEGORY_LABELS = { /** * @typedef {{ kcal: number, protein: number, fat: number, carbs: number }} NutritionPer100 * @typedef {{ amount: number, label?: string }} PurchasePack - * @typedef {{ id: string, name: string, category: keyof typeof CATEGORY_LABELS, pantryUnit: 'g'|'ml'|'szt', purchasePack?: PurchasePack, nutritionPer100g?: NutritionPer100 }} IngredientDef - * @typedef {{ id: string, ingredientId: string, name: string, brand?: string, packSize: number, packLabel?: string, nutritionPer100g: NutritionPer100 }} ProductDef + * @typedef {{ id: string, name: string, category: keyof typeof CATEGORY_LABELS, pantryUnit: 'g'|'ml'|'szt', purchasePack?: PurchasePack, nutritionPer100g?: NutritionPer100, image?: string }} IngredientDef + * @typedef {{ id: string, ingredientId: string, name: string, brand?: string, packSize: number, packLabel?: string, nutritionPer100g: NutritionPer100, image?: string }} ProductDef */ /** @type {Record} */ @@ -38,6 +38,7 @@ export const INGREDIENTS = { /* ── Nabiał ───────────────────────────────────────── */ jajko: { id: 'jajko', + image: 'images/ingredients/jajko.jpg', name: 'Jajka', category: 'nabial', pantryUnit: 'szt', @@ -103,6 +104,7 @@ export const INGREDIENTS = { }, losos_wedzony: { id: 'losos_wedzony', + image: 'images/ingredients/losos_wedzony.jpg', name: 'Łosoś wędzony', category: 'mieso_ryby', pantryUnit: 'g', @@ -112,6 +114,7 @@ export const INGREDIENTS = { /* ── Warzywa ──────────────────────────────────────── */ pomidor: { id: 'pomidor', + image: 'images/ingredients/pomidor.jpg', name: 'Pomidor', category: 'warzywa', pantryUnit: 'szt', @@ -120,6 +123,7 @@ export const INGREDIENTS = { }, pomidorki_koktajlowe: { id: 'pomidorki_koktajlowe', + image: 'images/ingredients/pomidorki_koktajlowe.jpg', name: 'Pomidorki koktajlowe', category: 'warzywa', pantryUnit: 'g', @@ -128,6 +132,7 @@ export const INGREDIENTS = { }, papryka_czerwona: { id: 'papryka_czerwona', + image: 'images/ingredients/papryka_czerwona.jpg', name: 'Papryka czerwona', category: 'warzywa', pantryUnit: 'szt', @@ -136,6 +141,7 @@ export const INGREDIENTS = { }, ogorek: { id: 'ogorek', + image: 'images/ingredients/ogorek.jpg', name: 'Ogórek', category: 'warzywa', pantryUnit: 'szt', @@ -144,6 +150,7 @@ export const INGREDIENTS = { }, czosnek: { id: 'czosnek', + image: 'images/ingredients/czosnek.jpg', name: 'Czosnek', category: 'warzywa', pantryUnit: 'szt', @@ -160,6 +167,7 @@ export const INGREDIENTS = { /* ── Owoce ────────────────────────────────────────── */ truskawki: { id: 'truskawki', + image: 'images/ingredients/truskawki.jpg', name: 'Truskawki', category: 'owoce', pantryUnit: 'g', @@ -167,6 +175,7 @@ export const INGREDIENTS = { }, borowki_amerykanskie: { id: 'borowki_amerykanskie', + image: 'images/ingredients/borowki_amerykanskie.jpg', name: 'Borówki amerykańskie', category: 'owoce', pantryUnit: 'g', @@ -174,6 +183,7 @@ export const INGREDIENTS = { }, banany: { id: 'banany', + image: 'images/ingredients/banany.jpg', name: 'Banany', category: 'owoce', pantryUnit: 'g', @@ -181,6 +191,7 @@ export const INGREDIENTS = { }, jagody: { id: 'jagody', + image: 'images/ingredients/jagody.jpg', name: 'Jagody', category: 'owoce', pantryUnit: 'g', @@ -196,6 +207,7 @@ export const INGREDIENTS = { /* ── Suche i kasze ────────────────────────────────── */ makaron_suchy: { id: 'makaron_suchy', + image: 'images/ingredients/makaron_suchy.jpg', name: 'Makaron', category: 'suche', pantryUnit: 'g', @@ -231,6 +243,7 @@ export const INGREDIENTS = { }, migdaly: { id: 'migdaly', + image: 'images/ingredients/migdaly.jpg', name: 'Migdały', category: 'suche', pantryUnit: 'g', @@ -289,6 +302,7 @@ export const INGREDIENTS = { }, oliwa: { id: 'oliwa', + image: 'images/ingredients/oliwa.jpg', name: 'Oliwa z oliwek', category: 'inne', pantryUnit: 'ml', @@ -296,6 +310,7 @@ export const INGREDIENTS = { }, hummus: { id: 'hummus', + image: 'images/ingredients/hummus.jpg', name: 'Hummus', category: 'inne', pantryUnit: 'g', diff --git a/js/services/pantryShopping.js b/js/services/pantryShopping.js index 0ff99e0..7ce0c5f 100644 --- a/js/services/pantryShopping.js +++ b/js/services/pantryShopping.js @@ -1,4 +1,4 @@ -import { INGREDIENTS, CATEGORY_LABELS, PRODUCTS, ingredientHasProducts } from '../data/catalog.js?v=6'; +import { INGREDIENTS, CATEGORY_LABELS, PRODUCTS, ingredientHasProducts } from '../data/catalog.js?v=8'; import { PANTRY_STORAGE_KEY, PANTRY_STORAGE_KEY_V2, SHOPPING_STORAGE_KEY } from '../storageKeys.js'; export const KITCHEN_LIST_ID = 'kitchen'; diff --git a/js/services/planIngredients.js b/js/services/planIngredients.js index 0794039..5363c3e 100644 --- a/js/services/planIngredients.js +++ b/js/services/planIngredients.js @@ -1,4 +1,4 @@ -import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=6'; +import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=8'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { addDays } from './dateUtils.js'; import { getDayPlan } from './planStore.js?v=2'; diff --git a/js/services/planStore.js b/js/services/planStore.js index e84314e..f5a7c01 100644 --- a/js/services/planStore.js +++ b/js/services/planStore.js @@ -1,4 +1,4 @@ -import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=6'; +import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=8'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { PLANS_STORAGE_KEY } from '../storageKeys.js'; import { startOfDay } from './dateUtils.js'; diff --git a/js/ui/mealPlanEditor.js b/js/ui/mealPlanEditor.js index 74961ba..149d00c 100644 --- a/js/ui/mealPlanEditor.js +++ b/js/ui/mealPlanEditor.js @@ -1,4 +1,4 @@ -import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=6'; +import { INGREDIENTS, RECIPES, PRODUCTS, CATEGORY_LABELS, getProductsForIngredient } from '../data/catalog.js?v=8'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { addDays, @@ -14,7 +14,7 @@ import { newPlanEntryId, savePlans, } from '../services/planStore.js?v=2'; -import { dayHasAnyMeal, autoSelectProducts, saveLastProductSelection } from '../services/planIngredients.js?v=3'; +import { dayHasAnyMeal, autoSelectProducts, saveLastProductSelection } from '../services/planIngredients.js?v=4'; import { loadPantry } from '../services/pantryShopping.js?v=2'; import { showAppToast } from './toast.js'; import { @@ -34,6 +34,115 @@ function esc(s) { const slotLabel = Object.fromEntries(MEAL_SLOTS.map((s) => [s.id, s.label])); +/* ── Product Card Popup ────────────────────────────── */ + +function getProductCardHTML() { + return ` + `; +} + +function openProductCard(ingredientId, productId) { + const overlay = document.getElementById('mpe-product-card-overlay'); + if (!overlay) return; + + const def = INGREDIENTS[ingredientId]; + const product = productId ? PRODUCTS[productId] : null; + const name = product?.name || def?.name || ingredientId; + const brand = product?.brand || ''; + const category = CATEGORY_LABELS[def?.category] || ''; + const nutrition = product?.nutritionPer100g || def?.nutritionPer100g; + const image = product?.image || def?.image; + const packLabel = product?.packLabel || def?.purchasePack?.label || ''; + const nutUnit = def?.pantryUnit === 'ml' ? '100 ml' : '100 g'; + + document.getElementById('mpe-pc-name').textContent = name; + document.getElementById('mpe-pc-brand').textContent = brand; + document.getElementById('mpe-pc-category').textContent = category; + document.getElementById('mpe-pc-nut-label').textContent = `Wartości odżywcze na ${nutUnit}`; + + const img = document.getElementById('mpe-pc-img'); + const fallback = document.getElementById('mpe-pc-fallback'); + if (image) { + img.src = image; + img.alt = name; + img.classList.remove('hidden'); + fallback.classList.add('hidden'); + } else { + img.classList.add('hidden'); + fallback.classList.remove('hidden'); + } + + const packWrap = document.getElementById('mpe-pc-pack'); + if (packLabel) { + packWrap.classList.remove('hidden'); + document.getElementById('mpe-pc-pack-val').textContent = packLabel; + } else { + packWrap.classList.add('hidden'); + } + + if (nutrition) { + document.getElementById('mpe-pc-kcal').textContent = nutrition.kcal; + document.getElementById('mpe-pc-protein').textContent = nutrition.protein + 'g'; + document.getElementById('mpe-pc-fat').textContent = nutrition.fat + 'g'; + document.getElementById('mpe-pc-carbs').textContent = nutrition.carbs + 'g'; + } + + overlay.classList.remove('hidden'); + overlay.style.pointerEvents = 'auto'; +} + +function closeProductCard() { + const overlay = document.getElementById('mpe-product-card-overlay'); + if (overlay) { + overlay.classList.add('hidden'); + overlay.style.pointerEvents = 'none'; + } +} + /* ── HTML template ──────────────────────────────────── */ export function getMealPlanEditorHTML() { @@ -85,7 +194,8 @@ export function getMealPlanEditorHTML() { - `; + + ${getProductCardHTML()}`; } /* ── Setup ──────────────────────────────────────────── */ @@ -304,7 +414,7 @@ export function setupMealPlanEditor() { : ''; html += `
`; - html += `
${esc(eName)}${productBadge}
`; + html += `
${esc(eName)}${productBadge}
`; html += `
`; html += shuffleBtn; html += ``; @@ -421,12 +536,22 @@ export function setupMealPlanEditor() {

Wartości odżywcze

-
-
-
${n.kcal}kcal
-
${n.protein}gBiałko
-
${n.carbs}gWęgle
-
${n.fat}gTłuszcze
+
+
+

${n.kcal}

+

kcal

+
+
+

${n.protein}g

+

białko

+
+
+

${n.fat}g

+

tłuszcz

+
+
+

${n.carbs}g

+

węgl.

@@ -636,11 +761,28 @@ export function setupMealPlanEditor() { renderNutrition(); }); + /* ── Product card ────────────────────────────── */ + + document.getElementById('mpe-pc-close')?.addEventListener('click', closeProductCard); + document.getElementById('mpe-product-card-overlay')?.addEventListener('click', (e) => { + if (e.target.id === 'mpe-product-card-overlay') closeProductCard(); + }); + /* ── Ingredient section delegation ────────────── */ const ingSec = document.getElementById('mpe-ing-section'); ingSec?.addEventListener('click', (e) => { + // Check "zmień" and other inner buttons before the card wrapper + const changeProdEarly = e.target.closest('.mpe-change-product'); + if (!changeProdEarly) { + const cardBtn = e.target.closest('.mpe-open-product-card'); + if (cardBtn) { + openProductCard(cardBtn.dataset.eid, cardBtn.dataset.pid || null); + return; + } + } + const remove = e.target.closest('.mpe-remove-ing'); if (remove) { if (remove.dataset.type === 'added') { diff --git a/js/views/Filter.js b/js/views/Filter.js index 812ce67..093e065 100644 --- a/js/views/Filter.js +++ b/js/views/Filter.js @@ -1,4 +1,4 @@ -import { RECIPES } from '../data/catalog.js?v=6'; +import { RECIPES } from '../data/catalog.js?v=8'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { applyFilters, getFilterState } from './RecipeList.js'; @@ -61,7 +61,7 @@ export function getFilterHTML() { outline: none; } -