-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JS RECIPE CODE #24
base: main
Are you sure you want to change the base?
JS RECIPE CODE #24
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
const YOUR_API_KEY = "67f9082ad89f4a5dbe3f592aca788d38"; | ||
const URL = `https://api.spoonacular.com/recipes/random?number=4&apiKey=${YOUR_API_KEY}`; // Fetch 4 recipes | ||
let recipes = []; | ||
// Fetch recipes from the API STANDARD FETCH FUNCTION | ||
const fetchRecipes = () => { | ||
//Use cached fetches if available so i dont run out of api calls | ||
if(recipe.cousines) {} | ||
|
||
fetch(URL) | ||
.then(response => response.json()) | ||
.then(data => { | ||
console.log("Fetched new recipes:", data.recipes); | ||
|
||
recipes = data.recipes; // Store fetched recipes in global variable | ||
localStorage.setItem('recipes', JSON.stringify(recipes)); | ||
|
||
// Process each recipe | ||
recipes.forEach(recipe => handleRecipeData(recipe)); | ||
|
||
// Now that recipes are fetched, add sorting functionality | ||
sortTime(); | ||
sortPrice(); | ||
}) | ||
.catch(error => console.error('Error fetching the data:', error)); | ||
}; | ||
//Use cached fetches if available so i dont run out of api | ||
|
||
// Fetch and cache recipes on page load | ||
document.addEventListener('DOMContentLoaded', fetchRecipes); | ||
|
||
// Handle the recipe data and create recipe cards | ||
const handleRecipeData = (recipe) => { | ||
const container = document.getElementById('container'); | ||
const recipeCard = document.createElement('section'); | ||
const time = recipe.readyInMinutes ? `${recipe.readyInMinutes} min` : 'Unknown Time'; | ||
const popularity = recipe.veryPopular ? "Very Popular" : "Not Popular"; | ||
|
||
recipeCard.classList.add('card'); | ||
|
||
// Store all cuisines in a data attribute | ||
const cuisines = recipe.cuisines && recipe.cuisines.length > 0 ? recipe.cuisines.map(c => c.toLowerCase()).join(",") : ""; | ||
recipeCard.setAttribute("data-cuisines", cuisines); | ||
|
||
// Assign classes for filtering | ||
if (recipe.vegetarian) { | ||
recipeCard.classList.add('vegetarian'); | ||
} | ||
if (recipe.veryPopular) { | ||
recipeCard.classList.add('very-popular'); | ||
} | ||
if (recipe.readyInMinutes) { | ||
recipeCard.classList.add('time'); | ||
} | ||
|
||
if (recipe.cheap) { | ||
recipeCard.classList.add('cheap'); | ||
} | ||
|
||
if (recipe.veryHealthy) { | ||
recipeCard.classList.add('healthy-food'); | ||
} | ||
|
||
recipeCard.innerHTML = ` | ||
<img src="${recipe.image || 'default-image.jpg'}" alt="${recipe.title}" /> | ||
<h2>${recipe.title || 'Unknown Title'}</h2> | ||
<p><strong>Cuisine:</strong> ${cuisines || 'Unknown'}</p> | ||
<p class="details"> | ||
<span class="bold">Time: </span>${time} | ||
</p> | ||
<p class="details"> | ||
<span class="bold">Popularity: </span>${popularity} | ||
</p> | ||
<p class="details"> | ||
<span class="bold">This dish is: </span>${recipe.cheap ? "Cheap" : "Not cheap"} | ||
</p> | ||
<p class="details"> | ||
<span class="bold">Price: </span>${recipe.pricePerServing}kr | ||
</p> | ||
<p class="details"> | ||
<span class="bold">This dish is: </span>${recipe.veryHealthy ? "Healthy" : "Not very healthy"} | ||
</p> | ||
<hr /> | ||
<div class="ingredients"> | ||
<p class="details bold">Ingredients</p> | ||
<ul> | ||
${recipe.extendedIngredients?.map(ingredient => `<li>${ingredient.name}</li>`).join('') || '<li>Unknown Ingredients</li>'} | ||
</ul> | ||
</div> | ||
|
||
`; | ||
|
||
|
||
container.appendChild(recipeCard); | ||
}; | ||
console.log(recipes[Math.floor(Math.random() * recipes.length)]); | ||
|
||
function addToFavorites(recipeTitle) { | ||
// Get existing favorites from local storage or initialize an empty array | ||
let favorites = JSON.parse(localStorage.getItem('favorites')) || []; | ||
|
||
// Add the new recipe to the favorites array | ||
favorites.push(recipeTitle); | ||
|
||
// Save the updated favorites array to local storage | ||
localStorage.setItem('favorites', JSON.stringify(favorites)); | ||
|
||
alert(`${recipeTitle} has been added to your favorites!`); | ||
} | ||
function sortTime() { | ||
document.getElementById("hightolowbtn").addEventListener("click", () => { | ||
// Create a copy of the recipes array and sort by time | ||
const sortedRecipes = [...recipes].sort((a, b) => (b.readyInMinutes || 0) - (a.readyInMinutes || 0)); | ||
|
||
// Clear the container before appending sorted recipes | ||
const container = document.getElementById("container"); | ||
container.innerHTML = ""; | ||
|
||
// Append sorted recipes | ||
sortedRecipes.forEach(recipe => handleRecipeData(recipe)); | ||
}); | ||
} | ||
|
||
function sortPrice() { | ||
document.getElementById("sort-price-btn").addEventListener("click", () => { | ||
// Create a copy of the recipes array and sort by price from high to low | ||
const sortedRecipes = [...recipes].sort((a, b) => (b.pricePerServing || 0) - (a.pricePerServing || 0)); | ||
|
||
// Clear the container before appending sorted recipes | ||
const container = document.getElementById("container"); | ||
container.innerHTML = ""; | ||
|
||
// Append sorted recipes | ||
sortedRecipes.forEach(recipe => handleRecipeData(recipe)); | ||
}); | ||
}function randomize() { | ||
document.getElementById("random-btn").addEventListener("click", () => { | ||
console.log("Fetching 4 new random recipes..."); | ||
|
||
// Fetch new recipes from the API (DO NOT use cached ones) | ||
fetch(URL) | ||
.then(response => response.json()) | ||
.then(data => { | ||
console.log("New random recipes:", data.recipes); | ||
|
||
recipes = data.recipes; // Update global variable | ||
localStorage.setItem("recipes", JSON.stringify(recipes)); // Cache the new recipes | ||
|
||
// Clear and display new recipes | ||
const container = document.getElementById("container"); | ||
container.innerHTML = ""; | ||
recipes.forEach(recipe => handleRecipeData(recipe)); | ||
}) | ||
.catch(error => console.error("Error fetching new recipes:", error)); | ||
}); | ||
} | ||
|
||
// Run when page loads | ||
document.addEventListener("DOMContentLoaded", () => { | ||
fetchRecipes(); // Load initial recipes | ||
randomize(); // Ensure the button fetches new ones | ||
sortTime(); | ||
sortPrice(); | ||
}); | ||
// Fetch recipes when page is loaded | ||
// Call randomize to attach event listener |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// cook.js | ||
|
||
// Key and values for filter buttons | ||
const obj = { | ||
"china-btn": "chinese", | ||
"italy-btn": "italian", | ||
"usa-btn": "american", | ||
"all-btn": "all", | ||
"asia-btn": "asian", | ||
"popular-btn": "popular", | ||
"vegetarian-btn": "vegetarian", | ||
"hightolowbtn": "hightolow", | ||
"sort-price-btn": "sort-price", | ||
"random-btn": "random" | ||
}; | ||
|
||
Object.keys(obj).forEach(buttonId => { | ||
const button = document.getElementById(buttonId); | ||
button.addEventListener("click", () => { | ||
const targetElementId = obj[buttonId]; | ||
console.log(`Filtering for: ${targetElementId}`); | ||
|
||
document.querySelectorAll(".card").forEach(card => { | ||
const cuisines = card.getAttribute("data-cuisines")?.toLowerCase().split(",") || []; // Store cuisines in a data attribute | ||
const isVegetarian = card.classList.contains("vegetarian"); | ||
const isVeryPopular = card.classList.contains("very-popular"); | ||
|
||
// Show all recipes | ||
if (targetElementId === "all") { | ||
card.style.display = "block"; | ||
} | ||
// Show vegetarian recipes | ||
else if (targetElementId === "vegetarian" && isVegetarian) { | ||
card.style.display = "block"; | ||
} | ||
// Show recipes that match cuisine | ||
else if (cuisines.includes(targetElementId.toLowerCase())) { | ||
card.style.display = "block"; | ||
} | ||
// Show very popular recipes | ||
else if (targetElementId === "popular" && isVeryPopular) { | ||
card.style.display = "block"; | ||
} | ||
// Hide all other cards | ||
else { | ||
card.style.display = "none"; | ||
} | ||
}); | ||
}); | ||
}); | ||
|
||
|
||
// Example clock function to display the current time in the console. not being used right now | ||
const clock = () => { | ||
let currentTime = new Date(); //to get the current time | ||
let hrs = (currentTime.getHours() < 10 ? "0" : "") + currentTime.getHours(); //to display hours and give double digit output | ||
let mins = (currentTime.getMinutes() < 10 ? "0" : "") + currentTime.getMinutes(); //to display minutes and give double digit output | ||
let sec = (currentTime.getSeconds() < 10 ? "0" : "") + currentTime.getSeconds(); //to display seconds and give double digit output | ||
|
||
console.clear(); //clear the console to continuously update the time | ||
console.log(hrs +':'+ mins +':'+ sec); //display the current time | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<link rel="stylesheet" href="styles.css"> | ||
<title>Recipe Library</title> | ||
</head> | ||
<body> | ||
<h1>Recipe Library</h1> | ||
<section class="filters"> | ||
<div> | ||
<h2>Filter cousines</h2> | ||
<button type="button" class="filter" id="all-btn">All</button> | ||
<button type="button" class="filter" id="italy-btn">Italian</button> | ||
<button type="button" class="filter" id="usa-btn">American</button> | ||
<button type="button" class="filter" id="asia-btn">Asian</button> | ||
<button type="button" class="filter" id="china-btn">Chinese</button> | ||
<button type="button" class="filter" id="vegetarian-btn">Vegetarian</button> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "Vegetarian" is supposed to be included in diet and not cuisines? |
||
</div> | ||
<div> | ||
<h2>Sort on by</h2> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just simple change in typo, change "Sort on by" to "Sort by". Nothing major! |
||
<button class="sort" id="hightolowbtn">Cooking time</button> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe change to "high-to-low-btn" or "highlow-btn" for better readability. |
||
<button type="button" class="sort" id="popular-btn">Popularity</button> | ||
<button class="sort" id="sort-price-btn">Price</button> | ||
<button class="sort" id="random-btn">Random</button> | ||
</div> | ||
</section> | ||
<section class="recipes" id="container"> | ||
<!-- Recipe cards will be dynamically added here --> | ||
</section> | ||
<script src="cook.js"></script> | ||
<script src="api.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* General Styles */ | ||
body { | ||
font-family: Montserrat, sans-serif; | ||
background-color: #FAFBFF; | ||
margin: 0; | ||
padding: 10px; | ||
} | ||
|
||
h1 { | ||
color: #0018A4; | ||
font-size: 48px; | ||
font-weight: 700; | ||
text-align: center; | ||
} | ||
|
||
h2 { | ||
font-size: 22px; | ||
font-weight: 700; | ||
} | ||
|
||
/* Filters & Sorting */ | ||
.filters { | ||
display: flex; | ||
justify-content: center; | ||
flex-wrap: wrap; | ||
gap: 20px; | ||
margin: 20px 0; | ||
} | ||
|
||
.filter-group, | ||
.sort-group { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
button { | ||
padding: 10px 16px; | ||
border-radius: 50px; | ||
outline: 0; | ||
border: 2px solid transparent; | ||
font-size: 16px; | ||
font-weight: 500; | ||
cursor: pointer; | ||
} | ||
|
||
button:hover { | ||
border: 2px solid #0018A4; | ||
} | ||
|
||
.filter { | ||
background: #CCFFE2; | ||
color: #0018A4; | ||
} | ||
|
||
.filter.active { | ||
background: #0018A4; | ||
color: white; | ||
} | ||
|
||
.sort { | ||
background: #FFECEA; | ||
} | ||
|
||
.sort.active { | ||
background: #FF6589; | ||
color: white; | ||
} | ||
|
||
/* Special Button Styles */ | ||
.popular-btn { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are using the class .popular-btn , but you have used an id though in your HTML file. |
||
background: #FF6589; /* Red for Popularity */ | ||
color: white; | ||
} | ||
|
||
.cooking-time-btn:hover, | ||
.popular-btn:hover, | ||
.price-btn:hover, | ||
.random-btn:hover { | ||
background: #FF6589; /* Red hover */ | ||
color: white; | ||
} | ||
|
||
.cooking-time-btn:active, | ||
.popular-btn:active, | ||
.price-btn:active, | ||
.random-btn:active { | ||
background: #FF6589; /* Red active */ | ||
color: white; | ||
} | ||
|
||
/* Recipe Grid */ | ||
|
||
.recipes { | ||
display: grid; | ||
grid-template-columns: repeat(2, 1fr); /* Two columns per row */ | ||
gap: 20px; /* More space between cards */ | ||
justify-content: center; | ||
padding: 20px; | ||
} | ||
|
||
.card { | ||
background: white; | ||
padding: 16px; /* Increased padding */ | ||
border-radius: 12px; /* Smoother edges */ | ||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); /* Slightly deeper shadow */ | ||
text-align: center; | ||
max-width: 450px; /* Bigger cards */ | ||
margin: auto; | ||
transition: transform 0.2s ease-in-out; | ||
} | ||
|
||
.card:hover { | ||
transform: translateY(-5px); | ||
} | ||
|
||
img { | ||
width: 100%; | ||
height: 350px; | ||
object-fit: cover; | ||
border-radius: 10px; | ||
} | ||
|
||
p { | ||
font-size: 16px; | ||
} | ||
|
||
/* Mobile Responsive Design */ | ||
@media (max-width: 768px) { | ||
h1 { | ||
font-size: 36px; | ||
} | ||
|
||
.filters { | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
button { | ||
font-size: 14px; | ||
padding: 8px; | ||
width: 90%; | ||
} | ||
|
||
.recipes { | ||
grid-template-columns: 1fr; /* Single-column layout */ | ||
} | ||
} | ||
|
||
@media (max-width: 480px) { | ||
h1 { | ||
font-size: 28px; | ||
} | ||
|
||
button { | ||
font-size: 14px; | ||
padding: 10px; | ||
width: 100%; | ||
} | ||
|
||
.recipes { | ||
grid-template-columns: 1fr; | ||
gap: 12px; | ||
} | ||
|
||
.card { | ||
padding: 12px; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just commenting the typo, should be "Filter cuisines".