diff --git a/package.json b/package.json index 8d15f9e..8f7aa48 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,14 @@ "preview": "vite preview" }, "dependencies": { + "@tailwindcss/vite": "^4.1.14", "leaflet": "^1.9.4", "lucide-react": "^0.546.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-leaflet": "^4.2.1", - "react-router-dom": "^6.27.0" + "react-router-dom": "^6.27.0", + "tailwindcss": "^4.1.14" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.1", diff --git a/src/pages/Recipes.jsx b/src/pages/Recipes.jsx index 9b352c1..e36efa4 100644 --- a/src/pages/Recipes.jsx +++ b/src/pages/Recipes.jsx @@ -1,90 +1,144 @@ -/** - * RECIPES DASHBOARD TODOs - * ----------------------- - * Easy: - * - [ ] Show meal category & area on cards - * - [ ] Add skeleton loader for images - * - [ ] Improve random recipe section layout - * - [ ] Add clear search button - * Medium: - * - [ ] Modal or drawer with full instructions & ingredients list - * - [ ] Filter by category / area (use list endpoints) - * - [ ] Pagination or load more - * - [ ] Favorite meals (localStorage) - * Advanced: - * - [ ] Nutrition estimation integration (open API) – optional - * - [ ] Tag-based browsing (ingredient tags) - * - [ ] Offline caching of last search - * - [ ] Extract service + hook (useMealsSearch) - */ -import { useEffect, useState } from 'react'; -import Loading from '../components/Loading.jsx'; -import ErrorMessage from '../components/ErrorMessage.jsx'; -import Card from '../components/Card.jsx'; -import HeroSection from '../components/HeroSection'; -import Food from '../Images/Food.jpg'; + /** + * RECIPES DASHBOARD TODOs + * ----------------------- + * Easy: + * - [ ] Show meal category & area on cards + * - [ ] Add skeleton loader for images + * - [ ] Improve random recipe section layout + * - [ ] Add clear search button + * Medium: + * - [ ] Modal or drawer with full instructions & ingredients list + * - [ ] Filter by category / area (use list endpoints) + * - [ ] Pagination or load more + * - [ ] Favorite meals (localStorage) + * Advanced: + * - [ ] Nutrition estimation integration (open API) – optional + * - [ ] Tag-based browsing (ingredient tags) + * - [ ] Offline caching of last search + * - [ ] Extract service + hook (useMealsSearch) + */ + import { useEffect, useState } from 'react'; + import Loading from '../components/Loading.jsx'; + import ErrorMessage from '../components/ErrorMessage.jsx'; + import Card from '../components/Card.jsx'; + import HeroSection from '../components/HeroSection'; + import Food from '../Images/Food.jpg'; -export default function Recipes() { - const [ingredient, setIngredient] = useState('chicken'); - const [meals, setMeals] = useState([]); - const [randomMeal, setRandomMeal] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); + export default function Recipes() { + const [ingredient, setIngredient] = useState('chicken'); + const [meals, setMeals] = useState([]); + const [randomMeal, setRandomMeal] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); - useEffect(() => { search(); }, []); + useEffect(() => { search(); }, []); - async function search() { - try { - setLoading(true); setError(null); - const res = await fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${encodeURIComponent(ingredient)}`); - if (!res.ok) throw new Error('Failed to fetch'); - const json = await res.json(); - setMeals(json.meals || []); - } catch (e) { setError(e); } finally { setLoading(false); } - } + async function search() { + try { + setLoading(true); setError(null); + const res = await fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${encodeURIComponent(ingredient)}`); + if (!res.ok) throw new Error('Failed to fetch'); + const json = await res.json(); + setMeals(json.meals || []); + } catch (e) { setError(e); } finally { setLoading(false); } + } - async function random() { - try { - setLoading(true); setError(null); - const res = await fetch('https://www.themealdb.com/api/json/v1/1/random.php'); - if (!res.ok) throw new Error('Failed to fetch'); - const json = await res.json(); - setRandomMeal(json.meals?.[0] || null); - } catch (e) { setError(e); } finally { setLoading(false); } - } + async function random() { + try { + setLoading(true); setError(null); + const res = await fetch('https://www.themealdb.com/api/json/v1/1/random.php'); + if (!res.ok) throw new Error('Failed to fetch'); + const json = await res.json(); + setRandomMeal(json.meals?.[0] || null); + } catch (e) { setError(e); } finally { setLoading(false); } + } - return ( -