-
Notifications
You must be signed in to change notification settings - Fork 60
JS Project Recipe Library - Gabriella #58
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
base: main
Are you sure you want to change the base?
Conversation
…lass active on click
…a message based on it
…o placeholder card
…ons that should not be active at the same time
…e info from an array of recipes
add the functions for creating its elements and fetching recipe info inside it.
…andom button + refactoring functions
…rs + refactor button logic of what can be active at the same time
… to them to toggle active state
…y it if fetch is empty or fails
…ardless of if it contains data from fetch or local storage
…en to be compatible with an array for the cuisines
…on live input text
…ction for toggling the class hidden for it
…ocal storage up to date with allRecipes
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.
The project is really great as a whole, it is very well structured which makes it easy to follow and read. I am also impressed about the functionallity of the project, it has smart solutions in html, CSS and Javascript. I particularly enjoyed the JS code because it was logically divided and the functions made sense, the "showRecipeCard" function especially. Coolt feautures with the searchbar and the"favourites". Really well done on your project! :)
| src="./cross-white.svg" | ||
| alt="cross icon"> | ||
| <div | ||
| class="modal" |
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.
Cool use of "modal", also in js. I have not seen this before:)
| id="card-container"> | ||
| </div> | ||
| <script src="./script.js"></script> | ||
| </body> |
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.
Good and easy-to-understand structure in your HTML, really nice :) Maybe you could use more semantic tags like “main” and “section” to make it even more accessible.
| <body> | ||
| <div class="top-container"> | ||
| <input | ||
| class="search-button" |
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.
I totally get the choice of the name but maybe for further clarity "search-input" could be another option for it, since it's "not really" a button:)
| } | ||
|
|
||
| .hidden { | ||
| display: none !important; |
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.
Had to look "!important" up😅. Curious about how you worked with it? Did it not pick this up from the beginning?
| .title { | ||
| color: #0018A4; | ||
| font-weight: 700; | ||
| font-style: bold; |
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.
I don't remember the Figma design by heart, maybe this was in there but i don't think "font-style: bold;" is a valid property. "font-weight" should do the trick i think.
| }); | ||
|
|
||
| // re-append the cards in sorted order | ||
| const cardContainer = document.getElementById("card-container"); |
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.
You already have a global variable for " cardcontainer" in row 16🙂 you don't have to call the DOM again, you can just do "sortedCardArray.forEach((card) => cardContainer.appendChild(card)) i think🙂
|
|
||
| const updateFavoriteRecipes = (recipeId, recipeIsLiked) => { | ||
| // find the corresponding recipe (in allRecipes) for the clicked card by comparing their recipe ID's | ||
| clickedRecipe = allRecipes.find(recipe => recipe.id === recipeId); |
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.
I can't find "clickedRecipe" as a const or let somewhere, maybe i've missed it but otherwise you could do that here:)
| const storedRecipes = JSON.parse(localStorage.getItem("recipes")) || []; | ||
|
|
||
| // show loading state when fetching data | ||
| let fetchLoadingState = true; |
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.
This is really nice👍
| card.dataset.id = recipe.id; | ||
|
|
||
| // check if the recipes id match any id of the recipes in favoriteRecipes. If true, set the variable to the class of active state for the heart icon | ||
| const heartIconClass = favoriteRecipes.some(favoriteRecipe => favoriteRecipe.id === recipe.id) ? "fas" : "far"; |
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.
This looked so good on the page🤩
| <p class="time"><b>Time:</b> ${recipe.readyInMinutes} min</p> | ||
| <p><b>Servings:</b> ${recipe.servings}</p> | ||
| </div> | ||
| <hr class="solid"> |
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.
smart to do this. Does it work even if the recipe doesn't have a summary?
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.
Really good job with this project!
You have implemented all requirements and several stretch goals.
I Like the way you can add to favorites list and that it is perserved in local storage.
Your code is nice structured and easy to follow.
Keep up the good work!
| <div | ||
| class="modal-overlay hidden" | ||
| id="modal-overlay"> | ||
| <img |
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.
Regarding the modal, take a look at the html element <dialog>
I'm not so used to it myself but it is pretty cool!
https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog
| if (fetchLoadingState === true){ | ||
| cardContainer.innerHTML = `<p>Loading...</p>`; |
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.
great with a loading state!
| if(fetchedRecipes && fetchedRecipes.length > 0 ) { | ||
| localStorage.setItem("recipes", JSON.stringify(fetchedRecipes)); | ||
| allRecipes = fetchedRecipes; | ||
| // if the fetch has no data (empty array), update allRecipes with data from local storage |
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.
Yes, well done with local storage
| if(!recipeArray || recipeArray.length === 0) { | ||
| cardContainer.innerHTML = `<p class="filter-error-message">Oh no!🥲 Unfortunately there are no recipes matching your current filter. Try another one!</p>`; | ||
| } |
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.
great with a fallback empty state
|
|
||
| function showCardInModal(cardButton) { | ||
| // find the card which button was clicked | ||
| const clickedCard = cardButton.closest(".card"); |
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.
clever
| modalContent.querySelector(".recipe-content .recipe-summary").classList.toggle("hidden"); | ||
|
|
||
| // make the recipe's instructions and ingredients visible | ||
| modalContent.querySelector(".recipe-content .recipe-instruction").classList.toggle("hidden"); | ||
| modalContent.querySelector(".recipe-content .ingredients").classList.toggle("hidden"); |
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.
isnt it enough to hide or show on the parent element?
| const sortedCardArray = [...document.querySelectorAll(".card")]; | ||
| // get the cooking time of each card |
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.
spread operator! nice
| const getTime = (card) => { | ||
| const text = card.querySelector(".time").textContent; | ||
| // extract and return the number from it | ||
| const number = text.match(/\d+/); |
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.
regular expression! Do you understand what it does?
| const addFavoriteRecipesToLocalStorage = () => { | ||
| // create a set of valid recipe IDs from allRecipes | ||
| const validRecipeIds = new Set(allRecipes.map(recipe => recipe.id)); | ||
|
|
||
| // filter favoriteRecipes so only recipes that exist in allRecipes are left | ||
| favoriteRecipes = favoriteRecipes.filter(favoriteRecipe => validRecipeIds.has(favoriteRecipe.id)); | ||
|
|
||
| // save cleaned favoriteRecipes to localStorage | ||
| localStorage.setItem("favoriteRecipes", JSON.stringify(favoriteRecipes)); | ||
| } |
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.
nice implementation
Link to Netlify: https://js-recipe-library.netlify.app/