Files
recipe-mockup/js/data/catalog.js

956 lines
39 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Katalog składników i przepisów — odpowiednik tabel w DB (edycja poza aplikacją).
* pantryUnit: jednostka magazynowa / sumowania na liście zakupów (g, ml, szt.).
* purchasePack: minimalna „sztuka” ze sklepu w tej samej jednostce co pantryUnit (np. 200 g).
* nutritionPer100g — wartości szacunkowe na 100 g (dla płynów: traktuj ml≈g przy wodzie).
*/
export const CATEGORY_LABELS = {
pieczywo: 'Pieczywo',
nabial: 'Nabiał',
mieso_ryby: 'Mięso i ryby',
warzywa: 'Warzywa',
owoce: 'Owoce',
suche: 'Suche i kasze',
przyprawy: 'Przyprawy i zioła',
inne: 'Inne',
};
/**
* @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, image?: string }} IngredientDef
* @typedef {{ id: string, ingredientId: string, name: string, brand?: string, packSize: number, packLabel?: string, nutritionPer100g: NutritionPer100, image?: string }} ProductDef
*/
/** @type {Record<string, IngredientDef>} */
export const INGREDIENTS = {
/* ── Pieczywo ─────────────────────────────────────── */
bulka_grahamka: {
id: 'bulka_grahamka',
name: 'Bułka grahamka',
category: 'pieczywo',
pantryUnit: 'szt',
weightPerPiece: 70,
purchasePack: { amount: 1, label: '1 bułka ~70 g' },
nutritionPer100g: { kcal: 260, protein: 9, fat: 3, carbs: 48 },
},
/* ── Nabiał ───────────────────────────────────────── */
jajko: {
id: 'jajko',
name: 'Jajka',
category: 'nabial',
pantryUnit: 'szt',
weightPerPiece: 60,
nutritionPer100g: { kcal: 143, protein: 13, fat: 9.5, carbs: 1.1 },
},
mozzarella: {
id: 'mozzarella',
name: 'Mozzarella',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 125, label: 'kulka 125 g' },
nutritionPer100g: { kcal: 280, protein: 22, fat: 20, carbs: 2 },
},
ricotta: {
id: 'ricotta',
name: 'Ricotta',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 250, label: 'opakowanie 250 g' },
nutritionPer100g: { kcal: 174, protein: 11, fat: 13, carbs: 3 },
},
burrata: {
id: 'burrata',
name: 'Burrata',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 150, label: 'opakowanie 150 g' },
nutritionPer100g: { kcal: 280, protein: 16, fat: 22, carbs: 2 },
},
serek_wiejski: {
id: 'serek_wiejski',
name: 'Serek wiejski',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 200, label: 'opakowanie 200 g' },
nutritionPer100g: { kcal: 97, protein: 11, fat: 5, carbs: 3 },
},
serek_smietankowy: {
id: 'serek_smietankowy',
name: 'Serek śmietankowy',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 150, label: 'opakowanie 150 g' },
nutritionPer100g: { kcal: 230, protein: 6, fat: 21, carbs: 4 },
},
mleko: {
id: 'mleko',
name: 'Mleko',
category: 'nabial',
pantryUnit: 'ml',
purchasePack: { amount: 1000, label: 'karton 1 l' },
nutritionPer100g: { kcal: 62, protein: 3.2, fat: 3.5, carbs: 4.7 },
},
skyr: {
id: 'skyr',
name: 'Skyr naturalny',
category: 'nabial',
pantryUnit: 'g',
purchasePack: { amount: 150, label: 'opakowanie 150 g' },
nutritionPer100g: { kcal: 63, protein: 11, fat: 0.2, carbs: 4 },
},
/* ── Mięso i ryby ─────────────────────────────────── */
szynka_parmenska: {
id: 'szynka_parmenska',
name: 'Szynka parmeńska',
category: 'mieso_ryby',
pantryUnit: 'g',
purchasePack: { amount: 100, label: 'opakowanie 100 g' },
nutritionPer100g: { kcal: 250, protein: 28, fat: 15, carbs: 0 },
},
szynka_z_kurczaka: {
id: 'szynka_z_kurczaka',
name: 'Szynka z kurczaka',
category: 'mieso_ryby',
pantryUnit: 'g',
purchasePack: { amount: 100, label: 'opakowanie 100 g' },
nutritionPer100g: { kcal: 105, protein: 19.5, fat: 2, carbs: 1.5 },
},
losos_wedzony: {
id: 'losos_wedzony',
name: 'Łosoś wędzony',
category: 'mieso_ryby',
pantryUnit: 'g',
purchasePack: { amount: 100, label: 'opakowanie 100 g' },
nutritionPer100g: { kcal: 150, protein: 20, fat: 7, carbs: 0 },
},
piers_kurczaka: {
id: 'piers_kurczaka',
name: 'Pierś z kurczaka',
category: 'mieso_ryby',
pantryUnit: 'g',
purchasePack: { amount: 500, label: 'opakowanie ~500 g' },
nutritionPer100g: { kcal: 110, protein: 23, fat: 1.5, carbs: 0 },
},
/* ── Warzywa ──────────────────────────────────────── */
pomidor: {
id: 'pomidor',
name: 'Pomidor',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 130,
nutritionPer100g: { kcal: 18, protein: 0.9, fat: 0.2, carbs: 3.9 },
},
pomidorki_koktajlowe: {
id: 'pomidorki_koktajlowe',
name: 'Pomidorki koktajlowe',
category: 'warzywa',
pantryUnit: 'g',
purchasePack: { amount: 250, label: 'opakowanie 250 g' },
nutritionPer100g: { kcal: 18, protein: 0.9, fat: 0.2, carbs: 3.9 },
},
papryka_czerwona: {
id: 'papryka_czerwona',
name: 'Papryka czerwona',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 160,
nutritionPer100g: { kcal: 31, protein: 1, fat: 0.3, carbs: 6 },
},
ogorek: {
id: 'ogorek',
name: 'Ogórek',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 200,
nutritionPer100g: { kcal: 15, protein: 0.7, fat: 0.1, carbs: 3 },
},
czosnek: {
id: 'czosnek',
name: 'Czosnek',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 35,
nutritionPer100g: { kcal: 149, protein: 6.4, fat: 0.5, carbs: 33 },
},
kielki_rzodkiewki: {
id: 'kielki_rzodkiewki',
name: 'Kiełki rzodkiewki',
category: 'warzywa',
pantryUnit: 'g',
nutritionPer100g: { kcal: 28, protein: 3, fat: 0.6, carbs: 3.5 },
},
kapusta_biala: {
id: 'kapusta_biala',
name: 'Kapusta biała',
category: 'warzywa',
pantryUnit: 'g',
purchasePack: { amount: 800, label: 'główka ~800 g' },
nutritionPer100g: { kcal: 25, protein: 1.3, fat: 0.1, carbs: 6 },
},
marchewka: {
id: 'marchewka',
name: 'Marchewka',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 80,
nutritionPer100g: { kcal: 41, protein: 0.9, fat: 0.2, carbs: 10 },
},
papryczka_chilli: {
id: 'papryczka_chilli',
name: 'Papryczka chilli',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 15,
nutritionPer100g: { kcal: 40, protein: 2, fat: 0.4, carbs: 9 },
},
pietruszka_korzen: {
id: 'pietruszka_korzen',
name: 'Pietruszka (korzeń)',
category: 'warzywa',
pantryUnit: 'szt',
weightPerPiece: 80,
nutritionPer100g: { kcal: 54, protein: 2.9, fat: 0.6, carbs: 10 },
},
seler: {
id: 'seler',
name: 'Seler korzeniowy',
category: 'warzywa',
pantryUnit: 'g',
purchasePack: { amount: 500, label: 'bulwa ~500 g' },
nutritionPer100g: { kcal: 42, protein: 1.5, fat: 0.3, carbs: 9 },
},
cukinia: {
id: 'cukinia',
name: 'Cukinia',
category: 'warzywa',
pantryUnit: 'g',
purchasePack: { amount: 300, label: 'sztuka ~300 g' },
nutritionPer100g: { kcal: 17, protein: 1.2, fat: 0.3, carbs: 3.1 },
},
ziemniaki: {
id: 'ziemniaki',
name: 'Ziemniaki',
category: 'warzywa',
pantryUnit: 'g',
nutritionPer100g: { kcal: 77, protein: 2, fat: 0.1, carbs: 17 },
},
imbir: {
id: 'imbir',
name: 'Imbir',
category: 'warzywa',
pantryUnit: 'g',
nutritionPer100g: { kcal: 80, protein: 1.8, fat: 0.8, carbs: 18 },
},
/* ── Owoce ────────────────────────────────────────── */
truskawki: {
id: 'truskawki',
name: 'Truskawki',
category: 'owoce',
pantryUnit: 'g',
nutritionPer100g: { kcal: 32, protein: 0.7, fat: 0.3, carbs: 8 },
},
borowki_amerykanskie: {
id: 'borowki_amerykanskie',
name: 'Borówki amerykańskie',
category: 'owoce',
pantryUnit: 'g',
nutritionPer100g: { kcal: 57, protein: 0.7, fat: 0.3, carbs: 14 },
},
banany: {
id: 'banany',
name: 'Banany',
category: 'owoce',
pantryUnit: 'g',
nutritionPer100g: { kcal: 89, protein: 1.1, fat: 0.3, carbs: 23 },
},
jagody: {
id: 'jagody',
name: 'Jagody',
category: 'owoce',
pantryUnit: 'g',
nutritionPer100g: { kcal: 44, protein: 0.7, fat: 0.4, carbs: 10 },
},
rokitnik_zwyczajny: {
id: 'rokitnik_zwyczajny',
name: 'Rokitnik zwyczajny - rokitnik pospolity (Hippophae rhamnoides)',
category: 'owoce',
pantryUnit: 'g',
nutritionPer100g: { kcal: 82, protein: 1.2, fat: 5.4, carbs: 5.5 },
},
limonka: {
id: 'limonka',
name: 'Limonka',
category: 'owoce',
pantryUnit: 'szt',
weightPerPiece: 60,
nutritionPer100g: { kcal: 30, protein: 0.7, fat: 0.2, carbs: 11 },
},
/* ── Suche i kasze ────────────────────────────────── */
makaron_suchy: {
id: 'makaron_suchy',
name: 'Makaron',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 371, protein: 13, fat: 1.5, carbs: 74 },
},
nasiona_slonecznika: {
id: 'nasiona_slonecznika',
name: 'Nasiona słonecznika',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 584, protein: 21, fat: 51, carbs: 20 },
},
orzechy_wloskie: {
id: 'orzechy_wloskie',
name: 'Orzechy włoskie',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 654, protein: 15, fat: 65, carbs: 14 },
},
orzechy_laskowe: {
id: 'orzechy_laskowe',
name: 'Orzechy laskowe',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 628, protein: 15, fat: 61, carbs: 17 },
},
orzechy_nerkowca: {
id: 'orzechy_nerkowca',
name: 'Orzechy nerkowca',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 553, protein: 18, fat: 44, carbs: 30 },
},
migdaly: {
id: 'migdaly',
name: 'Migdały',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 579, protein: 21, fat: 50, carbs: 22 },
},
orzechy_pekan: {
id: 'orzechy_pekan',
name: 'Orzechy pekan',
category: 'suche',
pantryUnit: 'g',
nutritionPer100g: { kcal: 691, protein: 9, fat: 72, carbs: 14 },
},
maka_pszenna: {
id: 'maka_pszenna',
name: 'Mąka pszenna',
category: 'suche',
pantryUnit: 'g',
purchasePack: { amount: 1000, label: 'torebka 1 kg' },
nutritionPer100g: { kcal: 364, protein: 10, fat: 1, carbs: 76 },
},
sezam: {
id: 'sezam',
name: 'Sezam',
category: 'suche',
pantryUnit: 'g',
purchasePack: { amount: 100, label: 'opakowanie 100 g' },
nutritionPer100g: { kcal: 573, protein: 18, fat: 50, carbs: 23 },
},
platki_owsiane: {
id: 'platki_owsiane',
name: 'Płatki owsiane',
category: 'suche',
pantryUnit: 'g',
purchasePack: { amount: 500, label: 'paczka 500 g' },
nutritionPer100g: { kcal: 379, protein: 13, fat: 7, carbs: 68 },
},
/* ── Przyprawy i zioła ────────────────────────────── */
bazylia_swieza: {
id: 'bazylia_swieza',
name: 'Bazylia świeża',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 23, protein: 3.2, fat: 0.6, carbs: 2.7 },
},
koper_swiezy: {
id: 'koper_swiezy',
name: 'Koper',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 43, protein: 3.5, fat: 1.1, carbs: 7 },
},
szczypiorek: {
id: 'szczypiorek',
name: 'Szczypiorek',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 30, protein: 3.3, fat: 0.7, carbs: 1.8 },
},
tymianek: {
id: 'tymianek',
name: 'Tymianek suszony',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 276, protein: 9, fat: 7, carbs: 45 },
},
chrzan: {
id: 'chrzan',
name: 'Chrzan tarty',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 44, protein: 1, fat: 0.5, carbs: 8 },
},
kolendra_swieza: {
id: 'kolendra_swieza',
name: 'Kolendra świeża',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 23, protein: 2.1, fat: 0.5, carbs: 3.7 },
},
natka_pietruszki: {
id: 'natka_pietruszki',
name: 'Natka pietruszki',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 36, protein: 3, fat: 0.8, carbs: 6.3 },
},
majeranek: {
id: 'majeranek',
name: 'Majeranek suszony',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 271, protein: 12.7, fat: 7, carbs: 60 },
},
cynamon: {
id: 'cynamon',
name: 'Cynamon',
category: 'przyprawy',
pantryUnit: 'g',
nutritionPer100g: { kcal: 247, protein: 4, fat: 1.2, carbs: 81 },
},
/* ── Inne ─────────────────────────────────────────── */
miod: {
id: 'miod',
name: 'Miód',
category: 'inne',
pantryUnit: 'g',
nutritionPer100g: { kcal: 304, protein: 0.3, fat: 0, carbs: 82 },
},
oliwa: {
id: 'oliwa',
name: 'Oliwa z oliwek',
category: 'inne',
pantryUnit: 'ml',
nutritionPer100g: { kcal: 884, protein: 0, fat: 100, carbs: 0 },
},
hummus: {
id: 'hummus',
name: 'Hummus',
category: 'inne',
pantryUnit: 'g',
purchasePack: { amount: 200, label: 'opakowanie 200 g' },
nutritionPer100g: { kcal: 166, protein: 8, fat: 10, carbs: 14 },
},
olej_rzepakowy: {
id: 'olej_rzepakowy',
name: 'Olej rzepakowy',
category: 'inne',
pantryUnit: 'ml',
purchasePack: { amount: 1000, label: 'butelka 1 l' },
nutritionPer100g: { kcal: 884, protein: 0, fat: 100, carbs: 0 },
},
erytrol: {
id: 'erytrol',
name: 'Erytrol',
category: 'inne',
pantryUnit: 'g',
purchasePack: { amount: 500, label: 'opakowanie 500 g' },
nutritionPer100g: { kcal: 0, protein: 0, fat: 0, carbs: 0 },
},
ekstrakt_waniliowy: {
id: 'ekstrakt_waniliowy',
name: 'Ekstrakt waniliowy',
category: 'inne',
pantryUnit: 'ml',
purchasePack: { amount: 30, label: 'buteleczka 30 ml' },
nutritionPer100g: { kcal: 288, protein: 0.1, fat: 0.1, carbs: 12.7 },
},
maslo_orzechowe: {
id: 'maslo_orzechowe',
name: 'Masło orzechowe',
category: 'inne',
pantryUnit: 'g',
purchasePack: { amount: 350, label: 'słoik 350 g' },
nutritionPer100g: { kcal: 594, protein: 25, fat: 50, carbs: 20 },
},
sos_sojowy: {
id: 'sos_sojowy',
name: 'Sos sojowy',
category: 'inne',
pantryUnit: 'ml',
purchasePack: { amount: 150, label: 'butelka 150 ml' },
nutritionPer100g: { kcal: 53, protein: 8, fat: 0, carbs: 5 },
},
syrop_z_agawy: {
id: 'syrop_z_agawy',
name: 'Syrop z agawy',
category: 'inne',
pantryUnit: 'g',
purchasePack: { amount: 350, label: 'butelka 350 g' },
nutritionPer100g: { kcal: 310, protein: 0, fat: 0, carbs: 76 },
},
czekolada: {
id: 'czekolada',
name: 'Czekolada gorzka',
category: 'inne',
pantryUnit: 'g',
purchasePack: { amount: 100, label: 'tabliczka 100 g' },
nutritionPer100g: { kcal: 546, protein: 8, fat: 31, carbs: 61 },
},
bulion_warzywny: {
id: 'bulion_warzywny',
name: 'Bulion warzywny',
category: 'inne',
pantryUnit: 'ml',
nutritionPer100g: { kcal: 6, protein: 0.5, fat: 0.1, carbs: 0.5 },
},
};
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
*/
/** Porcja bazowa = 1; składniki przez ingredientId */
/** @type {Record<string, RecipeDef>} */
export const RECIPES = {
kanapka_parmenska: {
id: 'kanapka_parmenska',
title: 'Kanapka z szynką parmeńską i mozzarellą',
minutes: 5,
thumbLabel: 'Parmeńska',
image: 'images/recipes/kanapka_parmenska.jpg',
allowedSlots: ['sniadanie', 'drugie_sniadanie', 'kolacja'],
tags: ['szybkie'],
nutritionPerServing: { kcal: 606, protein: 47, fat: 29, carbs: 39 },
ingredients: [
{ ingredientId: 'bulka_grahamka', amount: 1, unit: 'szt.' },
{ ingredientId: 'szynka_parmenska', amount: 95, unit: 'g' },
{ ingredientId: 'mozzarella', amount: 60, unit: 'g' },
{ ingredientId: 'pomidorki_koktajlowe', amount: 100, unit: 'g' },
],
steps: [
'Bułkę grahamkę przekrój na pół.',
'Na bułce ułóż plastry szynki parmeńskiej, na nią pokrojoną mozzarellę.',
'Podawaj z pomidorkami koktajlowymi.',
],
},
makaron_ricotta: {
id: 'makaron_ricotta',
title: 'Makaron z ricottą i pomidorami',
minutes: 20,
thumbLabel: 'Ricotta',
image: 'images/recipes/makaron_ricotta.jpg',
allowedSlots: ['obiad', 'kolacja'],
tags: ['wegetariańskie'],
nutritionPerServing: { kcal: 608, protein: 24, fat: 24, carbs: 75 },
ingredients: [
{ ingredientId: 'makaron_suchy', amount: 80, unit: 'g' },
{ ingredientId: 'pomidorki_koktajlowe', amount: 200, unit: 'g' },
{ ingredientId: 'czosnek', amount: 6, unit: 'g' },
{ ingredientId: 'tymianek', amount: 1, unit: 'g' },
{ ingredientId: 'oliwa', amount: 5, unit: 'ml' },
{ ingredientId: 'ricotta', amount: 75, unit: 'g', alternatives: ['burrata'] },
{ ingredientId: 'bazylia_swieza', amount: 3, unit: 'g' },
{ ingredientId: 'nasiona_slonecznika', amount: 15, unit: 'g' },
],
steps: [
'Makaron ugotuj wg przepisu na opakowaniu. Po ugotowaniu pozostaw 12 łyżki wody.',
'Na patelni rozgrzej oliwę, dodaj przeciśnięty czosnek, przekrojone na pół pomidorki i tymianek — podsmażaj 23 minuty.',
'Na patelnię z sosem dodaj ugotowany makaron. Wymieszaj, przypraw solą i pieprzem.',
'Ricottę wymieszaj z 12 łyżkami wody z gotowania makaronu. Nałóż na makaron.',
'Posyp bazylią świeżą i nasionami słonecznika.',
],
},
jajecznica: {
id: 'jajecznica',
title: 'Jajecznica z pieczywem',
minutes: 5,
thumbLabel: 'Jajecznica',
image: 'images/recipes/jajecznica.png',
allowedSlots: ['sniadanie', 'drugie_sniadanie', 'kolacja'],
tags: ['szybkie', 'wysokobiałkowe'],
nutritionPerServing: { kcal: 571, protein: 38, fat: 30, carbs: 36 },
ingredients: [
{ ingredientId: 'jajko', amount: 4, unit: 'szt.' },
{ ingredientId: 'oliwa', amount: 5, unit: 'ml' },
{ ingredientId: 'bulka_grahamka', amount: 1, unit: 'szt.' },
{ ingredientId: 'szczypiorek', amount: 5, unit: 'g' },
],
steps: [
'Na patelni rozgrzej oliwę na małej mocy palnika.',
'Wbij jajka bezpośrednio na patelnię. Smaż bez przykrycia, delikatnie mieszając łopatką, aż żółtka i białka stopniowo się połączą.',
'Dopraw solą i pieprzem. Kontynuuj smażenie, aż jajka się zetną, ale pozostaną lekko kremowe — ok. 34 minuty.',
'Posyp posiekanym szczypiorkiem i podawaj z bułką grahamką.',
],
},
kanapka_hummus: {
id: 'kanapka_hummus',
title: 'Kanapka z hummusem, wędliną i warzywami',
minutes: 5,
thumbLabel: 'Hummus',
image: 'images/recipes/kanapka_hummus.png',
allowedSlots: ['sniadanie', 'drugie_sniadanie', 'kolacja'],
tags: ['szybkie', 'wysokobiałkowe'],
nutritionPerServing: { kcal: 609, protein: 46, fat: 19, carbs: 66 },
ingredients: [
{ ingredientId: 'bulka_grahamka', amount: 1, unit: 'szt.' },
{ ingredientId: 'szynka_z_kurczaka', amount: 130, unit: 'g' },
{ ingredientId: 'pomidor', amount: 80, unit: 'g' },
{ ingredientId: 'papryka_czerwona', amount: 85, unit: 'g' },
{ ingredientId: 'ogorek', amount: 75, unit: 'g' },
{ ingredientId: 'szczypiorek', amount: 20, unit: 'g' },
{ ingredientId: 'hummus', amount: 140, unit: 'g' },
],
steps: [
'Pomidora i ogórka pokrój w plastry. Paprykę pokrój w paski. Szczypiorek posiekaj.',
'Bułkę grahamkę przekrój i posmaruj hummusem.',
'Na bułce ułóż szynkę z kurczaka, pomidora, paprykę i ogórka.',
'Posyp szczypiorkiem i podawaj.',
],
},
kanapka_losos: {
id: 'kanapka_losos',
title: 'Kanapka z wędzonym łososiem',
minutes: 5,
thumbLabel: 'Łosoś',
image: 'images/recipes/kanapka_losos.jpg',
allowedSlots: ['sniadanie', 'drugie_sniadanie', 'kolacja'],
tags: ['szybkie'],
nutritionPerServing: { kcal: 443, protein: 30, fat: 18, carbs: 39 },
ingredients: [
{ ingredientId: 'bulka_grahamka', amount: 1, unit: 'szt.' },
{ ingredientId: 'losos_wedzony', amount: 100, unit: 'g' },
{ ingredientId: 'serek_smietankowy', amount: 40, unit: 'g' },
{ ingredientId: 'chrzan', amount: 10, unit: 'g' },
{ ingredientId: 'koper_swiezy', amount: 5, unit: 'g' },
{ ingredientId: 'kielki_rzodkiewki', amount: 5, unit: 'g' },
{ ingredientId: 'ogorek', amount: 75, unit: 'g' },
],
steps: [
'Bułkę grahamkę przekrój i podsmaż na patelni na średnim ogniu przez 23 minuty.',
'Chrzan dokładnie wymieszaj z serkiem śmietankowym.',
'Koperek drobno posiekaj. Ogórka pokrój na mniejsze kawałki.',
'Na bułce rozsmaruj pastę chrzanowo-serową. Ułóż łososia, koperek, ogórka i kiełki.',
],
},
serek_owoc: {
id: 'serek_owoc',
title: 'Serek wiejski z orzechami i owocami',
minutes: 5,
thumbLabel: 'Serek',
image: 'images/recipes/serek_owoc.jpg',
allowedSlots: ['sniadanie', 'drugie_sniadanie', 'przekaska'],
tags: ['wegetariańskie', 'wysokobiałkowe', 'szybkie'],
nutritionPerServing: { kcal: 629, protein: 31, fat: 43, carbs: 40 },
ingredients: [
{ ingredientId: 'serek_wiejski', amount: 200, unit: 'g' },
{ ingredientId: 'miod', amount: 10, unit: 'g' },
{ ingredientId: 'orzechy_wloskie', amount: 50, unit: 'g', alternatives: ['orzechy_laskowe', 'orzechy_nerkowca', 'migdaly', 'orzechy_pekan'] },
{ ingredientId: 'truskawki', amount: 100, unit: 'g', alternatives: ['banany'] },
{ ingredientId: 'borowki_amerykanskie', amount: 80, unit: 'g', alternatives: ['jagody', 'rokitnik_zwyczajny'] },
],
steps: [
'Przełóż serek wiejski do miseczki.',
'Dodaj miód i delikatnie wymieszaj.',
'Orzechy posiekaj na mniejsze kawałki i posyp nimi serek z miodem.',
'Umyj owoce (ew. pokrój na połówki) i ułóż na wierzchu. Gotowe!',
],
},
dutch_baby: {
id: 'dutch_baby',
title: 'Dutch baby z owocami',
minutes: 45,
thumbLabel: 'Dutch baby',
image: 'images/recipes/dutch_baby.jpg',
allowedSlots: ['sniadanie', 'drugie_sniadanie'],
tags: ['wegetariańskie', 'wysokobiałkowe'],
nutritionPerServing: { kcal: 910, protein: 57, fat: 37, carbs: 88 },
ingredients: [
{ ingredientId: 'maka_pszenna', amount: 60, unit: 'g' },
{ ingredientId: 'mleko', amount: 125, unit: 'ml' },
{ ingredientId: 'jajko', amount: 2, unit: 'szt.' },
{ ingredientId: 'erytrol', amount: 15, unit: 'g' },
{ ingredientId: 'olej_rzepakowy', amount: 10, unit: 'ml' },
{ ingredientId: 'ekstrakt_waniliowy', amount: 1.5, unit: 'ml' },
{ ingredientId: 'skyr', amount: 225, unit: 'g' },
{ ingredientId: 'maslo_orzechowe', amount: 20, unit: 'g' },
{ ingredientId: 'borowki_amerykanskie', amount: 100, unit: 'g', alternatives: ['jagody'] },
{ ingredientId: 'truskawki', amount: 100, unit: 'g' },
],
steps: [
'Nagrzej piekarnik do 210°C wraz z patelnią żeliwną w środku.',
'Zmiksuj jajka, mąkę, mleko, ekstrakt waniliowy, 10 g erytrolu i szczyptę soli. Odstaw ciasto na 20 minut.',
'Wyjmij nagrzaną patelnię, rozprowadź olej rzepakowy i wlej ciasto.',
'Piecz do zbrązowienia brzegów (ok. 10 minut). Ostudź.',
'Wymieszaj skyr z pozostałym erytrolem (5 g) i masłem orzechowym. Nałóż na naleśnika.',
'Ułóż na wierzchu umyte borówki i truskawki.',
],
},
placki_kapusta_losos: {
id: 'placki_kapusta_losos',
title: 'Placki z białej kapusty z łososiem i słodkim sosem sojowym',
minutes: 35,
thumbLabel: 'Placki kapuściane',
image: 'images/recipes/placki_kapusta_losos.jpg',
allowedSlots: ['obiad', 'kolacja'],
nutritionPerServing: { kcal: 775, protein: 44, fat: 34, carbs: 80 },
ingredients: [
{ ingredientId: 'kapusta_biala', amount: 300, unit: 'g' },
{ ingredientId: 'marchewka', amount: 0.5, unit: 'szt.' },
{ ingredientId: 'czosnek', amount: 6, unit: 'g' },
{ ingredientId: 'papryczka_chilli', amount: 0.5, unit: 'szt.' },
{ ingredientId: 'szczypiorek', amount: 15, unit: 'g' },
{ ingredientId: 'kolendra_swieza', amount: 4, unit: 'g' },
{ ingredientId: 'jajko', amount: 1, unit: 'szt.' },
{ ingredientId: 'maka_pszenna', amount: 36, unit: 'g' },
{ ingredientId: 'sezam', amount: 20, unit: 'g' },
{ ingredientId: 'olej_rzepakowy', amount: 10, unit: 'ml' },
{ ingredientId: 'sos_sojowy', amount: 40, unit: 'ml' },
{ ingredientId: 'miod', amount: 24, unit: 'g' },
{ ingredientId: 'imbir', amount: 3, unit: 'g' },
{ ingredientId: 'limonka', amount: 3, unit: 'g' },
{ ingredientId: 'losos_wedzony', amount: 100, unit: 'g' },
],
steps: [
'Kapustę poszatkuj w cienkie paski i dodatkowo posiekaj nożem. Marchewkę zetrzyj na grubej tarce, czosnek na drobnej. Posiekaj szczypiorek i kolendrę, drobno pokrój chili.',
'W rondelku wymieszaj sos sojowy, miód, starty imbir i sok z limonki. Podgrzewaj 5 minut do uzyskania konsystencji syropu.',
'W misce połącz kapustę, marchewkę, czosnek, chili, 10 g szczypiorku, kolendrę, sól, pieprz, paprykę wędzoną i 10 g sezamu. Dodaj jajko i mąkę, dokładnie wymieszaj.',
'Rozgrzej olej rzepakowy na patelni. Nakładaj łyżką porcje ciasta, spłaszczając je w kształt placków. Smaż z każdej strony 34 minuty do zrumienienia.',
'Ułóż placki na talerzu, na każdym połóż plastry wędzonego łososia.',
'Polej słodkim sosem sojowym, posyp pozostałym szczypiorkiem (5 g) i sezamem (10 g).',
],
},
zupa_jarzynowa: {
id: 'zupa_jarzynowa',
title: 'Lekkostrawna zupa jarzynowa',
minutes: 50,
thumbLabel: 'Zupa jarzynowa',
image: 'images/recipes/zupa_jarzynowa.jpg',
allowedSlots: ['obiad'],
tags: ['wysokobiałkowe'],
nutritionPerServing: { kcal: 657, protein: 50, fat: 15, carbs: 81 },
ingredients: [
{ ingredientId: 'piers_kurczaka', amount: 150, unit: 'g' },
{ ingredientId: 'marchewka', amount: 150, unit: 'g' },
{ ingredientId: 'pietruszka_korzen', amount: 100, unit: 'g' },
{ ingredientId: 'seler', amount: 100, unit: 'g' },
{ ingredientId: 'cukinia', amount: 100, unit: 'g' },
{ ingredientId: 'ziemniaki', amount: 210, unit: 'g' },
{ ingredientId: 'bulion_warzywny', amount: 750, unit: 'ml' },
{ ingredientId: 'natka_pietruszki', amount: 10, unit: 'g' },
{ ingredientId: 'majeranek', amount: 4, unit: 'g' },
{ ingredientId: 'tymianek', amount: 3, unit: 'g' },
{ ingredientId: 'oliwa', amount: 10, unit: 'ml' },
],
steps: [
'Oczyść warzywa. Marchewkę, pietruszkę i seler pokrój w kostkę, ziemniaki w mniejszą kostkę, cukinię w ćwierćplasterki, mięso w większe kostki.',
'Wlej bulion do garnka. Dodaj marchewkę, pietruszkę, seler, ziemniaki i pierś z kurczaka. Doprowadź do wrzenia, wrzuć liść laurowy i ziele angielskie.',
'Zmniejsz ogień i gotuj pod częściowym przykryciem 20 minut.',
'Dodaj cukinię, majeranek i tymianek. Gotuj kolejne 10 minut, aż warzywa będą miękkie.',
'Dopraw solą, białym pieprzem i lubczykiem. Wmieszaj posiekaną natkę pietruszki oraz oliwę.',
'Przykryj i odstaw na 5 minut przed podaniem.',
],
},
ciasteczka_owsiane: {
id: 'ciasteczka_owsiane',
title: 'Ciasteczka owsiane z czekoladą',
minutes: 35,
thumbLabel: 'Ciasteczka owsiane',
image: 'images/recipes/ciasteczka_owsiane.jpg',
allowedSlots: ['drugie_sniadanie', 'przekaska'],
tags: ['wegetariańskie'],
nutritionPerServing: { kcal: 183, protein: 5, fat: 5, carbs: 30 },
ingredients: [
{ ingredientId: 'banany', amount: 240, unit: 'g' },
{ ingredientId: 'maslo_orzechowe', amount: 30, unit: 'g' },
{ ingredientId: 'syrop_z_agawy', amount: 15, unit: 'g', alternatives: ['miod'] },
{ ingredientId: 'ekstrakt_waniliowy', amount: 9, unit: 'ml' },
{ ingredientId: 'cynamon', amount: 2, unit: 'g' },
{ ingredientId: 'platki_owsiane', amount: 220, unit: 'g' },
{ ingredientId: 'czekolada', amount: 30, unit: 'g' },
],
steps: [
'Nagrzej piekarnik do 180°C (góra-dół). Wyłóż blachę papierem do pieczenia.',
'Obierz banany i rozgnieć je widelcem w misce na gładką papkę.',
'Dodaj masło orzechowe, syrop z agawy, ekstrakt waniliowy, cynamon i szczyptę soli. Wymieszaj przez ok. minutę.',
'Wsyp płatki owsiane i mieszaj aż do uzyskania gęstej, lepkiej masy.',
'Posiekaj czekoladę na drobne kawałki, wmieszaj do masy.',
'Formuj kulki wielkości orzecha włoskiego (ok. 8 sztuk) i układaj na blasze, lekko spłaszczając.',
'Piecz ok. 15 minut, aż brzegi się zrumienią. Studź ok. 10 minut przed zdjęciem z blachy.',
],
},
};
/* ══════════════════════════════════════════════════════════════════════
* Konkretne produkty — warianty składników generycznych.
* Każdy produkt należy do jednego IngredientDef (przez ingredientId).
* ══════════════════════════════════════════════════════════════════════ */
/** @type {Record<string, ProductDef>} */
export const PRODUCTS = {
/* ── Nabiał ───────────────────────────────────────── */
almette_naturalny: {
id: 'almette_naturalny',
ingredientId: 'serek_smietankowy',
name: 'Almette naturalny',
brand: 'Almette',
packSize: 150,
packLabel: '150 g',
nutritionPer100g: { kcal: 234, protein: 5.5, fat: 22, carbs: 3.5 },
},
philadelphia_original: {
id: 'philadelphia_original',
ingredientId: 'serek_smietankowy',
name: 'Philadelphia Original',
brand: 'Philadelphia',
packSize: 125,
packLabel: '125 g',
nutritionPer100g: { kcal: 235, protein: 5.4, fat: 21.5, carbs: 4.1 },
},
mozzarella_galbani: {
id: 'mozzarella_galbani',
ingredientId: 'mozzarella',
name: 'Galbani Mozzarella',
brand: 'Galbani',
packSize: 125,
packLabel: '125 g',
nutritionPer100g: { kcal: 253, protein: 18.4, fat: 19.1, carbs: 1.6 },
},
ricotta_galbani: {
id: 'ricotta_galbani',
ingredientId: 'ricotta',
name: 'Galbani Ricotta',
brand: 'Galbani',
packSize: 250,
packLabel: '250 g',
nutritionPer100g: { kcal: 138, protein: 10, fat: 10, carbs: 3 },
},
serek_wiejski_piatnica: {
id: 'serek_wiejski_piatnica',
ingredientId: 'serek_wiejski',
name: 'Piątnica Serek wiejski',
brand: 'Piątnica',
packSize: 200,
packLabel: '200 g',
nutritionPer100g: { kcal: 97, protein: 11, fat: 5, carbs: 2 },
},
serek_wiejski_piatnica_wb: {
id: 'serek_wiejski_piatnica_wb',
ingredientId: 'serek_wiejski',
name: 'Piątnica Serek wiejski wysokobiałkowy',
brand: 'Piątnica',
packSize: 200,
packLabel: '200 g',
nutritionPer100g: { kcal: 93, protein: 14, fat: 3, carbs: 2.4 },
},
/* ── Mięso i ryby ─────────────────────────────────── */
burrata_milbona: {
id: 'burrata_milbona',
ingredientId: 'burrata',
name: 'Milbona Burrata',
brand: 'Milbona',
packSize: 125,
packLabel: '125 g',
nutritionPer100g: { kcal: 254, protein: 10, fat: 23, carbs: 1.8 },
},
burrata_gustobello: {
id: 'burrata_gustobello',
ingredientId: 'burrata',
name: 'GustoBello Burrata',
brand: 'GustoBello',
packSize: 100,
packLabel: '100 g',
nutritionPer100g: { kcal: 259, protein: 10, fat: 23, carbs: 2 },
},
/* ── Mięso i ryby ─────────────────────────────────── */
losos_wedzony_suempol: {
id: 'losos_wedzony_suempol',
ingredientId: 'losos_wedzony',
name: 'Suempol Łosoś atlantycki wędzony',
brand: 'Suempol',
packSize: 100,
packLabel: '100 g',
nutritionPer100g: { kcal: 160, protein: 21.5, fat: 8, carbs: 0.5 },
},
/* ── Inne ─────────────────────────────────────────── */
hummus_klasyczny_well_well: {
id: 'hummus_klasyczny_well_well',
ingredientId: 'hummus',
name: 'Well Well Hummus klasyczny',
brand: 'Well Well',
packSize: 200,
packLabel: '200 g',
nutritionPer100g: { kcal: 198, protein: 6.6, fat: 12, carbs: 16 },
},
};
/** @param {string} ingredientId @returns {ProductDef[]} */
export function getProductsForIngredient(ingredientId) {
return Object.values(PRODUCTS).filter(p => p.ingredientId === ingredientId);
}
/** @param {string} ingredientId @returns {boolean} */
export function ingredientHasProducts(ingredientId) {
return Object.values(PRODUCTS).some(p => p.ingredientId === ingredientId);
}
/**
* Krok +/- w spiżarni: całe opakowanie albo domyślny krok (10 g/ml lub 1 szt.).
* @param {string} ingredientId
* @returns {number}
*/
export function pantryQtyStep(ingredientId) {
const d = INGREDIENTS[ingredientId];
if (!d) return 10;
if (d.purchasePack && Number.isFinite(d.purchasePack.amount) && d.purchasePack.amount > 0) {
return d.purchasePack.amount;
}
return d.pantryUnit === 'szt' ? 1 : 10;
}
/**
* @param {IngredientDef} def
* @param {number} stockQty — w pantryUnit
*/
export function nutritionForStock(def, stockQty) {
const n = def.nutritionPer100g;
if (!n || !Number.isFinite(stockQty) || stockQty <= 0) return null;
let grams = stockQty;
if (def.pantryUnit === 'szt' && def.weightPerPiece) {
grams = stockQty * def.weightPerPiece;
}
const f = grams / 100;
return {
kcal: Math.round(n.kcal * f),
protein: Math.round(n.protein * f * 10) / 10,
fat: Math.round(n.fat * f * 10) / 10,
carbs: Math.round(n.carbs * f * 10) / 10,
};
}
/**
* Pełne opakowania + reszta (np. 450 g / 200 → 2 + 50 g).
* @param {IngredientDef} def
* @param {number} stockQty
* @returns {{ fullPacks: number, remainder: number } | null}
*/
export function splitStockIntoPacks(def, stockQty) {
const size = def.purchasePack?.amount;
if (!size || !Number.isFinite(size) || size <= 0 || !Number.isFinite(stockQty)) return null;
const fullPacks = Math.floor(stockQty / size);
const remainder = Math.round((stockQty - fullPacks * size) * 10) / 10;
return { fullPacks, remainder };
}