Skip to content

Conversation

@sandrahagevall
Copy link

Live on Netlify

Here's my current version — some changes or adjustments may be added later on.

Copy link

@Appilistus Appilistus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow!! The code looks great! It is well structured, clean and easy to follow with all comments:) I don't know what to say except that you have done such a fantastic job! The site looks great as well, I really like the animation:D
Really well done!

Comment on lines +36 to +50
<svg
class="heart-icon"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="red"
viewBox="0 0 24 24"
>
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42
4.42 3 7.5 3c1.74 0 3.41 0.81
4.5 2.09C13.09 3.81 14.76 3
16.5 3 19.58 3 22 5.42
22 8.5c0 3.78-3.4 6.86-8.55
11.54L12 21.35z" />
</svg>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know about svg and path tags. So you made your heart icon by coding here? Great job! :D

Comment on lines +82 to +85
<button
id="clearSearchBtn"
class="btn-clear-search"
>✖</button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea to have this button! This makes the search bar looks professional and it is easy to erase the keywords :)

Comment on lines +149 to +152
<div
id="loading"
class="loading"
>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wish I could see this on the browser!

Comment on lines +16 to +20
// ---------- GLOBAL STATE ----------
let selectedFilters = []
let selectedSort = null
let showFavoritesOnly = false
let allRecipes = []

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea to have all global states and elements up here! The code looks clean:)

const now = Date.now()

// Use cached recipes if last fetch was under 24 hours ago
if (lastFetch && (now - lastFetch < 24 * 60 * 60 * 1000)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smart to use the cached data!

// ---------- CORE RENDERING FUNCTIONS ----------
const showRecipes = (recipesArray) => {
// Add animation: fade out and scale down before updating content
recipesContainer.style.opacity = "0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this animation! It looks really good!

Comment on lines +306 to +307
resetFilters()
updateRecipes()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a preference, but I would prefer the filter not to reset and still show random recipes after the second click:) But this works good as well!

}
}

@media (min-width: 2000px) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that you have media query for a bigger screen:) The site looks good!

@JennieDalgren JennieDalgren self-assigned this Oct 23, 2025
Copy link

@JennieDalgren JennieDalgren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good job with this project!

Your code is well structured and easy to follow. You have implemented filters in a smart and tasteful way massaging the data when needed. I also love that you did the favorite feature. And the animations are subtle and absolutely great! Very impressed.
I saw that you've used some new concepts that we havent talked about such as Set. Make sure that you understand the concept so you can explain it to others, even if you found that solution somewhere.

Keep up the good work!

display: none;
width: 0;
opacity: 0;
transition: width 0.3s ease, opacity 0.3s ease;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice animation!

Comment on lines +329 to +336
@keyframes spin {
0% {
transform: rotate(0deg);
}

100% {
transform: rotate(360deg);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +24 to +32
const resetFilters = () => {
selectedFilters = []
selectedSort = null
showFavoritesOnly = false
favBtn.classList.remove("active")
filterButtons.forEach(btn => btn.classList.remove("selected"))
sortButtons.forEach(btn => btn.classList.remove("selected"))
randomButton.classList.remove("selected")
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

smart!

Comment on lines +38 to +42
const fromInstructions = recipe.analyzedInstructions?.flatMap(instr =>
instr.steps?.flatMap(step =>
step.ingredients?.map(i => i.name.toLowerCase().trim())
)
) || []

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice to play around with flatMap

step.ingredients?.map(i => i.name.toLowerCase().trim())
)
) || []
return [...new Set([...fromExtended, ...fromInstructions])]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and Set

Comment on lines +132 to +133
if (recipesArray.length === 0) {
recipesContainer.innerHTML = `<p class="placeholder-output">😢 No recipes match your filter, try choosing another one</p>`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good with empty state

Comment on lines +147 to +154
<svg class="heart-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 24 24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5
2 5.42 4.42 3 7.5 3c1.74 0 3.41 0.81
4.5 2.09C13.09 3.81 14.76 3
16.5 3 19.58 3 22 5.42
22 8.5c0 3.78-3.4 6.86-8.55
11.54L12 21.35z"/>
</svg>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wiie! svg! great job

Comment on lines +161 to +164
// Fade in again after new content is added
recipesContainer.style.opacity = "1"
recipesContainer.style.transform = "scale(1)"
}, 150)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is totally fine but if it starts to be too much styling going on in the js file I suggest to add/remove a css class and deal with the styling there.

Comment on lines +177 to +179
if (showFavoritesOnly === true) {
filteredRecipes = filteredRecipes.filter(recipe => recipe.isFavorite === true)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice implementation of faves

Comment on lines +199 to +208
favBtn.addEventListener("click", () => {
if (showFavoritesOnly === false) {
showFavoritesOnly = true
favBtn.classList.add("active")
} else {
showFavoritesOnly = false
favBtn.classList.remove("active")
}
updateRecipes()
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants