videofolxtv/client/src/components/simple-carousel.tsx
sebastjanartic e9172e83e6 Improve video display with responsive grid layout
Refactors the SimpleCarousel component to use a flex-wrap container, removing horizontal scroll buttons and implementing responsive styling for video posters based on screen size. Adds CSS for the new layout and adjusts the "Top 10" number overlay positioning.

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/kdQ95gE
2025-08-29 23:26:37 +00:00

128 lines
4.5 KiB
TypeScript

import { useState, useRef, useEffect } from "react";
import { type Video } from "@shared/schema";
import VideoCard from "./video-card";
import { ChevronLeft, ChevronRight } from "lucide-react";
interface SimpleCarouselProps {
category: {
title: string;
videos: Video[];
};
onVideoClick: (video: Video) => void;
}
export default function SimpleCarousel({ category, onVideoClick }: SimpleCarouselProps) {
const scrollContainerRef = useRef<HTMLDivElement>(null);
const scrollIntervalRef = useRef<NodeJS.Timeout | null>(null);
const [isScrolling, setIsScrolling] = useState(false);
const [currentDirection, setCurrentDirection] = useState<'left' | 'right' | null>(null);
const [speed, setSpeed] = useState<'normal' | 'fast'>('normal');
const scroll = (direction: 'left' | 'right') => {
// If already scrolling in same direction, toggle speed
if (isScrolling && currentDirection === direction) {
const newSpeed = speed === 'normal' ? 'fast' : 'normal';
setSpeed(newSpeed);
// Restart with new speed immediately
if (scrollIntervalRef.current) {
clearInterval(scrollIntervalRef.current);
}
const speedValue = newSpeed === 'fast' ? 1.8 : 0.8;
scrollIntervalRef.current = setInterval(() => {
if (!scrollContainerRef.current) return;
const scrollAmount = direction === 'right' ? speedValue : -speedValue;
scrollContainerRef.current.scrollBy({
left: scrollAmount,
behavior: 'auto'
});
}, 8);
} else {
// If not scrolling or different direction, start scrolling
startAutoScroll(direction);
}
};
const startAutoScroll = (direction: 'left' | 'right') => {
if (scrollIntervalRef.current) {
clearInterval(scrollIntervalRef.current);
}
setIsScrolling(true);
setCurrentDirection(direction);
setSpeed('normal'); // Reset to normal speed when starting
const speedValue = 0.8; // Always start with normal speed
scrollIntervalRef.current = setInterval(() => {
if (!scrollContainerRef.current) return;
const scrollAmount = direction === 'right' ? speedValue : -speedValue;
scrollContainerRef.current.scrollBy({
left: scrollAmount,
behavior: 'auto'
});
}, 8);
};
const stopAutoScroll = () => {
if (scrollIntervalRef.current) {
clearInterval(scrollIntervalRef.current);
scrollIntervalRef.current = null;
}
setIsScrolling(false);
setCurrentDirection(null);
setSpeed('normal');
};
// Initialize scroll position in the middle so we can scroll both ways
useEffect(() => {
if (scrollContainerRef.current && category.videos.length > 0) {
// Wait for content to load, then scroll to middle
setTimeout(() => {
if (scrollContainerRef.current) {
const containerWidth = scrollContainerRef.current.scrollWidth;
const viewportWidth = scrollContainerRef.current.clientWidth;
const middlePosition = (containerWidth - viewportWidth) / 2;
scrollContainerRef.current.scrollTo({
left: middlePosition,
behavior: 'auto'
});
}
}, 100);
}
}, [category.videos.length]);
return (
<div className="relative group mb-12">
<h2 className="oswald-text text-2xl text-bunny-light mb-6 px-4">
{category.title}
</h2>
{/* Container z flex wrap */}
<div className="container flex flex-wrap justify-center gap-2.5 p-2.5 md:flex-row flex-col items-center">
{category.videos.map((video, videoIndex) => (
<div key={video.id} className="relative">
{/* Top 10 Number overlay for first category */}
{category.title.includes("Top 10") && (
<div className="absolute top-1 left-1 z-30 text-white font-black text-xl md:text-2xl drop-shadow-2xl pointer-events-none"
style={{
textShadow: '4px 4px 8px rgba(0,0,0,0.8), -2px -2px 4px rgba(0,0,0,0.6)',
WebkitTextStroke: '1px rgba(0,0,0,0.8)',
}}>
{videoIndex + 1}
</div>
)}
<VideoCard
video={video}
onClick={onVideoClick}
className="poster w-[150px] md:w-[150px] sm:w-[120px] h-auto hover:scale-105 transition-all duration-300 hover:shadow-2xl rounded-md overflow-hidden relative"
/>
</div>
))}
</div>
</div>
);
}