Skip to content

Commit 3a78a8a

Browse files
Merge pull request #121 from Shaily-62/recipes-dashboard-ui
Improve the Ui of recipe dashboard.
2 parents c4d2854 + 78e3486 commit 3a78a8a

File tree

7 files changed

+444
-64
lines changed

7 files changed

+444
-64
lines changed

src/Images/burger.jpg

333 KB
Loading

src/Images/chicken.jpg

271 KB
Loading

src/Images/paneerBriyani.jpg

128 KB
Loading

src/Images/pasta.jpg

333 KB
Loading

src/Images/salad.jpeg

264 KB
Loading

src/pages/Recipes.jsx

Lines changed: 131 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,74 +17,143 @@
1717
* - [ ] Offline caching of last search
1818
* - [ ] Extract service + hook (useMealsSearch)
1919
*/
20-
import { useEffect, useState } from 'react';
21-
import Loading from '../components/Loading.jsx';
22-
import ErrorMessage from '../components/ErrorMessage.jsx';
23-
import Card from '../components/Card.jsx';
24-
import HeroSection from '../components/HeroSection';
25-
import Food from '../Images/Food.jpg';
20+
import React, { useState } from "react";
2621

27-
export default function Recipes() {
28-
const [ingredient, setIngredient] = useState('chicken');
29-
const [meals, setMeals] = useState([]);
30-
const [randomMeal, setRandomMeal] = useState(null);
31-
const [loading, setLoading] = useState(false);
32-
const [error, setError] = useState(null);
3322

34-
useEffect(() => { search(); }, []);
3523

36-
async function search() {
37-
try {
38-
setLoading(true); setError(null);
39-
const res = await fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${encodeURIComponent(ingredient)}`);
40-
if (!res.ok) throw new Error('Failed to fetch');
41-
const json = await res.json();
42-
setMeals(json.meals || []);
43-
} catch (e) { setError(e); } finally { setLoading(false); }
44-
}
24+
export default function App() {
25+
const [query, setQuery] = useState("");
26+
const [loadedImages, setLoadedImages] = useState({});
27+
const [isDark, setIsDark] = useState(false);
4528

46-
async function random() {
47-
try {
48-
setLoading(true); setError(null);
49-
const res = await fetch('https://www.themealdb.com/api/json/v1/1/random.php');
50-
if (!res.ok) throw new Error('Failed to fetch');
51-
const json = await res.json();
52-
setRandomMeal(json.meals?.[0] || null);
53-
} catch (e) { setError(e); } finally { setLoading(false); }
54-
}
29+
const dishes = [
30+
{
31+
id: 1,
32+
name: "Cheesy Burger",
33+
category: "Fast Food",
34+
area: "American",
35+
desc: "Juicy, cheesy and delicious.",
36+
img: "/src/images/burger.jpg",
37+
},
38+
{
39+
id: 2,
40+
name: "Creamy Pasta",
41+
category: "Main Course",
42+
area: "Italian",
43+
desc: "Rich and flavorful with herbs.",
44+
img: "/src/images/pasta.jpg",
45+
},
46+
{
47+
id: 3,
48+
name: "Fresh Salad",
49+
category: "Healthy",
50+
area: "Mediterranean",
51+
desc: "Crisp greens with a tangy dressing.",
52+
img: "/src/images/salad.jpeg",
53+
},
54+
];
55+
56+
const randomRecipe = [{
57+
id: 1,
58+
name: "Chicken Tikka Masala",
59+
category: "Main Course",
60+
area: "Indian",
61+
desc: "Aromatic curry with tender chicken pieces.",
62+
img: "/src/images/chicken.jpg",
63+
},
64+
{
65+
id: 2,
66+
name: "paneer Briyani",
67+
category: "Main Course",
68+
area: "Indian",
69+
desc: "Paneer biryani is a fragrant dish made with spiced paneer and basmati rice..",
70+
img: "/src/images/paneerBriyani.jpg",
71+
},
72+
];
73+
74+
75+
const filteredDishes = dishes.filter((dish) =>
76+
dish.name.toLowerCase().includes(query.toLowerCase())
77+
);
78+
79+
const filterRandomRecipe = randomRecipe.filter((randomDish) =>
80+
randomDish.name.toLowerCase().includes(query.toLowerCase())
81+
);
5582

5683
return (
57-
<div>
58-
<HeroSection
59-
image={Food}
60-
title={
61-
<>
62-
Delicious Made <span style={{ color: 'yellow' }}>Simple</span>
63-
</>
64-
}
65-
subtitle="Wholesome recipes with heart, made easy for every home cook"
66-
/>
67-
<h2>Recipe Finder</h2>
68-
<form onSubmit={e => { e.preventDefault(); search(); }} className="inline-form">
69-
<input value={ingredient} onChange={e => setIngredient(e.target.value)} placeholder="Ingredient" />
70-
<button type="submit">Search</button>
71-
<button type="button" onClick={random}>Random</button>
72-
</form>
73-
{loading && <Loading />}
74-
<ErrorMessage error={error} />
75-
{randomMeal && (
76-
<Card title={`Random: ${randomMeal.strMeal}`} footer={<a href={randomMeal.strSource} target="_blank" rel="noreferrer">Source</a>}>
77-
<img src={randomMeal.strMealThumb} alt="" width="100" />
78-
{/* TODO: Show instructions modal */}
79-
</Card>
80-
)}
81-
<div className="grid">
82-
{meals.map(m => (
83-
<Card key={m.idMeal} title={m.strMeal}>
84-
<img src={m.strMealThumb} alt="" width="100" />
85-
</Card>
86-
))}
87-
</div>
84+
<div className={`app ${isDark ? "dark" : "light"}`}>
85+
{/* Header */}
86+
<header>
87+
<h1>🍴 Recipes Dashboard</h1>
88+
</header>
89+
90+
{/* Search Section */}
91+
<section className="search-section">
92+
<h2>Find your next favorite recipe</h2>
93+
<div className="search-box">
94+
<input
95+
type="text"
96+
placeholder="What are you hungry for?"
97+
value={query}
98+
onChange={(e) => setQuery(e.target.value)}
99+
className="search-input"
100+
/>
101+
{query && (
102+
<button onClick={() => setQuery("")} className="clear-btn">
103+
104+
</button>
105+
)}
106+
</div>
107+
</section>
108+
109+
{/* Random Recipe */}
110+
<section className="random-recipe">
111+
<div className="cards-grid">
112+
{filterRandomRecipe.map((randomDish) => (
113+
<div className="card" key={randomDish.id}>
114+
<img src={randomDish.img} alt={randomDish.name} className="random-recipe-img" />
115+
<div className="random-recipe-info">
116+
<h3>{randomDish.name}</h3>
117+
<p>{randomDish.desc}</p>
118+
<p className="muted">
119+
{randomDish.category}{randomDish.area}
120+
</p>
121+
<button className="btn btn-primary">View Recipe</button>
122+
</div>
123+
</div>
124+
))}
125+
126+
</div>
127+
</section>
128+
129+
130+
{/* Cards */}
131+
<section className="cards-section">
132+
<h3 className="cards-title">Popular Recipes</h3>
133+
<div className="cards-grid">
134+
{filteredDishes.map((dish) => (
135+
<div className="card" key={dish.id}>
136+
{!loadedImages[dish.id] && <div className="skeleton" />}
137+
<img
138+
src={dish.img}
139+
alt={dish.name}
140+
style={{ display: loadedImages[dish.id] ? "block" : "none" }}
141+
onLoad={() =>
142+
setLoadedImages((prev) => ({ ...prev, [dish.id]: true }))
143+
}
144+
/>
145+
<h4>{dish.name}</h4>
146+
<p className="muted">
147+
{dish.category}{dish.area}
148+
</p>
149+
<p>{dish.desc}</p>
150+
<button className="btn btn-primary">View Recipe</button>
151+
</div>
152+
))}
153+
</div>
154+
</section>
155+
156+
<footer>© {new Date().getFullYear()} Recipes Dashboard</footer>
88157
</div>
89158
);
90159
}

0 commit comments

Comments
 (0)