Replace ingredients images with SVGs
This commit is contained in:
@@ -38,7 +38,6 @@ export const INGREDIENTS = {
|
||||
/* ── Nabiał ───────────────────────────────────────── */
|
||||
jajko: {
|
||||
id: 'jajko',
|
||||
image: 'images/ingredients/jajko.jpg',
|
||||
name: 'Jajka',
|
||||
category: 'nabial',
|
||||
pantryUnit: 'szt',
|
||||
@@ -120,7 +119,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
losos_wedzony: {
|
||||
id: 'losos_wedzony',
|
||||
image: 'images/ingredients/losos_wedzony.jpg',
|
||||
name: 'Łosoś wędzony',
|
||||
category: 'mieso_ryby',
|
||||
pantryUnit: 'g',
|
||||
@@ -138,7 +136,6 @@ export const INGREDIENTS = {
|
||||
/* ── Warzywa ──────────────────────────────────────── */
|
||||
pomidor: {
|
||||
id: 'pomidor',
|
||||
image: 'images/ingredients/pomidor.jpg',
|
||||
name: 'Pomidor',
|
||||
category: 'warzywa',
|
||||
pantryUnit: 'szt',
|
||||
@@ -147,7 +144,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
pomidorki_koktajlowe: {
|
||||
id: 'pomidorki_koktajlowe',
|
||||
image: 'images/ingredients/pomidorki_koktajlowe.jpg',
|
||||
name: 'Pomidorki koktajlowe',
|
||||
category: 'warzywa',
|
||||
pantryUnit: 'g',
|
||||
@@ -156,7 +152,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
papryka_czerwona: {
|
||||
id: 'papryka_czerwona',
|
||||
image: 'images/ingredients/papryka_czerwona.jpg',
|
||||
name: 'Papryka czerwona',
|
||||
category: 'warzywa',
|
||||
pantryUnit: 'szt',
|
||||
@@ -165,7 +160,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
ogorek: {
|
||||
id: 'ogorek',
|
||||
image: 'images/ingredients/ogorek.jpg',
|
||||
name: 'Ogórek',
|
||||
category: 'warzywa',
|
||||
pantryUnit: 'szt',
|
||||
@@ -174,7 +168,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
czosnek: {
|
||||
id: 'czosnek',
|
||||
image: 'images/ingredients/czosnek.jpg',
|
||||
name: 'Czosnek',
|
||||
category: 'warzywa',
|
||||
pantryUnit: 'szt',
|
||||
@@ -253,7 +246,6 @@ export const INGREDIENTS = {
|
||||
/* ── Owoce ────────────────────────────────────────── */
|
||||
truskawki: {
|
||||
id: 'truskawki',
|
||||
image: 'images/ingredients/truskawki.jpg',
|
||||
name: 'Truskawki',
|
||||
category: 'owoce',
|
||||
pantryUnit: 'g',
|
||||
@@ -261,7 +253,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
borowki_amerykanskie: {
|
||||
id: 'borowki_amerykanskie',
|
||||
image: 'images/ingredients/borowki_amerykanskie.jpg',
|
||||
name: 'Borówki amerykańskie',
|
||||
category: 'owoce',
|
||||
pantryUnit: 'g',
|
||||
@@ -269,7 +260,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
banany: {
|
||||
id: 'banany',
|
||||
image: 'images/ingredients/banany.jpg',
|
||||
name: 'Banany',
|
||||
category: 'owoce',
|
||||
pantryUnit: 'g',
|
||||
@@ -277,7 +267,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
jagody: {
|
||||
id: 'jagody',
|
||||
image: 'images/ingredients/jagody.jpg',
|
||||
name: 'Jagody',
|
||||
category: 'owoce',
|
||||
pantryUnit: 'g',
|
||||
@@ -301,7 +290,6 @@ export const INGREDIENTS = {
|
||||
/* ── Suche i kasze ────────────────────────────────── */
|
||||
makaron_suchy: {
|
||||
id: 'makaron_suchy',
|
||||
image: 'images/ingredients/makaron_suchy.jpg',
|
||||
name: 'Makaron',
|
||||
category: 'suche',
|
||||
pantryUnit: 'g',
|
||||
@@ -337,7 +325,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
migdaly: {
|
||||
id: 'migdaly',
|
||||
image: 'images/ingredients/migdaly.jpg',
|
||||
name: 'Migdały',
|
||||
category: 'suche',
|
||||
pantryUnit: 'g',
|
||||
@@ -448,7 +435,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
oliwa: {
|
||||
id: 'oliwa',
|
||||
image: 'images/ingredients/oliwa.jpg',
|
||||
name: 'Oliwa z oliwek',
|
||||
category: 'inne',
|
||||
pantryUnit: 'ml',
|
||||
@@ -456,7 +442,6 @@ export const INGREDIENTS = {
|
||||
},
|
||||
hummus: {
|
||||
id: 'hummus',
|
||||
image: 'images/ingredients/hummus.jpg',
|
||||
name: 'Hummus',
|
||||
category: 'inne',
|
||||
pantryUnit: 'g',
|
||||
@@ -528,6 +513,10 @@ export const INGREDIENTS = {
|
||||
},
|
||||
};
|
||||
|
||||
for (const [id, def] of Object.entries(INGREDIENTS)) {
|
||||
def.image = `icons/ingredients/${id}.svg`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{ ingredientId: string, amount: number, unit: string, alternatives?: string[] }} RecipeIngredientDef
|
||||
* @typedef {{ id: string, title: string, minutes: number, thumbLabel: string, image?: string, allowedSlots: string[], tags?: string[], nutritionPerServing: NutritionPer100, ingredients: RecipeIngredientDef[], steps: string[] }} RecipeDef
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, CATEGORY_LABELS, PRODUCTS, ingredientHasProducts } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, CATEGORY_LABELS, PRODUCTS, ingredientHasProducts } from '../data/catalog.js?v=9';
|
||||
import { PANTRY_STORAGE_KEY, PANTRY_STORAGE_KEY_V2, SHOPPING_STORAGE_KEY } from '../storageKeys.js';
|
||||
|
||||
export const KITCHEN_LIST_ID = 'kitchen';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=9';
|
||||
import { MEAL_SLOTS } from '../planner/mealSlots.js';
|
||||
import { addDays } from './dateUtils.js';
|
||||
import { dateKey, getDayPlan } from './planStore.js?v=2';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=9';
|
||||
import { MEAL_SLOTS } from '../planner/mealSlots.js';
|
||||
import { PLANS_STORAGE_KEY } from '../storageKeys.js';
|
||||
import { startOfDay } from './dateUtils.js';
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
getProductsForIngredient,
|
||||
ingredientHasProducts,
|
||||
pantryQtyStep,
|
||||
} from '../data/catalog.js?v=8';
|
||||
} from '../data/catalog.js?v=9';
|
||||
import {
|
||||
addOrMergeShoppingLines,
|
||||
KITCHEN_LIST_ID,
|
||||
@@ -76,7 +76,8 @@ function macroLine(n) {
|
||||
|
||||
function mediaHtml(image, icon, sizeClass = 'w-9 h-9', radiusClass = 'rounded-lg') {
|
||||
if (image) {
|
||||
return `<img src="${esc(image)}" alt="" class="${sizeClass} ${radiusClass} object-cover shrink-0">`;
|
||||
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>`;
|
||||
}
|
||||
@@ -154,30 +155,35 @@ export function getIngredientCardHTML({
|
||||
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;',
|
||||
heroHeightClass = 'h-[180px]',
|
||||
} = {}) {
|
||||
if (!idBase) throw new Error('getIngredientCardHTML requires idBase');
|
||||
return `
|
||||
<div id="${idBase}-overlay" class="${overlayClass}" style="${overlayStyle}">
|
||||
<div id="${idBase}" class="${cardClass}" style="${cardStyle}">
|
||||
<div id="${idBase}-hero" class="relative w-full ${heroHeightClass} overflow-hidden" style="background:#393937;">
|
||||
<img id="${idBase}-img" class="w-full h-full object-cover hidden" alt="" />
|
||||
<div id="${idBase}-fallback" class="w-full h-full flex items-center justify-center">
|
||||
<i id="${idBase}-fallback-icon" class="fas fa-box-open text-3xl" style="color:#6d6c67;"></i>
|
||||
<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-16 h-16 rounded-2xl flex items-center justify-center shrink-0 overflow-hidden" style="background:#393937;">
|
||||
<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>
|
||||
</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">
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="${idBase}-back" class="absolute top-3 left-3 w-8 h-8 rounded-full hidden flex items-center justify-center" style="background:rgba(0,0,0,0.5); color:#fff;" aria-label="Wróć do składnika">
|
||||
<i class="fas fa-chevron-left text-sm"></i>
|
||||
</button>
|
||||
<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:rgba(0,0,0,0.5); color:#fff;" 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:#393937; color:#ddd6ca;" aria-label="Zamknij">
|
||||
<i class="fas fa-times text-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="px-4 pt-3 pb-4 space-y-3">
|
||||
<div>
|
||||
<p id="${idBase}-category" class="text-[10px] font-semibold uppercase tracking-wider" style="color:#6ee7b7;"></p>
|
||||
<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>
|
||||
</div>
|
||||
<div class="px-4 pt-2 pb-4 space-y-3">
|
||||
<div id="${idBase}-nutrition"></div>
|
||||
<div id="${idBase}-stock"></div>
|
||||
<div id="${idBase}-products"></div>
|
||||
@@ -239,23 +245,22 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
const fallback = el('fallback');
|
||||
const fallbackIcon = el('fallback-icon');
|
||||
|
||||
if (heroEl) {
|
||||
heroEl.style.height = '';
|
||||
heroEl.style.background = '#393937';
|
||||
}
|
||||
|
||||
if (img && fallback) {
|
||||
const image = isListMode ? def.image : (product?.image || def.image);
|
||||
const altName = isListMode ? def.name : (product?.name || def.name);
|
||||
if (image) {
|
||||
img.src = image;
|
||||
img.alt = altName;
|
||||
const isSvg = image.endsWith('.svg');
|
||||
img.classList.toggle('object-contain', isSvg);
|
||||
img.classList.toggle('object-cover', !isSvg);
|
||||
img.style.padding = isSvg ? '6px' : '';
|
||||
img.classList.remove('hidden');
|
||||
fallback.classList.add('hidden');
|
||||
} else {
|
||||
img.classList.add('hidden');
|
||||
fallback.classList.remove('hidden');
|
||||
if (fallbackIcon) fallbackIcon.className = `fas ${icon} text-3xl`;
|
||||
if (fallbackIcon) fallbackIcon.className = `fas ${icon} text-2xl`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,6 +291,7 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
|
||||
|
||||
if (backBtn) {
|
||||
backBtn.classList.toggle('hidden', !isBackAvailable);
|
||||
backBtn.classList.toggle('flex', Boolean(isBackAvailable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, RECIPES, PRODUCTS, getProductsForIngredient } from '../data/catalog.js?v=9';
|
||||
import { MEAL_SLOTS } from '../planner/mealSlots.js';
|
||||
import {
|
||||
addDays,
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
renderCalendarGrid,
|
||||
syncCalendarTodayButton,
|
||||
} from './mealCalendar.js?v=11';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from './ingredientCard.js?v=20260417-113';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from './ingredientCard.js?v=20260417-115';
|
||||
|
||||
function esc(s) {
|
||||
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RECIPES } from '../data/catalog.js?v=8';
|
||||
import { RECIPES } from '../data/catalog.js?v=9';
|
||||
import { MEAL_SLOTS } from '../planner/mealSlots.js';
|
||||
import { applyFilters, getFilterState } from './RecipeList.js';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, RECIPES } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, RECIPES } from '../data/catalog.js?v=9';
|
||||
import { MEAL_SLOTS } from '../planner/mealSlots.js';
|
||||
import {
|
||||
addMonths,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
INGREDIENTS,
|
||||
CATEGORY_LABELS,
|
||||
} from '../data/catalog.js?v=8';
|
||||
} from '../data/catalog.js?v=9';
|
||||
import { loadPantry, getPantryTotal } from '../services/pantryShopping.js?v=2';
|
||||
import { loadPlans } from '../services/planStore.js?v=2';
|
||||
import { addDays, addMonths, sameDay, sameMonth, startOfDay, startOfMonth } from '../services/dateUtils.js';
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
renderCalendarGrid,
|
||||
syncCalendarTodayButton,
|
||||
} from '../ui/mealCalendar.js?v=11';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260417-113';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260417-115';
|
||||
|
||||
/* ── helpers ── */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RECIPES, INGREDIENTS, PRODUCTS } from '../data/catalog.js?v=8';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260417-113';
|
||||
import { RECIPES, INGREDIENTS, PRODUCTS } from '../data/catalog.js?v=9';
|
||||
import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260417-115';
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RECIPES } from '../data/catalog.js?v=8';
|
||||
import { RECIPES } from '../data/catalog.js?v=9';
|
||||
import { getRecipeGridSectionHTML, renderRecipeGrid } from '../ui/recipeGrid.js';
|
||||
|
||||
const DEFAULT_MIN_MINUTES = 5;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INGREDIENTS, CATEGORY_LABELS } from '../data/catalog.js?v=8';
|
||||
import { INGREDIENTS, CATEGORY_LABELS } from '../data/catalog.js?v=9';
|
||||
import {
|
||||
KITCHEN_LIST_ID,
|
||||
loadShoppingState,
|
||||
@@ -98,8 +98,9 @@ function itemRowHtml(item) {
|
||||
const image = def?.image;
|
||||
const checked = item.checked;
|
||||
|
||||
const mediaFit = image && image.endsWith('.svg') ? 'object-contain' : 'object-cover';
|
||||
const mediaHtml = image
|
||||
? `<img src="${esc(image)}" alt="" class="w-8 h-8 rounded-lg object-cover shrink-0">`
|
||||
? `<img src="${esc(image)}" alt="" class="w-8 h-8 rounded-lg ${mediaFit} shrink-0">`
|
||||
: `<div class="w-8 h-8 rounded-lg flex items-center justify-center shrink-0" style="background:#2f2f2d;"><i class="fas ${icon} text-xs" style="color:#8f8b84;"></i></div>`;
|
||||
|
||||
return `
|
||||
|
||||
Reference in New Issue
Block a user