-
Notifications
You must be signed in to change notification settings - Fork 60
Dessert Recipes Project – Technigo Bootcamp Project 2025 #59
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
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 think your HTML structure is nice and clean! It’s easy to see where each part of the app goes. Super nice you used main and section for the recipes whitch that makes it very readable. Maybe you could add an alt attribute (like a short description) to your images so it helps people using screen readers know what the picture shows :)
irisdgz
left a comment
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 nice work Kausyar! The code is well structured and realtivly easy for me to follow. I like how you’ve added clear sections for rendering, filters and favorites. Cool to see how you’re using async/await and localStorage together. The filtering and sorting part is especially nice and works smoothly. Overall, super solid project eventhou it has its own style and not the one in the Figma demo!
| const LS_COFFEE = "coffeeData"; | ||
| const LS_JUICE = "juiceData"; | ||
| const LS_FAVORITES = "favorites"; | ||
|
|
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 use of localStorage keys!
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.
Thank!)
| buttons.filter(Boolean).forEach((btn) => btn.classList.remove("active")); | ||
| if (activeBtn) activeBtn.classList.add("active"); | ||
| } | ||
|
|
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 recognize this pattern from I dont remeber where, youtube or our session! Removing and adding classes to show active buttons. Nice and clean implementation!
| if (coffeeRendered) return; | ||
| coffeeRendered = true; | ||
| if (containerCoffee) containerCoffee.innerHTML = ""; | ||
|
|
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 use of async/await to fetch the recipe data!
|
|
||
| ensureNoMatchBanner(containerCoffee); | ||
| } | ||
|
|
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 how you check localStorage first before fetching new data , here learned something myself as well :)
| const isCoffee = category === "coffee"; | ||
| const container = isCoffee ? containerCoffee : containerJuice; | ||
| if (!container) return; | ||
|
|
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.
well used async here again!
| if (!cards || !cards.length) return null; | ||
| return cards[Math.floor(Math.random() * cards.length)]; | ||
| } | ||
|
|
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 job here with random recpies.
| item.parentElement | ||
| ?.querySelectorAll(".filter__item") | ||
| .forEach((li) => li.classList.remove("active")); | ||
| item.classList.add("active"); |
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 looks great! I like how you combine event listeners with sorting and filtering.
| console.warn("No data-id on card"); | ||
| return; | ||
| } | ||
|
|
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 how you added a favorites feature! Great way to use localStorage and JSON to save user interactions
JennieDalgren
left a comment
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 job with this project!
Take a look at the API calls and make sure yoou have data to be able to try your filters. I get empty states on almost all of them.
Really good implementation of favorite recipes and that is persists in local storage.
You project is not entirely responsive, see the screenshot:

Clean up your code a bit and work on the naming of your functions. If you change your "theme" of the recipes, change the names in your code too. Also, stick to english comments. And remember to use commit messages in a better way, the message should reflect the change that you have done in the code, do not just copy paste the same message every time, that really beats the purpose of commits.
What you need to fix:
- Responsiveness
- Make sure the filters you have chosen to work with is actually working
- Clean up the code. Remove unused code, proper naming of variables and functions, english in comments if you need them.
Almost there! 💪
| :root { | ||
| --color-primary-first-light: #fafbff; | ||
| --color-primary-first: #0018a4; | ||
| --color-primary-second-light: #ffecea; | ||
| --color-primary-second: #ff6589; | ||
| --color-white: #ffffff; | ||
| --color-white-base: #ffffff; | ||
| --color-grey-light-1: #f8f9fa; | ||
| --color-grey-light-2: #e9ecef; | ||
| --color-grey-light-3: #dee2e6; | ||
| --color-grey-light-4: #ced4da; | ||
| --color-grey-dark: #868e96; | ||
| --color-grey-dark-base: #868e96; | ||
| --color-font: #212529; | ||
| --color-font-base: #212529; | ||
| --color-button: #8d9271; | ||
| --color-black: #000000; | ||
| --color-blue: #176d8c; | ||
| --border-radius-xxs: 0.5rem; | ||
| --border-radius-xs: 1rem; | ||
| --border-radius-sm: 1.5rem; | ||
| --border-radius-md: 2rem; | ||
| --border-radius-lg: 2.5rem; | ||
| --border-radius-xl: 3rem; | ||
| --box-shadow: 0 0.5rem 1rem #0019a453; |
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 that you use variables
css/style.css
Outdated
| ------------------------------------ */ | ||
| /* | ||
|
|
||
| ПЕРЕКЛЮЧЕНИЯ МЕЖДУ КАРТОЧКАМИ |
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.
stick to english comments
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.
Im done ✅✅✅
css/style.css
Outdated
| border: 1px solid #e9ecef; | ||
| background-color: #e9ecef; |
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.
use the variable that you have for this color?
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.
Im done ✅✅✅
css/style.css
Outdated
| } | ||
| .header__input-mobile:focus { | ||
| outline: none; | ||
| border-color: #e9ecef; |
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.
variable?
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.
Im done ✅✅✅
| const mainCoffee = document.querySelector(".main-coffee"); | ||
| const mainJuice = document.querySelector(".main-juice"); | ||
| const mainTea = document.querySelector(".main-tea"); | ||
| const mainFavorites = document.querySelector(".main-favorites"); |
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'm very confused about all these drink references? That is not reflected in your deployed website, which looks like it is focused on desserts?
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.
Im done ✅✅✅ I wrote desserts instead of juice
js/script.js
Outdated
| if ( | ||
| /(baklava|kunafa|kanafeh|maamoul|halva|tahini|rose\s*water|orange\s*blossom|middle\s*east|arab|leban|turk|persian|iran)/.test( | ||
| t | ||
| ) | ||
| ) | ||
| return "middle eastern"; | ||
|
|
||
| const ing = ingredients.map((i) => String(i || "").toLowerCase()).join(" "); | ||
| if (/(mascarpone|savoiardi|amaretto)/.test(ing)) return "italian"; | ||
| if (/(matcha|azuki|black\s*sesame|rice\s*flour)/.test(ing)) return "asian"; | ||
| if (/(tahini|date|rose\s*water|orange\s*blossom|cardamom)/.test(ing)) |
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 looks very hard coded, why don't you use the cuisine data from the API instead?
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 simplified the cuisine detection function (detectCuisine). Now it only uses the cuisines field from the api data, and if the cuisine is not specified, it returns 'international'
| function toNum(v) { | ||
| const n = Number(v); | ||
| return Number.isFinite(n) ? n : 0; | ||
| } |
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.
what do you need this for?
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 toNum function is used for safely converting values to numbers when sorting the cards 😀
| seedIfEmpty(LS_COFFEE, DEMO_CAKES); | ||
| seedIfEmpty(LS_JUICE, DEMO_DESSERTS); | ||
|
|
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.
should this actually be happening? You are supposed to fetch from the API?
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're totally right to ask! Here’s the idea behind seedIfEmpty:
1- Fallback for API limits:
The Spoonacular API has strict limits (150 requests/day on the free plan). When the limit is reached, it returns a 402/429 error. Demo data makes sure the filters always work so you can test them.
2- Immediate UI feedback:
Without demo data, the user would see a blank screen while waiting for the API. With demo data, the interface shows content right away and updates it if the API responds.
js/script.js
Outdated
| buttonCoffee?.addEventListener("click", () => { | ||
| mainCoffee?.classList.remove("hidden"); | ||
| mainJuice?.classList.add("hidden"); | ||
| mainTea?.classList.add("hidden"); | ||
| mainFavorites?.classList.add("hidden"); | ||
| setActiveButton(buttonCoffee); | ||
| }); | ||
|
|
||
| //Turn on JUICE container and turn off the others | ||
| buttonJuice?.addEventListener("click", () => { | ||
| mainCoffee?.classList.add("hidden"); | ||
| mainJuice?.classList.remove("hidden"); | ||
| mainTea?.classList.add("hidden"); | ||
| mainFavorites?.classList.add("hidden"); | ||
| setActiveButton(buttonJuice); |
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 get the logic here, and it is nice. However I don't see any use of a coffee or juice button? Use names that makes sense for your project.
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.
done ✅
Updated project description and added features, demo, technologies, and file structure.
Removed line breaks for a more concise introduction.
JennieDalgren
left a comment
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.
✅

Hi there! 👋
I built Recipe Library as part of my Technigo JavaScript Bootcamp 2025 journey. This project lets users explore and save dessert recipes from different cuisines in a fun and interactive way.
Key Features:
This project helped me practice working with APIs, dynamic content, local storage, and creating interactive, responsive UI components. 🌟