Make video rows flow continuously and smoothly like water

Update the Netflix grid component to use CSS transforms for smooth, continuous scrolling animations instead of incremental index changes, improving the visual experience of video rows.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 2eb1084e-b728-4449-9231-f1665924c8d5
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2eb1084e-b728-4449-9231-f1665924c8d5/QCN70f2
This commit is contained in:
sebastjanartic 2025-08-29 15:05:04 +00:00
parent bc53d99ff0
commit c85660e529

View File

@ -137,17 +137,14 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
const [showLeftButton, setShowLeftButton] = useState(false);
const [showRightButton, setShowRightButton] = useState(true);
const [currentIndex, setCurrentIndex] = useState(0);
const [translateX, setTranslateX] = useState(0);
const [isScrolling, setIsScrolling] = useState(false);
const videosToShow = 5; // Show 5 videos at a time
const videoWidth = 120; // Width + spacing
const scroll = (direction: 'left' | 'right') => {
if (direction === 'right') {
// Always move forward in the circle - perpetual motion
setCurrentIndex(prev => prev + 1);
} else {
// For left arrow, also move forward but faster to create illusion of reverse
setCurrentIndex(prev => prev + 1);
}
const speed = direction === 'right' ? videoWidth : -videoWidth;
setTranslateX(prev => prev - speed);
};
const startAutoScroll = (direction: 'left' | 'right') => {
@ -156,29 +153,41 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
clearInterval(scrollIntervalRef.current);
}
// Both directions move forward - true perpetual motion carousel
scrollIntervalRef.current = setInterval(() => {
setCurrentIndex(prev => prev + 1);
}, direction === 'left' ? 600 : 800); // Left moves slightly faster for effect
setIsScrolling(true);
// Continuous smooth flowing animation
const speed = direction === 'right' ? 2 : -2; // pixels per frame
const animate = () => {
setTranslateX(prev => {
const newValue = prev - speed;
const totalWidth = category.videos.length * videoWidth;
// Reset position for infinite loop
if (direction === 'right' && newValue <= -totalWidth) {
return 0;
} else if (direction === 'left' && newValue >= 0) {
return -totalWidth + videoWidth;
}
return newValue;
});
if (isScrolling) {
scrollIntervalRef.current = requestAnimationFrame(animate);
}
};
animate();
};
// Initialize in middle section for smooth infinite scroll
// Initialize starting position
useEffect(() => {
if (category.videos.length > 0) {
setCurrentIndex(category.videos.length); // Start in middle section for smooth wrapping
setTranslateX(-category.videos.length * videoWidth); // Start in middle section
}
}, [category.videos.length]);
// Handle seamless infinite scroll - only forward movement
useEffect(() => {
const totalVideos = category.videos.length;
if (currentIndex >= totalVideos * 2) {
// When we reach the end, seamlessly jump back to start of middle section
// This creates the illusion of infinite forward movement
setCurrentIndex(currentIndex - totalVideos);
}
}, [currentIndex, category.videos.length]);
// Always show both buttons
useEffect(() => {
setShowLeftButton(true);
@ -186,8 +195,9 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
}, []);
const stopAutoScroll = () => {
setIsScrolling(false);
if (scrollIntervalRef.current) {
clearInterval(scrollIntervalRef.current);
cancelAnimationFrame(scrollIntervalRef.current);
scrollIntervalRef.current = null;
}
};
@ -281,13 +291,14 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
<ChevronRight className="w-5 h-5 text-white" />
</button>
{/* Smooth sliding carousel - videos move like geese one by one */}
{/* Continuously flowing carousel - videos flow like water */}
<div className="overflow-hidden">
<div
className="flex space-x-2 md:space-x-3 pb-4 px-4 md:px-0 transition-transform duration-500 ease-in-out"
className="flex space-x-2 md:space-x-3 pb-4 px-4 md:px-0"
style={{
transform: `translateX(-${currentIndex * (112 + 8)}px)`, // Mobile: 112px width + 8px spacing
willChange: 'transform'
transform: `translateX(${translateX}px)`,
willChange: 'transform',
transition: isScrolling ? 'none' : 'transform 0.3s ease-out'
}}
>
{/* Create infinite loop by tripling the videos */}