From 7d882d7429e6dc6a8c9582eb4d157d77a5851bcb Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Mon, 29 Jun 2026 11:54:34 +0300 Subject: [PATCH 01/10] feat(animations): add scroll-fade to mobile homepage sections --- .../src/components/MobileChefSection.tsx | 12 ++++++- .../frontend/src/components/MobileSection.tsx | 13 ++++++-- .../styles/components/_mobile-section.scss | 32 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/components/MobileChefSection.tsx b/apps/frontend/src/components/MobileChefSection.tsx index 2d9848d..e4e9c17 100644 --- a/apps/frontend/src/components/MobileChefSection.tsx +++ b/apps/frontend/src/components/MobileChefSection.tsx @@ -1,8 +1,12 @@ +'use client'; + +import { useRef } from 'react'; import { RestaurantCard } from '@org/ui-components'; import type { Chef, Restaurant } from '@org/shared-types'; import { strapiImageUrl } from '../lib/api'; import { TEXT } from '../lib/text'; import { Carousel } from './Carousel'; +import { useIntersectionObserver } from '../hooks/useIntersectionObserver'; interface Props { chef: Chef; @@ -10,8 +14,14 @@ interface Props { } export function MobileChefSection({ chef, restaurants }: Props) { + const ref = useRef(null); + const isVisible = useIntersectionObserver(ref); + return ( -
+

{TEXT.chefOfTheWeek.sectionTitle}

(null); + const isVisible = useIntersectionObserver(ref); + return ( -
+

{title}

{children} {linkLabel && linkHref && ( diff --git a/apps/frontend/src/styles/components/_mobile-section.scss b/apps/frontend/src/styles/components/_mobile-section.scss index 6179150..5699c1b 100644 --- a/apps/frontend/src/styles/components/_mobile-section.scss +++ b/apps/frontend/src/styles/components/_mobile-section.scss @@ -85,6 +85,21 @@ &:hover { opacity: 0.7; } } + opacity: 0; + transform: translateY(12px); + transition: opacity $duration-slow $ease-out, transform $duration-slow $ease-out; + + &--visible { + opacity: 1; + transform: none; + } + + @include reduced-motion { + opacity: 1; + transform: none; + transition: none; + } + @include for-normal-layout { display: none; } } @@ -135,3 +150,20 @@ @include for-normal-layout { display: none; } } + +.epicure-chef-week { + opacity: 0; + transform: translateY(12px); + transition: opacity $duration-slow $ease-out, transform $duration-slow $ease-out; + + &--visible { + opacity: 1; + transform: none; + } + + @include reduced-motion { + opacity: 1; + transform: none; + transition: none; + } +} From 1a8a4a4c2491536d3cd347fbe7662f3d096d1679 Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Mon, 29 Jun 2026 11:54:41 +0300 Subject: [PATCH 02/10] feat(animations): fade in cards on mount across restaurants, chefs, and dish grid --- apps/frontend/src/styles/components/_dish-grid.scss | 7 +++++++ apps/frontend/src/styles/pages/_chefs.scss | 6 ++++++ apps/frontend/src/styles/pages/_restaurants.scss | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/apps/frontend/src/styles/components/_dish-grid.scss b/apps/frontend/src/styles/components/_dish-grid.scss index 2fc9320..2c83a2c 100644 --- a/apps/frontend/src/styles/components/_dish-grid.scss +++ b/apps/frontend/src/styles/components/_dish-grid.scss @@ -23,6 +23,13 @@ } } +// ── Card entrance animation ─────────────────────────────────────── +.epicure-dish-grid .epicure-dish-card { + animation: epicure-fade-in 250ms $ease-out both; + + @include reduced-motion { animation: none; } +} + // ── Dish card overrides (restaurant detail context only) ────────── // Scoped under .epicure-dish-grid so homepage DishCard is unaffected. // Resets desktop _dish-card.scss overrides (690px height, large text, diff --git a/apps/frontend/src/styles/pages/_chefs.scss b/apps/frontend/src/styles/pages/_chefs.scss index f623bbc..7ac1d0b 100644 --- a/apps/frontend/src/styles/pages/_chefs.scss +++ b/apps/frontend/src/styles/pages/_chefs.scss @@ -67,6 +67,12 @@ gap: 1rem; padding: 32px $layout-gutter-mobile 56px; + .epicure-chef-grid__item { + animation: epicure-fade-in 250ms $ease-out both; + + @include reduced-motion { animation: none; } + } + @include for-normal-layout { grid-template-columns: repeat(3, 379px); gap: 1.5rem; diff --git a/apps/frontend/src/styles/pages/_restaurants.scss b/apps/frontend/src/styles/pages/_restaurants.scss index 9a5b272..9374b9b 100644 --- a/apps/frontend/src/styles/pages/_restaurants.scss +++ b/apps/frontend/src/styles/pages/_restaurants.scss @@ -62,6 +62,12 @@ gap: 1rem; padding: 32px 20px 56px; + .epicure-restaurant-card { + animation: epicure-fade-in 250ms $ease-out both; + + @include reduced-motion { animation: none; } + } + .epicure-restaurant-card__image { aspect-ratio: 334 / 207; height: auto; From ab8e0fdf37496eb60ba3082053e0350961fbfdcd Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 11:25:37 +0300 Subject: [PATCH 03/10] fix(cart): stack same-dish items regardless of change selection order; fix confirm-remove overflow on tall cart items --- apps/frontend/src/context/CartContext.tsx | 6 ++++-- .../src/styles/components/_cart-item.scss | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/context/CartContext.tsx b/apps/frontend/src/context/CartContext.tsx index c702f33..1a2d9ff 100644 --- a/apps/frontend/src/context/CartContext.tsx +++ b/apps/frontend/src/context/CartContext.tsx @@ -38,11 +38,13 @@ function isValidCartState(val: unknown): val is CartState { } function itemsMatch(a: CartItem, b: CartItem): boolean { + const changesA = [...a.selectedChanges].sort(); + const changesB = [...b.selectedChanges].sort(); return ( a.dish.id === b.dish.id && a.selectedSide === b.selectedSide && - a.selectedChanges.length === b.selectedChanges.length && - a.selectedChanges.every((c, i) => c === b.selectedChanges[i]) + changesA.length === changesB.length && + changesA.every((c, i) => c === changesB[i]) ); } diff --git a/apps/frontend/src/styles/components/_cart-item.scss b/apps/frontend/src/styles/components/_cart-item.scss index bf5a344..b582534 100644 --- a/apps/frontend/src/styles/components/_cart-item.scss +++ b/apps/frontend/src/styles/components/_cart-item.scss @@ -81,6 +81,15 @@ &--confirm-remove { animation: epicure-cart-shake 0.35s ease-out; @include reduced-motion { animation: none; } + height: auto; + align-items: flex-start; + + .epicure-cart-item__body { + height: auto; + overflow: visible; + } + + .epicure-cart-item__price-row { display: none; } } &__confirm-remove { @@ -222,4 +231,16 @@ .epicure-cart-item__name { font-size: 1rem; } .epicure-cart-item__meta { font-size: 0.8125rem; white-space: normal; } .epicure-cart-item__price-val { font-size: 0.9375rem; } + + .epicure-cart-item--confirm-remove { + height: auto; + align-items: flex-start; + } + + .epicure-cart-item--confirm-remove .epicure-cart-item__body { + height: auto; + overflow: visible; + } + + .epicure-cart-item--confirm-remove .epicure-cart-item__price-row { display: none; } } From 9a9d87c39ca66e050cd9efa70fed775d8b4440ee Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 11:27:46 +0300 Subject: [PATCH 04/10] feat(dish-card): add hover image-scale + shadow lift to match restaurant card --- apps/frontend/src/styles/components/_dish-card.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/styles/components/_dish-card.scss b/apps/frontend/src/styles/components/_dish-card.scss index 1f1bdcc..02bba14 100644 --- a/apps/frontend/src/styles/components/_dish-card.scss +++ b/apps/frontend/src/styles/components/_dish-card.scss @@ -5,6 +5,7 @@ background: $white; border-radius: 4px; overflow: hidden; + transition: box-shadow 200ms; &__image-wrap { position: relative; } @@ -13,6 +14,7 @@ aspect-ratio: 1; object-fit: cover; display: block; + transition: transform $duration-base $ease-out; } &__type-icon { @@ -89,7 +91,13 @@ color: inherit; cursor: pointer; - &:hover { opacity: 0.92; } + &:hover .epicure-dish-card { box-shadow: 0 6px 20px $shadow-subtle; } + &:hover .epicure-dish-card__image { transform: scale(1.04); } + + @include reduced-motion { + .epicure-dish-card { transition: none; } + .epicure-dish-card__image { transition: none; } + } } @include for-normal-layout { From 65774fee122cf391146bba105c27e0e008b8c7f5 Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 11:36:00 +0300 Subject: [PATCH 05/10] feat(icons-legend): scroll-in stagger animation and icon hover scale --- apps/frontend/src/components/IconsLegend.tsx | 9 ++++++++- .../styles/components/_mobile-section.scss | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/components/IconsLegend.tsx b/apps/frontend/src/components/IconsLegend.tsx index f7d2847..3077161 100644 --- a/apps/frontend/src/components/IconsLegend.tsx +++ b/apps/frontend/src/components/IconsLegend.tsx @@ -1,8 +1,15 @@ +'use client'; + +import { useRef } from 'react'; import { TEXT } from '../lib/text'; +import { useIntersectionObserver } from '../hooks/useIntersectionObserver'; export function IconsLegend() { + const ref = useRef(null); + const isVisible = useIntersectionObserver(ref); + return ( -
+

{TEXT.home.iconsTitle}

    {TEXT.icons.map(icon => ( diff --git a/apps/frontend/src/styles/components/_mobile-section.scss b/apps/frontend/src/styles/components/_mobile-section.scss index 5699c1b..c58539e 100644 --- a/apps/frontend/src/styles/components/_mobile-section.scss +++ b/apps/frontend/src/styles/components/_mobile-section.scss @@ -134,11 +134,25 @@ flex-direction: column; align-items: center; gap: 2rem; + opacity: 0; + transform: translateY(12px); + transition: opacity $duration-slow $ease-out, transform $duration-slow $ease-out; + + &:nth-child(2) { transition-delay: 80ms; } + &:nth-child(3) { transition-delay: 160ms; } + + &:hover .epicure-icons-legend__icon { transform: scale(1.18); } + } + + &--visible &__item { + opacity: 1; + transform: none; } &__icon { width: 56px; height: 56px; + transition: transform 200ms $ease-out; } &__label { @@ -148,6 +162,11 @@ letter-spacing: 1.97px; } + @include reduced-motion { + &__item { opacity: 1; transform: none; transition: none; } + &__icon { transition: none; } + } + @include for-normal-layout { display: none; } } From 86a1c598049433be786f4167e00f8e36980553c3 Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 11:36:12 +0300 Subject: [PATCH 06/10] feat(chef-week): grayscale-to-color hover on chef photo for mobile and desktop --- .../src/styles/components/_chef-week.scss | 11 +++++++++++ apps/frontend/src/styles/pages/_home.scss | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/styles/components/_chef-week.scss b/apps/frontend/src/styles/components/_chef-week.scss index c113612..6b715d3 100644 --- a/apps/frontend/src/styles/components/_chef-week.scss +++ b/apps/frontend/src/styles/components/_chef-week.scss @@ -20,6 +20,7 @@ position: relative; width: 100%; margin-bottom: 1.25rem; + overflow: hidden; } &__photo { @@ -28,6 +29,16 @@ object-fit: cover; display: block; filter: grayscale(100%); + transition: filter $duration-base $ease-out, transform $duration-base $ease-out; + } + + &__photo-wrap:hover &__photo { + filter: grayscale(0%); + transform: scale(1.03); + } + + @include reduced-motion { + &__photo { transition: none; } } &__name-bar { diff --git a/apps/frontend/src/styles/pages/_home.scss b/apps/frontend/src/styles/pages/_home.scss index a02c99a..662e781 100644 --- a/apps/frontend/src/styles/pages/_home.scss +++ b/apps/frontend/src/styles/pages/_home.scss @@ -224,7 +224,10 @@ align-items: start; } - &__photo-col { position: relative; } + &__photo-col { + position: relative; + overflow: hidden; + } &__photo { width: 100%; @@ -232,6 +235,16 @@ object-fit: cover; display: block; filter: grayscale(100%); + transition: filter $duration-base $ease-out, transform $duration-base $ease-out; + } + + &__photo-col:hover &__photo { + filter: grayscale(0%); + transform: scale(1.03); + } + + @include reduced-motion { + &__photo { transition: none; } } &__name-bar { From 322cdc822ac36ff357aa262bcbfba5f03fde16c1 Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 11:41:02 +0300 Subject: [PATCH 07/10] feat(chefs): add infinite scroll (6 per load) matching restaurants grid pattern --- apps/frontend/src/components/ChefsGrid.tsx | 42 ++++++++++++++++------ 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/components/ChefsGrid.tsx b/apps/frontend/src/components/ChefsGrid.tsx index e9ec189..81d6577 100644 --- a/apps/frontend/src/components/ChefsGrid.tsx +++ b/apps/frontend/src/components/ChefsGrid.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect, useMemo, useRef } from 'react'; +import { useState, useEffect, useMemo, useRef, useCallback } from 'react'; import type { Chef } from '@org/shared-types'; import { ChefCard } from '@org/ui-components'; import { TEXT } from '../lib/text'; @@ -10,6 +10,8 @@ import { ChefModal } from './ChefModal'; import { useIntersectionObserver } from '../hooks/useIntersectionObserver'; import { useTabIndicator } from '../hooks/useTabIndicator'; +const PAGE_SIZE = 6; + type ChefTab = (typeof TEXT.chefsGrid.tabs)[number]['id']; export function ChefsGrid() { @@ -18,9 +20,11 @@ export function ChefsGrid() { const [activeTab, setActiveTab] = useState('all'); const [highlightId, setHighlightId] = useState(null); const [selectedChef, setSelectedChef] = useState(null); + const [visibleCount, setVisibleCount] = useState(PAGE_SIZE); const gridRef = useRef(null); const gridVisible = useIntersectionObserver(gridRef); const tabsRef = useRef(null); + const sentinelRef = useRef(null); useTabIndicator(tabsRef, activeTab); useEffect(() => { @@ -45,10 +49,32 @@ export function ChefsGrid() { .finally(() => setLoading(false)); }, []); + const filtered = useMemo(() => { + if (activeTab === 'new') return [...chefs].sort((a, b) => b.id - a.id); + if (activeTab === 'most-viewed') + return chefs.filter(c => c.chefOfTheWeek); + return chefs; + }, [chefs, activeTab]); + + useEffect(() => { setVisibleCount(PAGE_SIZE); }, [filtered]); + + const loadMore = useCallback(() => setVisibleCount(prev => prev + PAGE_SIZE), []); + + useEffect(() => { + const sentinel = sentinelRef.current; + if (!sentinel) return; + const observer = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) loadMore(); + }, { threshold: 0 }); + observer.observe(sentinel); + return () => observer.disconnect(); + }, [loadMore, filtered]); + useEffect(() => { if (!highlightId || chefs.length === 0) return; - // Switch to 'all' so the chef card is guaranteed to be in the DOM + // Switch to 'all' and show all chefs so the target card is in the DOM setActiveTab('all'); + setVisibleCount(chefs.length); const isMobile = window.matchMedia('(max-width: 767px)').matches; let modalTimer: ReturnType; const scrollTimer = setTimeout(() => { @@ -64,13 +90,6 @@ export function ChefsGrid() { return () => { clearTimeout(scrollTimer); clearTimeout(modalTimer); }; }, [highlightId, chefs]); - const filtered = useMemo(() => { - if (activeTab === 'new') return [...chefs].sort((a, b) => b.id - a.id); - if (activeTab === 'most-viewed') - return chefs.filter(c => c.chefOfTheWeek); - return chefs; - }, [chefs, activeTab]); - return ( <> {selectedChef && ( @@ -107,7 +126,7 @@ export function ChefsGrid() { ref={gridRef} className={`epicure-chef-grid${gridVisible ? ' epicure-chef-grid--visible' : ''}`} > - {filtered.map(chef => ( + {filtered.slice(0, visibleCount).map(chef => ( ))} + {visibleCount < filtered.length && ( + )} From e9556273d404b191bb3af56a409753e779ec724a Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 12:01:07 +0300 Subject: [PATCH 08/10] fix: resolve 9 bugs from code review (highlight override, cross-restaurant cart, chef restaurants fallback, sentinel re-fire, hasItems, reduced-motion, dead CSS) --- apps/frontend/src/app/page.tsx | 2 +- apps/frontend/src/components/CartPanel.tsx | 2 +- apps/frontend/src/components/ChefModal.tsx | 2 +- apps/frontend/src/components/ChefsGrid.tsx | 13 ++++++++++--- apps/frontend/src/components/RestaurantsGrid.tsx | 2 +- apps/frontend/src/context/CartContext.tsx | 12 ++---------- apps/frontend/src/styles/basics/_base.scss | 5 +++++ .../frontend/src/styles/components/_cart-item.scss | 14 -------------- .../frontend/src/styles/components/_dish-card.scss | 5 +++++ apps/frontend/src/styles/pages/_restaurants.scss | 4 ---- 10 files changed, 26 insertions(+), 35 deletions(-) diff --git a/apps/frontend/src/app/page.tsx b/apps/frontend/src/app/page.tsx index e223ffc..9eee137 100644 --- a/apps/frontend/src/app/page.tsx +++ b/apps/frontend/src/app/page.tsx @@ -22,7 +22,7 @@ export default async function HomePage() { const popularRestaurants = restaurants.filter(r => r.isPopular); const weeklyChef = chefs.find(c => c.chefOfTheWeek); const chefRestaurantIds = new Set(weeklyChef?.restaurants?.map(r => r.id) ?? []); - const chefRestaurants = weeklyChef?.restaurants != null + const chefRestaurants = chefRestaurantIds.size > 0 ? restaurants.filter(r => chefRestaurantIds.has(r.id)) : weeklyChef ? restaurants.filter(r => r.chef?.id === weeklyChef.id) diff --git a/apps/frontend/src/components/CartPanel.tsx b/apps/frontend/src/components/CartPanel.tsx index 1c2d8dc..1ab9cfd 100644 --- a/apps/frontend/src/components/CartPanel.tsx +++ b/apps/frontend/src/components/CartPanel.tsx @@ -61,7 +61,7 @@ export function CartPanel({ onClose }: CartPanelProps) {
)} - 0} /> + 0} />
); diff --git a/apps/frontend/src/components/ChefModal.tsx b/apps/frontend/src/components/ChefModal.tsx index caf009e..4ecf3cb 100644 --- a/apps/frontend/src/components/ChefModal.tsx +++ b/apps/frontend/src/components/ChefModal.tsx @@ -14,7 +14,7 @@ interface ChefModalProps { } export function ChefModal({ chef, onClose }: ChefModalProps) { - const hasPopulated = chef.restaurants !== undefined; + const hasPopulated = chef.restaurants !== undefined && chef.restaurants.length > 0; const [restaurants, setRestaurants] = useState(chef.restaurants ?? []); useEffect(() => { diff --git a/apps/frontend/src/components/ChefsGrid.tsx b/apps/frontend/src/components/ChefsGrid.tsx index 81d6577..eb59fd1 100644 --- a/apps/frontend/src/components/ChefsGrid.tsx +++ b/apps/frontend/src/components/ChefsGrid.tsx @@ -25,6 +25,7 @@ export function ChefsGrid() { const gridVisible = useIntersectionObserver(gridRef); const tabsRef = useRef(null); const sentinelRef = useRef(null); + const highlightPendingRef = useRef(false); useTabIndicator(tabsRef, activeTab); useEffect(() => { @@ -56,7 +57,10 @@ export function ChefsGrid() { return chefs; }, [chefs, activeTab]); - useEffect(() => { setVisibleCount(PAGE_SIZE); }, [filtered]); + useEffect(() => { + if (highlightPendingRef.current) return; + setVisibleCount(PAGE_SIZE); + }, [filtered]); const loadMore = useCallback(() => setVisibleCount(prev => prev + PAGE_SIZE), []); @@ -68,11 +72,13 @@ export function ChefsGrid() { }, { threshold: 0 }); observer.observe(sentinel); return () => observer.disconnect(); - }, [loadMore, filtered]); + }, [loadMore]); useEffect(() => { if (!highlightId || chefs.length === 0) return; - // Switch to 'all' and show all chefs so the target card is in the DOM + // Switch to 'all' and show all chefs so the target card is in the DOM. + // Set the pending flag first so the [filtered] reset effect skips the PAGE_SIZE reset. + highlightPendingRef.current = true; setActiveTab('all'); setVisibleCount(chefs.length); const isMobile = window.matchMedia('(max-width: 767px)').matches; @@ -85,6 +91,7 @@ export function ChefsGrid() { modalTimer = setTimeout(() => { if (chef) setSelectedChef(chef); setHighlightId(null); + highlightPendingRef.current = false; }, isMobile ? 1200 : 500); }, 1000); return () => { clearTimeout(scrollTimer); clearTimeout(modalTimer); }; diff --git a/apps/frontend/src/components/RestaurantsGrid.tsx b/apps/frontend/src/components/RestaurantsGrid.tsx index 04e2ce0..2853cdc 100644 --- a/apps/frontend/src/components/RestaurantsGrid.tsx +++ b/apps/frontend/src/components/RestaurantsGrid.tsx @@ -173,7 +173,7 @@ export function RestaurantsGrid() { }, { threshold: 0.1 }); observer.observe(sentinel); return () => observer.disconnect(); - }, [filtered, loadMore]); + }, [loadMore]); function clearAllFilters() { setSelectedRatings(new Set()); diff --git a/apps/frontend/src/context/CartContext.tsx b/apps/frontend/src/context/CartContext.tsx index 1a2d9ff..3c2aa19 100644 --- a/apps/frontend/src/context/CartContext.tsx +++ b/apps/frontend/src/context/CartContext.tsx @@ -116,15 +116,7 @@ export function CartProvider({ children }: { children: ReactNode }) { } function confirmRemove(item: CartItem) { - setState(prev => { - const updated = prev.cartItems.filter(c => !itemsMatch(c, item)); - return { - ...prev, - cartItems: updated, - restaurantId: updated.length ? prev.restaurantId : null, - restaurantName: updated.length ? prev.restaurantName : null, - }; - }); + removeFromCart(item); } function cancelRemove(item: CartItem) { @@ -137,7 +129,7 @@ export function CartProvider({ children }: { children: ReactNode }) { } function conflictsWithCart(incomingRestaurantId: number): boolean { - return state.cartItems.some(c => !c.pendingRemove) && state.restaurantId !== incomingRestaurantId; + return state.cartItems.length > 0 && state.restaurantId !== incomingRestaurantId; } const committedItems = state.cartItems.filter(c => !c.pendingRemove); diff --git a/apps/frontend/src/styles/basics/_base.scss b/apps/frontend/src/styles/basics/_base.scss index 2acb093..2484029 100644 --- a/apps/frontend/src/styles/basics/_base.scss +++ b/apps/frontend/src/styles/basics/_base.scss @@ -53,3 +53,8 @@ ul { margin: 0; padding: 0; } + +.epicure-scroll-sentinel { + height: 1px; + width: 100%; +} diff --git a/apps/frontend/src/styles/components/_cart-item.scss b/apps/frontend/src/styles/components/_cart-item.scss index b582534..cd0ddaa 100644 --- a/apps/frontend/src/styles/components/_cart-item.scss +++ b/apps/frontend/src/styles/components/_cart-item.scss @@ -149,20 +149,6 @@ margin-bottom: 0.125rem; } - &__delete { - display: flex; - align-items: center; - justify-content: center; - align-self: center; - background: none; - border: none; - cursor: pointer; - padding: 0.5rem; - flex-shrink: 0; - opacity: 0.55; - &:hover { opacity: 1; } - } - &__price-row { display: flex; align-items: center; diff --git a/apps/frontend/src/styles/components/_dish-card.scss b/apps/frontend/src/styles/components/_dish-card.scss index 02bba14..cd4e20a 100644 --- a/apps/frontend/src/styles/components/_dish-card.scss +++ b/apps/frontend/src/styles/components/_dish-card.scss @@ -7,6 +7,11 @@ overflow: hidden; transition: box-shadow 200ms; + @include reduced-motion { + transition: none; + &__image { transition: none; } + } + &__image-wrap { position: relative; } &__image { diff --git a/apps/frontend/src/styles/pages/_restaurants.scss b/apps/frontend/src/styles/pages/_restaurants.scss index 9374b9b..77aa312 100644 --- a/apps/frontend/src/styles/pages/_restaurants.scss +++ b/apps/frontend/src/styles/pages/_restaurants.scss @@ -222,7 +222,3 @@ @include reduced-motion { transition: none; } } -.epicure-scroll-sentinel { - height: 1px; - width: 100%; -} From afb88771101050796b566c0fea8e0134d54b1e1a Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 12:42:41 +0300 Subject: [PATCH 09/10] fix(ui): align dish card rows and reposition sign-in modal --- apps/frontend/src/styles/components/_dish-card.scss | 2 +- apps/frontend/src/styles/components/_dish-grid.scss | 7 ++++--- apps/frontend/src/styles/components/_sign-in-modal.scss | 4 ++-- apps/frontend/src/styles/pages/_home.scss | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/frontend/src/styles/components/_dish-card.scss b/apps/frontend/src/styles/components/_dish-card.scss index cd4e20a..dbdf66f 100644 --- a/apps/frontend/src/styles/components/_dish-card.scss +++ b/apps/frontend/src/styles/components/_dish-card.scss @@ -109,7 +109,7 @@ .epicure-dish-card { display: flex; flex-direction: column; - height: 690px; + height: 650px; &__image-wrap { flex-shrink: 0; diff --git a/apps/frontend/src/styles/components/_dish-grid.scss b/apps/frontend/src/styles/components/_dish-grid.scss index 2c83a2c..e94dac5 100644 --- a/apps/frontend/src/styles/components/_dish-grid.scss +++ b/apps/frontend/src/styles/components/_dish-grid.scss @@ -13,7 +13,7 @@ @include for-normal-layout { grid-template-columns: repeat(4, 272px); - grid-auto-rows: 413px; + grid-auto-rows: 460px; justify-content: center; gap: 2rem; width: 1184px; @@ -107,7 +107,7 @@ // ── Desktop overrides ──────────────────────────────────────────── @include for-normal-layout { - height: auto; + height: 100%; border-radius: 4px; &__image { @@ -121,12 +121,13 @@ padding: 0.875rem 1rem 1rem; display: flex; flex-direction: column; + flex: 1; } &__name { font-size: 2rem; font-weight: 400; - min-height: auto; + min-height: 4.8rem; order: unset; } diff --git a/apps/frontend/src/styles/components/_sign-in-modal.scss b/apps/frontend/src/styles/components/_sign-in-modal.scss index 2d4f36a..731a49c 100644 --- a/apps/frontend/src/styles/components/_sign-in-modal.scss +++ b/apps/frontend/src/styles/components/_sign-in-modal.scss @@ -140,7 +140,7 @@ } .epicure-signin-modal { - top: 173px; + top: 110px; left: 50%; right: auto; transform: translateX(-50%); @@ -158,7 +158,7 @@ &__close-desktop { display: block; position: fixed; - top: 144px; + top: 81px; left: calc(50% - 286px); z-index: $z-panel-top; background: none; diff --git a/apps/frontend/src/styles/pages/_home.scss b/apps/frontend/src/styles/pages/_home.scss index 662e781..6322dc0 100644 --- a/apps/frontend/src/styles/pages/_home.scss +++ b/apps/frontend/src/styles/pages/_home.scss @@ -192,10 +192,10 @@ .epicure-dish-card__restaurant { order: 2; } .epicure-dish-card__type-icon { order: 3; } .epicure-dish-card__description { order: 4; } - .epicure-dish-card__price-row { order: 5; margin-top: 0; } + .epicure-dish-card__price-row { order: 5; margin-top: auto; } .epicure-dish-card__info { - justify-content: space-between; + justify-content: flex-start; } } } From b4ce286de0d14d3feb4a756ec725bee2597cab4b Mon Sep 17 00:00:00 2001 From: Amit Oved Date: Tue, 30 Jun 2026 12:47:06 +0300 Subject: [PATCH 10/10] ix(build): destructure totalItems from useCart in CartPanel --- apps/frontend/src/components/CartPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/components/CartPanel.tsx b/apps/frontend/src/components/CartPanel.tsx index 1ab9cfd..235456f 100644 --- a/apps/frontend/src/components/CartPanel.tsx +++ b/apps/frontend/src/components/CartPanel.tsx @@ -12,7 +12,7 @@ interface CartPanelProps { } export function CartPanel({ onClose }: CartPanelProps) { - const { cartItems, restaurantName, totalPrice, comment, setComment } = useCart(); + const { cartItems, restaurantName, totalPrice, totalItems, comment, setComment } = useCart(); useEffect(() => { document.body.style.overflow = 'hidden';