├── .vscode └── settings.json ├── README.md ├── index.html ├── script.js └── style.css /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "liveServer.settings.port": 5501 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🍽️ Meal Explorer – API Learning Project 2 | 3 | This project is a simple web app built to help me learn and practice how to work with **APIs**. It uses **[TheMealDB](https://www.themealdb.com/api.php)** – a free, open-source meal database API – to fetch and display meals based on different filters such as category, ingredient, or area. 4 | 5 | --- 6 | 7 | ## 🎯 Purpose 8 | 9 | The main goal of this project was to **train myself in API integration**, JSON parsing, and dynamic frontend rendering using JavaScript. It was a hands-on way to understand how to: 10 | 11 | - Make HTTP requests 12 | - Work with JSON data 13 | - Use an external API effectively in a web project 14 | - Display data dynamically in the UI 15 | 16 | --- 17 | 18 | ## 🧰 Technologies Used 19 | 20 | - **HTML**, **CSS**, **JavaScript** 21 | - **Fetch API** for HTTP requests 22 | - **TheMealDB API** for meal data 23 | 24 | --- 25 | 26 | ## 🔍 Features 27 | 28 | - Search for meals by name 29 | - Filter meals by category or area 30 | - View full recipe details including ingredients and instructions 31 | - Fetch a random meal suggestion 32 | 33 | --- 34 | 35 | ## 📦 Getting Started 36 | 37 | 1. Clone the repo: 38 | ```bash 39 | git clone https://github.com/melau-eddy/recipe-generator-api 40 | cd mealdb-api-training 41 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |

Get your favorite meals

12 | 13 |
14 | 15 | 21 | 22 | 27 | 28 |
29 | 30 |
31 |
32 |
33 |

Food Name

34 |

The meals cooking procedure will be displayed here once you search for the meal of your choice.

35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const searchMeal = async (e) => { 2 | // Prevent form from submitting and page refresh 3 | e.preventDefault(); 4 | 5 | const input = document.querySelector(".input"); 6 | const title = document.querySelector(".title"); 7 | const info = document.querySelector(".info"); 8 | const img = document.querySelector(".img-content"); 9 | 10 | // Function to display meal info 11 | const showMealInfo = (meal) => { 12 | const { strMeal, strMealThumb, strInstructions } = meal; 13 | title.textContent = strMeal; 14 | img.style.backgroundImage = `url(${strMealThumb})`; 15 | info.textContent = strInstructions; 16 | }; 17 | 18 | // Function to display an alert if meal not found 19 | const showAlert = () => { 20 | alert("Meal not found"); 21 | }; 22 | 23 | // Function to fetch meal data from the API 24 | const fetchMealData = async (val) => { 25 | const res = await fetch(`https://www.themealdb.com/api/json/v1/1/search.php?s=${val}`); 26 | const { meals } = await res.json(); 27 | return meals; 28 | }; 29 | 30 | const val = input.value.trim(); 31 | 32 | if (val) { 33 | const meals = await fetchMealData(val); 34 | 35 | if (!meals || meals.length === 0) { 36 | showAlert(); 37 | return; 38 | } 39 | 40 | meals.forEach(showMealInfo); 41 | } else { 42 | alert("Please try searching for a meal."); 43 | } 44 | }; 45 | 46 | // Add event listener for form submission 47 | const form = document.querySelector("form"); 48 | form.addEventListener("submit", searchMeal); 49 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0px; 3 | padding: 0px; 4 | font-family: sans-serif; 5 | } 6 | 7 | body{ 8 | h1{ 9 | margin-left: 35%; 10 | margin-top: 20px; 11 | } 12 | background-color: rgb(248, 203, 144); 13 | .header-content{ 14 | display: flex; 15 | align-items: center; 16 | justify-content: space-between; 17 | margin: 5% 100px; 18 | 19 | .nav-links{ 20 | display: flex; 21 | flex-direction: row; 22 | gap: 30px; 23 | 24 | a{ 25 | text-decoration: none; 26 | color: black; 27 | } 28 | } 29 | 30 | .search-bar{ 31 | input{ 32 | position: relative; 33 | border-radius: 20px; 34 | padding: 10px; 35 | width: 300px; 36 | } 37 | 38 | button{ 39 | padding: 10px 15px; 40 | border-radius: 10px; 41 | margin-left: 10px; 42 | } 43 | } 44 | } 45 | 46 | .body-content{ 47 | display: flex; 48 | align-items: center; 49 | justify-content: space-between; 50 | margin: 10px 200px; 51 | border: 1px solid; 52 | padding: 30px; 53 | border-radius: 20px; 54 | gap: 100px; 55 | .img-content{ 56 | width: 600px; 57 | height: 600px; 58 | border-radius:50%; 59 | object-fit: cover; 60 | } 61 | .text-content{ 62 | display: flex; 63 | flex-direction: column; 64 | gap: 20px; 65 | 66 | p{ 67 | max-width: 600px; 68 | } 69 | 70 | button{ 71 | width: 15%; 72 | padding: 8px 15px; 73 | border-radius: 10px; 74 | } 75 | } 76 | } 77 | } --------------------------------------------------------------------------------