From 373108af199e6ff9ef2d31af4de5854f98fac855 Mon Sep 17 00:00:00 2001 From: rewatpun10 Date: Tue, 24 Feb 2026 20:19:12 +1100 Subject: [PATCH] fixes: scrollable and category highlight issue fixed --- src/components/CategoryFilterBar.tsx | 56 ++++++++++++++++++++++------ src/components/ItemCard.tsx | 34 ++++------------- src/main.css | 2 +- 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/components/CategoryFilterBar.tsx b/src/components/CategoryFilterBar.tsx index 61b54fb..ecd87d7 100644 --- a/src/components/CategoryFilterBar.tsx +++ b/src/components/CategoryFilterBar.tsx @@ -8,6 +8,7 @@ interface CategoryFilterBarProps { const CategoryFilterBar: React.FC = ({ categories }) => { const [selected, setSelected] = useState(() => categories[0]?.id ?? ''); const [hovered, setHovered] = useState(''); + const STICKY_OFFSET = 140; useEffect(() => { if (!categories.length) { @@ -21,6 +22,7 @@ const CategoryFilterBar: React.FC = ({ categories }) => const handleClick = (categoryId: string) => { setSelected(categoryId); + setHovered(''); document.getElementById(categoryId)?.scrollIntoView({ behavior: 'smooth', block: 'start', @@ -29,21 +31,51 @@ const CategoryFilterBar: React.FC = ({ categories }) => useEffect(() => { if (!categories.length) return; + const lastCategoryId = categories[categories.length - 1]?.id ?? ''; + let ticking = false; - const observer = new IntersectionObserver( - (entries) => { - const visibleSection = entries.find((entry) => entry.isIntersecting); - if (visibleSection) setSelected(visibleSection.target.id); - }, - { threshold: 0.3 } - ); + const updateSelectedByScroll = () => { + const anchorY = window.scrollY + STICKY_OFFSET + 8; + let activeId = categories[0].id; - categories.forEach((cat) => { - const el = document.getElementById(cat.id); - if (el) observer.observe(el); - }); + for (const category of categories) { + const sectionEl = document.getElementById(category.id); + if (!sectionEl) continue; + if (sectionEl.offsetTop <= anchorY) { + activeId = category.id; + } else { + break; + } + } + + // Ensure the last section gets selected near page bottom even if its top + // never crosses the anchor due to limited remaining scroll space. + const scrollBottom = window.scrollY + window.innerHeight; + const pageBottom = document.documentElement.scrollHeight; + if (pageBottom - scrollBottom <= 4) { + activeId = lastCategoryId || activeId; + } + + setSelected((prev) => (prev === activeId ? prev : activeId)); + }; + + const onScrollOrResize = () => { + if (ticking) return; + ticking = true; + window.requestAnimationFrame(() => { + updateSelectedByScroll(); + ticking = false; + }); + }; + + updateSelectedByScroll(); + window.addEventListener('scroll', onScrollOrResize, { passive: true }); + window.addEventListener('resize', onScrollOrResize); - return () => observer.disconnect(); + return () => { + window.removeEventListener('scroll', onScrollOrResize); + window.removeEventListener('resize', onScrollOrResize); + }; }, [categories]); if (!categories.length) return null; diff --git a/src/components/ItemCard.tsx b/src/components/ItemCard.tsx index c2380b3..8886112 100644 --- a/src/components/ItemCard.tsx +++ b/src/components/ItemCard.tsx @@ -26,10 +26,6 @@ const ItemCard: React.FC = ({ product, onAddToCart }) => { typeof product.price === 'number' && Number.isFinite(product.price) ? product.price : 0; - const isDesktopOrTablet = - typeof window !== 'undefined' - ? window.matchMedia('(min-width: 640px)').matches - : false; // derive shopId from URL so we can pass to modal (optional) const parts = @@ -41,35 +37,21 @@ const ItemCard: React.FC = ({ product, onAddToCart }) => { return ( <>
{ - setIsModalOpen(true); - } - : undefined - } - onKeyDown={ - isDesktopOrTablet - ? (event) => { - if (event.key === 'Enter' || event.key === ' ') { - event.preventDefault(); - setIsModalOpen(true); - } - } - : undefined - } + className="rounded-xl shadow-md bg-white overflow-hidden flex flex-col" > -
+
+

{product.label} diff --git a/src/main.css b/src/main.css index f11a509..d65d8b1 100644 --- a/src/main.css +++ b/src/main.css @@ -22,7 +22,7 @@ overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; - touch-action: pan-x; + touch-action: auto; padding-bottom: 0.5rem; scroll-snap-type: x proximity; }