From aaf1231ed05e5a7eaa266ca721afc5a7c831422f Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Wed, 3 Sep 2025 08:52:46 +0000 Subject: [PATCH] Improve mobile scrolling behavior by debouncing category index updates Add a scroll timer to debounce the calculation and update of the current category index on mobile devices, preventing visual flickering during scrolling. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1/OdlP8Wj --- client/src/components/netflix-grid.tsx | 39 +++++++++++++++++++------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/client/src/components/netflix-grid.tsx b/client/src/components/netflix-grid.tsx index 09ca3b0..824ef12 100644 --- a/client/src/components/netflix-grid.tsx +++ b/client/src/components/netflix-grid.tsx @@ -195,6 +195,7 @@ function CategoryRow({ category, onVideoClick, hideScrollButtons = false }: Cate const [currentIndex, setCurrentIndex] = useState(0); const [touchStart, setTouchStart] = useState(0); const [touchEnd, setTouchEnd] = useState(0); + const [scrollTimer, setScrollTimer] = useState(null); const checkScrollButtons = () => { if (scrollRef.current) { @@ -260,26 +261,44 @@ function CategoryRow({ category, onVideoClick, hideScrollButtons = false }: Cate }; }, [category.videos]); + // Cleanup timer on unmount + useEffect(() => { + return () => { + if (scrollTimer) { + clearTimeout(scrollTimer); + } + }; + }, [scrollTimer]); + const handleScroll = () => { checkScrollButtons(); - // Calculate current index for mobile dots + // Clear existing timer + if (scrollTimer) { + clearTimeout(scrollTimer); + } + + // Calculate current index for mobile dots with delay if (scrollRef.current) { const containerWidth = scrollRef.current.clientWidth; const scrollLeft = scrollRef.current.scrollLeft; const isMobile = window.innerWidth < 768; if (isMobile) { - // On mobile, calculate which card is most visible - const cardWidth = containerWidth - 24; // Account for container margins (12px each side) - const scrollProgress = scrollLeft / cardWidth; - const newIndex = Math.round(scrollProgress); - const clampedIndex = Math.min(Math.max(newIndex, 0), 9); // Ensure 0-9 range + // Debounce the dot update to prevent flickering during scroll + const timer = setTimeout(() => { + const cardWidth = containerWidth - 24; // Account for container margins (12px each side) + const scrollProgress = scrollLeft / cardWidth; + const newIndex = Math.round(scrollProgress); + const clampedIndex = Math.min(Math.max(newIndex, 0), 9); // Ensure 0-9 range + + // Only update if index actually changed + if (clampedIndex !== currentIndex) { + setCurrentIndex(clampedIndex); + } + }, 100); // 100ms delay for stable positioning - // Only update if index actually changed to prevent flickering - if (clampedIndex !== currentIndex) { - setCurrentIndex(clampedIndex); - } + setScrollTimer(timer); } } };