Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
JS RECIPE CODE
phenomenalCode authored Mar 16, 2025
commit 9869cd3ee67691449e4ba246c64471fb8a2163a1
165 changes: 165 additions & 0 deletions api.js
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
62 changes: 62 additions & 0 deletions cook.js
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
};
35 changes: 35 additions & 0 deletions index.html
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>
Copy link

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".

<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>
Copy link

Choose a reason for hiding this comment

The 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>
Copy link

Choose a reason for hiding this comment

The 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>
Copy link

Choose a reason for hiding this comment

The 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>
169 changes: 169 additions & 0 deletions styles.css
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 {
Copy link

@T-Thiry T-Thiry Mar 23, 2025

Choose a reason for hiding this comment

The 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;
}
}