Improve video carousel navigation and display logic

Refactor the `CategoryRow` component to implement a new carousel logic using `useState` for `currentIndex` and `videosToShow`. The infinite scrolling behavior has been replaced with a fixed number of visible videos that cycle through the category's videos. The `getVisibleVideos` function now calculates and returns the subset of videos to display based on the `currentIndex` and `videosToShow`. The `scroll` function is updated to handle index manipulation for navigation. The `useEffect` hook is simplified to ensure both navigation buttons are always visible.

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 14:53:28 +00:00
parent 87dea07bae
commit bb57672a6f

View File

@ -137,20 +137,16 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
const [showLeftButton, setShowLeftButton] = useState(false); const [showLeftButton, setShowLeftButton] = useState(false);
const [showRightButton, setShowRightButton] = useState(true); const [showRightButton, setShowRightButton] = useState(true);
// Create infinite carousel by duplicating videos const [currentIndex, setCurrentIndex] = useState(0);
const infiniteVideos = [...category.videos, ...category.videos, ...category.videos]; const videosToShow = 5; // Show 5 videos at a time
const scroll = (direction: 'left' | 'right') => { const scroll = (direction: 'left' | 'right') => {
if (!scrollRef.current) return; const totalVideos = category.videos.length;
const container = scrollRef.current;
const videoWidth = 224; // approx width of one video card + spacing
const scrollAmount = videoWidth * 2; // Show 2 videos at a time
if (direction === 'left') { if (direction === 'left') {
container.scrollBy({ left: -scrollAmount, behavior: 'smooth' }); setCurrentIndex(prev => prev === 0 ? totalVideos - 1 : prev - 1);
} else { } else {
container.scrollBy({ left: scrollAmount, behavior: 'smooth' }); setCurrentIndex(prev => prev === totalVideos - 1 ? 0 : prev + 1);
} }
}; };
@ -159,38 +155,26 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
scroll(direction); scroll(direction);
}; };
const checkScrollPosition = () => { // Get visible videos based on current index
if (!scrollRef.current) return; const getVisibleVideos = () => {
const totalVideos = category.videos.length;
const visible = [];
const container = scrollRef.current; for (let i = 0; i < videosToShow; i++) {
const currentScroll = container.scrollLeft; const index = (currentIndex + i) % totalVideos;
const maxScroll = container.scrollWidth - container.clientWidth; visible.push({
const sectionWidth = (container.scrollWidth / 3); // One third (original videos) ...category.videos[index],
displayIndex: i
// Reset to middle section when approaching edges for infinite effect });
if (currentScroll <= 100) {
// Jump to end of first section (start of second section)
container.scrollLeft = sectionWidth + currentScroll;
} else if (currentScroll >= maxScroll - 100) {
// Jump to start of second section
container.scrollLeft = sectionWidth + (currentScroll - 2 * sectionWidth);
} }
return visible;
// Always show both buttons
setShowLeftButton(true);
setShowRightButton(true);
}; };
// Initialize position to middle section on mount // Always show both buttons
useEffect(() => { useEffect(() => {
if (scrollRef.current && category.videos.length > 0) { setShowLeftButton(true);
const container = scrollRef.current; setShowRightButton(true);
const sectionWidth = container.scrollWidth / 3; }, []);
container.scrollLeft = sectionWidth; // Start in middle section
setShowLeftButton(true);
setShowRightButton(true);
}
}, [category.videos]);
const stopAutoScroll = () => { const stopAutoScroll = () => {
if (scrollIntervalRef.current) { if (scrollIntervalRef.current) {
@ -284,37 +268,30 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
<ChevronRight className="w-5 h-5 text-white" /> <ChevronRight className="w-5 h-5 text-white" />
</button> </button>
{/* Scrollable video row - edge to edge */} {/* Carousel video row */}
<div <div className="flex space-x-2 md:space-x-3 pb-4 px-4 md:px-0 transition-transform duration-500 ease-in-out">
ref={scrollRef} {getVisibleVideos().map((video, index) => {
className="flex space-x-2 md:space-x-3 overflow-x-auto scrollbar-hide pb-4 scroll-smooth px-4 md:px-0" const actualIndex = (currentIndex + index) % category.videos.length;
onScroll={checkScrollPosition} return (
style={{ <div key={`${video.id}-${currentIndex}-${index}`} className="flex-shrink-0 w-28 md:w-52 relative group">
scrollbarWidth: 'none', {/* Top 10 Number overlay for first category */}
msOverflowStyle: 'none', {category.title.includes("Top 10") && (
scrollBehavior: 'smooth', <div className="absolute top-1 left-1 z-20 text-white font-black text-3xl md:text-5xl drop-shadow-2xl"
WebkitOverflowScrolling: 'touch' style={{
}} textShadow: '4px 4px 8px rgba(0,0,0,0.8), -2px -2px 4px rgba(0,0,0,0.6)',
> WebkitTextStroke: '2px rgba(0,0,0,0.8)'
{infiniteVideos.map((video, index) => ( }}>
<div key={`${video.id}-${index}`} className="flex-shrink-0 w-28 md:w-52 relative group"> {actualIndex + 1}
{/* Top 10 Number overlay for first category */} </div>
{category.title.includes("Top 10") && index < 10 && ( )}
<div className="absolute top-1 left-1 z-20 text-white font-black text-3xl md:text-5xl drop-shadow-2xl" <VideoCard
style={{ video={video}
textShadow: '4px 4px 8px rgba(0,0,0,0.8), -2px -2px 4px rgba(0,0,0,0.6)', onClick={onVideoClick}
WebkitTextStroke: '2px rgba(0,0,0,0.8)' className="w-full hover:scale-105 hover:z-10 transition-all duration-300 group-hover:shadow-xl rounded-md overflow-hidden"
}}> />
{index + 1} </div>
</div> );
)} })}
<VideoCard
video={video}
onClick={onVideoClick}
className="w-full hover:scale-105 hover:z-10 transition-all duration-300 group-hover:shadow-xl rounded-md overflow-hidden"
/>
</div>
))}
</div> </div>
</div> </div>
</div> </div>