-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
369 lines (335 loc) · 12.6 KB
/
Copy pathscript.js
File metadata and controls
369 lines (335 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
const input = document.getElementById('search-input')
const searchBtn = document.getElementById('search-btn')
const grid = document.getElementById('results-grid')
const homeBtn = document.getElementById('home-btn')
const modal = document.getElementById('recipe-modal')
const modalContent = document.getElementById('modal-content')
const closeModal = document.getElementById('close-modal')
const savedLink = document.getElementById('view-saved')
const SPOONACULAR_API_KEY = '62491d92c7814883ac5fc2fe8dcff501'
let savedRecipes = JSON.parse(localStorage.getItem('saved_dishes')) || []
let searchCache = []
const localIndianRecipes = [
{
idMeal: 'local_1',
strMeal: 'Paneer Tikka',
strMealThumb: 'assets/paneer_tikka.png',
strCategory: 'Vegetarian',
strArea: 'Indian',
strInstructions:
'1. Cut paneer, onions, and bell peppers into cubes.\n2. Marinate them with yogurt, ginger-garlic paste, tikka masala, red chili powder, and lemon juice for 30 minutes.\n3. Skewer the paneer and vegetables alternately.\n4. Grill in an oven, pan, or tandoor at 200°C for 15-20 minutes until edges are charred.\n5. Serve hot with mint chutney and lemon wedges.',
ingredients: [
'250g Paneer',
'1/2 cup Yogurt',
'1 large Bell Pepper',
'1 large Onion',
'2 tbsp Tikka Masala',
'1 tbsp Lemon Juice',
'1 tbsp Ginger Garlic Paste'
]
},
{
idMeal: 'local_2',
strMeal: 'Butter Chicken',
strMealThumb: 'assets/butter_chicken.png',
strCategory: 'Chicken',
strArea: 'Indian',
strInstructions:
'1. Marinate chicken with yogurt, spices, ginger, and garlic, then bake or grill until cooked.\n2. In a pan, melt butter and sauté onions, ginger, and garlic.\n3. Add tomato puree, cashew paste, chili powder, and garam masala. Simmer into a smooth gravy.\n4. Stir in heavy cream and add the grilled chicken pieces.\n5. Cook on low heat for 10 minutes, garnish with kasuri methi and cream.',
ingredients: [
'500g Chicken',
'50g Butter',
'1 cup Tomato Puree',
'1/2 cup Heavy Cream',
'3 tbsp Yogurt',
'2 tbsp Cashews Paste',
'1 tsp Garam Masala'
]
},
{
idMeal: 'local_3',
strMeal: 'Samosa',
strMealThumb: 'assets/samosa.png',
strCategory: 'Snack',
strArea: 'Indian',
strInstructions:
'1. Boil and mash potatoes, then sauté with green peas, cumin, coriander powder, garam masala, and green chilies.\n2. Prepare a dough using all-purpose flour (maida), carom seeds (ajwain), ghee, and water.\n3. Roll out the dough, cut into halves, and shape into cones.\n4. Fill the cones with the spiced potato mixture and seal the edges with water.\n5. Deep fry on medium-low heat until golden brown and crispy. Serve with tamarind and green chutney.',
ingredients: [
'3 boiled Potatoes',
'2 cups All-purpose Flour',
'1/4 cup Green Peas',
'3 tbsp Ghee',
'1 tsp Garam Masala',
'1/2 tsp Carom Seeds'
]
},
{
idMeal: 'local_4',
strMeal: 'Masala Dosa',
strMealThumb: 'assets/masala_dosa.png',
strCategory: 'Vegetarian',
strArea: 'Indian',
strInstructions:
'1. Soak rice and urad dal, grind to a smooth batter, and ferment overnight.\n2. Prepare potato bhaji by tempering boiled potatoes with mustard seeds, curry leaves, turmeric, onions, and green chilies.\n3. Heat a non-stick tawa, spread a ladleful of batter in a thin circular motion to make a crepe.\n4. Drizzle butter or oil around the edges and cook until golden brown and crispy.\n5. Place a portion of potato bhaji in the center, fold, and serve hot with coconut chutney and sambar.',
ingredients: [
'2 cups Rice Batter',
'3 boiled Potatoes',
'1 tsp Mustard Seeds',
'8-10 Curry Leaves',
'1 medium Onion',
'1/2 tsp Turmeric Powder'
]
},
{
idMeal: 'local_5',
strMeal: 'Poha',
strMealThumb: 'assets/poha.png',
strCategory: 'Breakfast',
strArea: 'Indian',
strInstructions:
'1. Rinse flattened rice (poha) in a colander under running water until soft, then drain and set aside with a pinch of turmeric and salt.\n2. Heat oil in a pan. Sauté peanuts until crunchy, then remove and set aside.\n3. In the same oil, add mustard seeds, green chilies, curry leaves, and chopped onions. Sauté until onions are translucent.\n4. Add roasted peanuts and the soft poha. Mix gently.\n5. Cover and steam on low heat for 2 minutes.\n6. Garnish with coriander leaves, grated coconut, and lemon juice. Serve hot!',
ingredients: [
'2 cups Flattened Rice (Poha)',
'1 medium Onion (chopped)',
'1/4 cup Peanuts',
'1 tsp Mustard Seeds',
'2 Green Chilies',
'8-10 Curry Leaves',
'1/2 tsp Turmeric Powder',
'Lemon juice'
]
},
{
idMeal: 'local_6',
strMeal: 'Jalebi',
strMealThumb: 'assets/jalebi.png',
strCategory: 'Dessert',
strArea: 'Indian',
strInstructions:
'1. Mix all-purpose flour (maida), chickpea flour (besan), baking powder, and yogurt. Let it ferment for 12 hours.\n2. Prepare sugar syrup by boiling sugar and water with cardamom powder and saffron strands until 1-string consistency.\n3. Pour the batter into a squeeze bottle or piping bag with a small nozzle.\n4. Heat ghee or oil in a flat pan. Squeeze the batter in circular spiral shapes directly into the hot oil.\n5. Fry on medium heat until crispy and golden yellow.\n6. Drain and immediately soak the fried jalebis in the warm sugar syrup for 2-3 minutes. Serve hot!',
ingredients: [
'1 cup All-purpose Flour',
'1/2 cup Water',
'1/2 tsp Cardamom Powder',
'A pinch of Saffron',
'Ghee for frying'
]
}
]
function updateSavedCount () {
const countEl = document.getElementById('saved-count')
if (countEl) countEl.textContent = savedRecipes.length
}
function showToast (msg, color = '#10b981') {
const toast = document.createElement('div')
toast.innerText = msg
toast.className = 'toast-msg'
if (color !== '#10b981') toast.style.background = color
document.body.appendChild(toast)
setTimeout(() => {
toast.style.opacity = '0'
setTimeout(() => toast.remove(), 500)
}, 2500)
}
async function search (query) {
if (!query) {
showToast('Enter a dish name!', '#ef4444')
return
}
grid.innerHTML = "<p class='grid-msg'>Searching recipes...</p>"
let results = []
const localMatches = localIndianRecipes.filter(
r =>
r.strMeal.toLowerCase().includes(query.toLowerCase()) ||
r.strCategory.toLowerCase().includes(query.toLowerCase())
)
if (localMatches.length > 0) {
results = [...localMatches]
}
if (SPOONACULAR_API_KEY && SPOONACULAR_API_KEY !== 'YOUR_API_KEY_HERE') {
try {
const res = await fetch(
`https://api.spoonacular.com/recipes/complexSearch?query=${query}&apiKey=${SPOONACULAR_API_KEY}&number=10`
)
if (res.ok) {
const data = await res.json()
if (data.results && data.results.length > 0) {
const spoonMeals = data.results.map(r => ({
idMeal: `spoon_${r.id}`,
strMeal: r.title,
strMealThumb: r.image
}))
results = [...results, ...spoonMeals]
}
}
} catch (e) {
console.warn('Spoonacular fetch failed, moving to fallback:', e)
}
}
try {
const res = await fetch(
`https://www.themealdb.com/api/json/v1/1/search.php?s=${query}`
)
const data = await res.json()
if (data.meals) {
const existingNames = new Set(results.map(r => r.strMeal.toLowerCase()))
const filteredMeals = data.meals.filter(
m => !existingNames.has(m.strMeal.toLowerCase())
)
results = [...results, ...filteredMeals]
}
} catch (e) {
console.error('TheMealDB fetch failed:', e)
}
searchCache = results
render(searchCache)
}
function render (meals) {
grid.innerHTML = ''
if (!meals || meals.length === 0) {
grid.innerHTML =
"<p class='grid-msg'>Dish not found. Try searching 'Pizza', 'Paneer', 'Samosa', or 'Burger'.</p>"
return
}
meals.forEach(m => {
const card = document.createElement('div')
card.className = 'recipe-card'
card.innerHTML = `<img src="${m.strMealThumb}" alt="${m.strMeal}"><h3>${m.strMeal}</h3>`
card.onclick = () => openDetails(m.idMeal)
grid.appendChild(card)
})
}
async function openDetails (id) {
try {
let meal = null
let ings = []
if (id.startsWith('local_')) {
meal = localIndianRecipes.find(r => r.idMeal === id)
ings = meal.ingredients
} else if (id.startsWith('spoon_')) {
const cleanId = id.replace('spoon_', '')
grid.innerHTML =
"<p class='grid-msg'>Loading details from Spoonacular...</p>"
const res = await fetch(
`https://api.spoonacular.com/recipes/${cleanId}/information?apiKey=${SPOONACULAR_API_KEY}`
)
const mealData = await res.json()
meal = {
idMeal: id,
strMeal: mealData.title,
strMealThumb: mealData.image,
strCategory: mealData.dishTypes
? mealData.dishTypes.join(', ')
: 'General',
strArea: mealData.cuisines ? mealData.cuisines.join(', ') : 'Global',
strInstructions: mealData.instructions
? mealData.instructions.replace(/<[^>]*>/g, '')
: 'Enjoy your meal!'
}
ings = mealData.extendedIngredients
? mealData.extendedIngredients.map(i => i.original)
: []
} else {
const res = await fetch(
`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${id}`
)
const data = await res.json()
const dbMeal = data.meals[0]
meal = dbMeal
for (let i = 1; i <= 20; i++) {
const item = dbMeal[`strIngredient${i}`]
if (item && item.trim()) {
ings.push(`${dbMeal[`strMeasure${i}`] || ''} ${item}`.trim())
} else {
break
}
}
}
const isSaved = savedRecipes.some(r => r.idMeal === meal.idMeal)
modalContent.innerHTML = `
<h2 class="modal-dish-title">${meal.strMeal}</h2>
<img class="modal-dish-img" src="${meal.strMealThumb}">
<p><strong>Category:</strong> ${
meal.strCategory
} | <strong>Area:</strong> ${meal.strArea}</p>
<h4 class="modal-sub-title">Ingredients:</h4>
<ul class="ing-list">${ings.map(i => `<li>${i}</li>`).join('')}</ul>
<h4 class="modal-sub-title">Steps:</h4>
<p class="modal-steps-text">${meal.strInstructions}</p>
<button id="save-recipe-btn" class="save-btn ${
isSaved ? 'saved' : ''
}">
${isSaved ? '✓ Saved in Book' : '❤ Save Recipe'}
</button>
`
document.getElementById('save-recipe-btn').onclick = () => toggleSave(meal)
modal.classList.remove('hidden')
} catch (e) {
showToast("Can't load details", '#ef4444')
console.error(e)
}
}
function toggleSave (meal) {
const idx = savedRecipes.findIndex(r => r.idMeal === meal.idMeal)
const btn = document.getElementById('save-recipe-btn')
if (idx === -1) {
savedRecipes.push(meal)
btn.innerText = '✓ Saved in Book'
btn.classList.add('saved')
showToast('Recipe Saved! ❤')
} else {
savedRecipes.splice(idx, 1)
btn.innerText = '❤ Save Recipe'
btn.classList.remove('saved')
showToast('Removed from Book', '#64748b')
}
localStorage.setItem('saved_dishes', JSON.stringify(savedRecipes))
updateSavedCount()
}
searchBtn.onclick = () => search(input.value)
if (homeBtn) {
homeBtn.onclick = e => {
e.preventDefault()
input.value = ''
fetchInitialIndian()
}
}
input.onkeypress = e => {
if (e.key === 'Enter') search(input.value)
}
savedLink.onclick = e => {
e.preventDefault()
render(savedRecipes)
}
closeModal.onclick = () => modal.classList.add('hidden')
window.onclick = e => {
if (e.target === modal) modal.classList.add('hidden')
}
async function fetchInitialIndian () {
grid.innerHTML = "<p class='grid-msg'>Cooking up Ghar Ka Khana...</p>"
try {
const res = await fetch(
'https://www.themealdb.com/api/json/v1/1/filter.php?a=Indian'
)
let data = await res.json()
const vegIds = ['52785', '52807', '52868', '52865']
const nonVegIds = ['52806', '52795']
const orderedIds = [...vegIds, ...nonVegIds]
let meals = []
if (data.meals) {
const filtered = data.meals.filter(m => orderedIds.includes(m.idMeal))
filtered.sort(
(a, b) => orderedIds.indexOf(a.idMeal) - orderedIds.indexOf(b.idMeal)
)
meals = filtered
}
meals = [...localIndianRecipes, ...meals]
render(meals)
} catch (e) {
render(localIndianRecipes)
}
}
document.addEventListener('DOMContentLoaded', () => {
updateSavedCount()
fetchInitialIndian()
})