Skip to content

Commit 7cc7109

Browse files
committed
add meal finder app
1 parent 11b9c73 commit 7cc7109

File tree

4 files changed

+327
-0
lines changed

4 files changed

+327
-0
lines changed

Diff for: 66-meal finder/index.html

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link
7+
rel="stylesheet"
8+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
9+
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
10+
crossorigin="anonymous"
11+
/>
12+
<link rel="stylesheet" href="style.css" />
13+
<title>Meal Finder</title>
14+
</head>
15+
<body>
16+
<div class="container">
17+
<h1>Meal Finder</h1>
18+
<div class="flex">
19+
<form class="flex" id="submit">
20+
<input
21+
type="text"
22+
id="search"
23+
placeholder="Search for meals or keywords"
24+
/>
25+
<button class="search-btn" type="submit">
26+
<i class="fas fa-search"></i>
27+
</button>
28+
</form>
29+
<button class="random-btn" id="random">
30+
<i class="fas fa-random"></i>
31+
</button>
32+
</div>
33+
34+
<div id="result-heading"></div>
35+
<div id="meals" class="meals"></div>
36+
<div id="single-meal"></div>
37+
</div>
38+
<script src="script.js"></script>
39+
</body>
40+
</html>

Diff for: 66-meal finder/script.js

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const search = document.getElementById("search");
2+
const submit = document.getElementById("submit");
3+
const random = document.getElementById("random");
4+
const mealsElement = document.getElementById("meals");
5+
const resultHeading = document.getElementById("result-heading");
6+
const singleMealElement = document.getElementById("single-meal");
7+
8+
function searchMeal(e) {
9+
e.preventDefault();
10+
singleMealElement.innerHTML = "";
11+
const term = search.value;
12+
if (term.trim()) {
13+
fetch(`https://www.themealdb.com/api/json/v1/1/search.php?s=${term}`)
14+
.then((res) => res.json())
15+
.then((data) => {
16+
resultHeading.innerHTML = `<h2>Search results for '${term}':</h2>`;
17+
if (data.meals === null) {
18+
resultHeading.innerHTML =
19+
"<p>There are no search results. Try again!</p>";
20+
} else {
21+
mealsElement.innerHTML = data.meals
22+
.map(
23+
(meal) => `
24+
<div class="meal">
25+
<img src="${meal.strMealThumb}" alt="${meal.strMeal}" />
26+
<div class="meal-info" data-mealID="${meal.idMeal}">
27+
<h3>${meal.strMeal}</h3>
28+
</div>
29+
</div>
30+
`
31+
)
32+
.join("");
33+
}
34+
});
35+
search.value = "";
36+
} else {
37+
alert("Please enter a search term");
38+
}
39+
}
40+
41+
function getMealById(mealID) {
42+
fetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealID}`)
43+
.then((res) => res.json())
44+
.then((data) => {
45+
const meal = data.meals[0];
46+
addMealToDOM(meal);
47+
singleMealElement.scrollIntoView();
48+
});
49+
}
50+
51+
function getRandomMeal() {
52+
mealsElement.innerHTML = "";
53+
resultHeading.innerHTML = "";
54+
fetch("https://www.themealdb.com/api/json/v1/1/random.php")
55+
.then((res) => res.json())
56+
.then((data) => {
57+
const meal = data.meals[0];
58+
addMealToDOM(meal);
59+
});
60+
}
61+
62+
function addMealToDOM(meal) {
63+
const ingredients = [];
64+
for (let i = 1; i <= 20; i++) {
65+
if (meal[`strIngredient${i}`]) {
66+
ingredients.push(
67+
`${meal[`strIngredient${i}`]} - ${meal[`strMeasure${i}`]}`
68+
);
69+
} else {
70+
break;
71+
}
72+
}
73+
singleMealElement.innerHTML = `
74+
<div class="single-meal">
75+
<h1>${meal.strMeal}</h1>
76+
<img src="${meal.strMealThumb}" alt="${meal.strMeal}" />
77+
<div class="main">
78+
<h2>Ingredients</h2>
79+
<ul>
80+
${ingredients.map((ingredient) => `<li>${ingredient}</li>`).join("")}
81+
</ul>
82+
<p>${meal.strInstructions}</p>
83+
</div>
84+
<div class="single-meal-info">
85+
${meal.strCategory ? `<p>${meal.strCategory}</p>` : ""}
86+
${meal.strArea ? `<p>${meal.strArea}</p>` : ""}
87+
</div>
88+
</div>
89+
`;
90+
}
91+
92+
submit.addEventListener("submit", searchMeal);
93+
random.addEventListener("click", getRandomMeal);
94+
mealsElement.addEventListener("click", (e) => {
95+
const mealInfo = e.path.find((item) => {
96+
if (item.classList) {
97+
return item.classList.contains("meal-info");
98+
} else {
99+
return false;
100+
}
101+
});
102+
103+
if (mealInfo) {
104+
const mealID = mealInfo.getAttribute("data-mealid");
105+
getMealById(mealID);
106+
}
107+
});
108+
109+
// Init
110+
getRandomMeal();

Diff for: 66-meal finder/style.css

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
@import url("https://fonts.googleapis.com/css2?family=Akaya+Telivigala&display=swap");
2+
3+
:root {
4+
--main-color: #e4e0ef;
5+
--light-color: #301c17;
6+
--border-color: #ada3d4;
7+
--border-color-secondary: #473fb5;
8+
--shadow-color: rgba(0, 0, 0, 0.7);
9+
}
10+
11+
* {
12+
box-sizing: border-box;
13+
}
14+
15+
body {
16+
background-color: var(--main-color);
17+
color: var(--light-color);
18+
font-family: "Akaya Telivigala", cursive;
19+
margin: 0;
20+
}
21+
22+
.container {
23+
margin: auto;
24+
max-width: 800px;
25+
display: flex;
26+
flex-direction: column;
27+
align-items: center;
28+
justify-content: center;
29+
text-align: center;
30+
}
31+
32+
.flex {
33+
display: flex;
34+
}
35+
36+
input,
37+
button {
38+
border: 1px solid var(--border-color);
39+
border-top-left-radius: 4px;
40+
border-bottom-left-radius: 4px;
41+
font-size: 14px;
42+
padding: 8px 10px;
43+
margin: 0;
44+
}
45+
46+
input[type="text"] {
47+
width: 100%;
48+
}
49+
50+
button {
51+
background-color: var(--border-color-secondary);
52+
color: var(--main-color);
53+
}
54+
55+
input[type="text"]:focus,
56+
button:focus {
57+
outline: none;
58+
}
59+
60+
button:active {
61+
transform: scale(0.98);
62+
}
63+
64+
.search-btn {
65+
cursor: pointer;
66+
border-left: 0;
67+
border-radius: 0;
68+
border-top-right-radius: 4px;
69+
border-bottom-right-radius: 4px;
70+
}
71+
72+
.random-btn {
73+
cursor: pointer;
74+
margin-left: 10px;
75+
border-top-right-radius: 4px;
76+
border-bottom-right-radius: 4px;
77+
}
78+
79+
.meals {
80+
display: grid;
81+
grid-template-columns: repeat(2, 1fr);
82+
gap: 20px;
83+
margin-top: 20px;
84+
}
85+
86+
.meal {
87+
cursor: pointer;
88+
position: relative;
89+
height: 180px;
90+
width: 180px;
91+
text-align: center;
92+
}
93+
94+
.meal img {
95+
width: 100%;
96+
height: 100%;
97+
border: 4px var(--border-color) solid;
98+
border-radius: 2px;
99+
}
100+
101+
.meal-info {
102+
position: absolute;
103+
top: 0;
104+
left: 0;
105+
height: 100%;
106+
width: 100%;
107+
background-color: var(--shadow-color);
108+
display: flex;
109+
align-items: center;
110+
justify-content: center;
111+
opacity: 0;
112+
transition: opacity 0.2s ease-in;
113+
}
114+
115+
.meal:hover .meal-info {
116+
color: var(--main-color);
117+
opacity: 1;
118+
}
119+
120+
.single-meal {
121+
margin: 30px auto;
122+
width: 70%;
123+
}
124+
125+
.single-meal img {
126+
width: 300px;
127+
margin: 15px;
128+
border: 4px var(--border-color) solid;
129+
border-radius: 2px;
130+
}
131+
132+
.single-meal-info {
133+
margin: 20px;
134+
padding: 10px;
135+
border: 2px var(--border-color-secondary) dashed;
136+
border-radius: 5px;
137+
}
138+
139+
.single-meal p {
140+
margin: 0;
141+
letter-spacing: 0.5px;
142+
line-height: 1.5;
143+
text-align: left;
144+
}
145+
146+
.single-meal ul {
147+
padding-left: 0;
148+
list-style-type: none;
149+
}
150+
151+
.single-meal ul li {
152+
border: 1px var(--border-color) solid;
153+
border-radius: 5px;
154+
background-color: var(--light-color);
155+
display: inline-block;
156+
color: var(--main-color);
157+
font-size: 1.1rem;
158+
padding: 5px;
159+
margin: 0 5px 5px 0;
160+
}
161+
162+
@media (min-width: 740px) {
163+
input[type="text"] {
164+
width: 300px;
165+
}
166+
167+
.meals {
168+
grid-template-columns: repeat(3, 1fr);
169+
}
170+
}
171+
172+
@media (min-width: 940px) {
173+
.meals {
174+
grid-template-columns: repeat(4, 1fr);
175+
}
176+
}

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
| 63 | [DOM Array Methods](https://github.com/solygambas/html-css-fifty-projects/tree/master/63-DOM%20array%20methods) | [Live Demo](https://codepen.io/solygambas/full/NWbeXYR) |
7272
| 64 | [Menu Slider & Modal](https://github.com/solygambas/html-css-fifty-projects/tree/master/64-menu%20slider%20modal) | [Live Demo](https://codepen.io/solygambas/full/MWbLeKd) |
7373
| 65 | [Hangman Game](https://github.com/solygambas/html-css-fifty-projects/tree/master/65-hangman%20game) | [Live Demo](https://codepen.io/solygambas/full/MWbLEYr) |
74+
| 66 | [Meal Finder App](https://github.com/solygambas/html-css-fifty-projects/tree/master/66-meal%20finder) | [Live Demo](https://codepen.io/solygambas/full/dyOagYE) |
7475

7576
Mainly based on 2 courses by Brad Traversy (2020):
7677

0 commit comments

Comments
 (0)