Improve carousel navigation and video scrolling behavior
Refactor the `CategoryRow` component to use `scrollTo` for smoother horizontal scrolling and dynamically show/hide navigation buttons based on scroll position. 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:
parent
208d3d9f76
commit
d4b1359b79
BIN
attached_assets/image_1756478620689.png
Normal file
BIN
attached_assets/image_1756478620689.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
@ -1,4 +1,4 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { type Video } from "@shared/schema";
|
||||
import VideoCard from "./video-card";
|
||||
import BunnyVideoModal from "./bunny-video-modal";
|
||||
@ -134,28 +134,30 @@ interface CategoryRowProps {
|
||||
function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const scrollIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [isLeftButtonHovered, setIsLeftButtonHovered] = useState(false);
|
||||
const [isRightButtonHovered, setIsRightButtonHovered] = useState(false);
|
||||
const [showLeftButton, setShowLeftButton] = useState(false);
|
||||
const [showRightButton, setShowRightButton] = useState(true);
|
||||
|
||||
const scroll = (direction: 'left' | 'right') => {
|
||||
if (!scrollRef.current) return;
|
||||
|
||||
const containerWidth = scrollRef.current.clientWidth;
|
||||
const scrollAmount = containerWidth * 0.8; // 80% of container width
|
||||
const container = scrollRef.current;
|
||||
const currentScroll = container.scrollLeft;
|
||||
const maxScroll = container.scrollWidth - container.clientWidth;
|
||||
const videoWidth = 224; // approx width of one video card + spacing
|
||||
const scrollAmount = videoWidth * 3; // Show 3 videos at a time
|
||||
|
||||
console.log(`Scrolling ${direction}, container width: ${containerWidth}, scroll amount: ${scrollAmount}`);
|
||||
let targetScroll;
|
||||
|
||||
if (direction === 'left') {
|
||||
scrollRef.current.scrollBy({
|
||||
left: -scrollAmount,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
targetScroll = Math.max(0, currentScroll - scrollAmount);
|
||||
} else {
|
||||
scrollRef.current.scrollBy({
|
||||
left: scrollAmount,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
targetScroll = Math.min(maxScroll, currentScroll + scrollAmount);
|
||||
}
|
||||
|
||||
container.scrollTo({
|
||||
left: targetScroll,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
};
|
||||
|
||||
const startAutoScroll = (direction: 'left' | 'right') => {
|
||||
@ -163,6 +165,22 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
|
||||
scroll(direction);
|
||||
};
|
||||
|
||||
const checkScrollPosition = () => {
|
||||
if (!scrollRef.current) return;
|
||||
|
||||
const container = scrollRef.current;
|
||||
const currentScroll = container.scrollLeft;
|
||||
const maxScroll = container.scrollWidth - container.clientWidth;
|
||||
|
||||
setShowLeftButton(currentScroll > 10); // Show left if not at start
|
||||
setShowRightButton(currentScroll < maxScroll - 10); // Show right if not at end
|
||||
};
|
||||
|
||||
// Check scroll position on mount and when videos change
|
||||
useEffect(() => {
|
||||
checkScrollPosition();
|
||||
}, [category.videos]);
|
||||
|
||||
const stopAutoScroll = () => {
|
||||
if (scrollIntervalRef.current) {
|
||||
clearInterval(scrollIntervalRef.current);
|
||||
@ -186,15 +204,11 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsLeftButtonHovered(true);
|
||||
startAutoScroll('left');
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsLeftButtonHovered(false);
|
||||
stopAutoScroll();
|
||||
}}
|
||||
className="flex absolute left-2 top-[45%] -translate-y-1/2 w-12 h-12 z-30 bg-black/80 hover:bg-black/95 rounded-full items-center justify-center transition-all duration-300 cursor-pointer border border-white/30 shadow-lg opacity-0 group-hover:opacity-100 hover:!opacity-100"
|
||||
className={`${showLeftButton ? 'opacity-0 group-hover:opacity-100 hover:!opacity-100' : 'hidden'} flex absolute left-2 top-[45%] -translate-y-1/2 w-12 h-12 z-30 bg-black/80 hover:bg-black/95 rounded-full items-center justify-center transition-all duration-300 cursor-pointer border border-white/30 shadow-lg`}
|
||||
data-testid="button-scroll-left"
|
||||
>
|
||||
<ChevronLeft className="w-6 h-6 text-white" />
|
||||
@ -209,15 +223,11 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsRightButtonHovered(true);
|
||||
startAutoScroll('right');
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsRightButtonHovered(false);
|
||||
stopAutoScroll();
|
||||
}}
|
||||
className="flex absolute right-2 top-[45%] -translate-y-1/2 w-12 h-12 z-30 bg-black/80 hover:bg-black/95 rounded-full items-center justify-center transition-all duration-300 cursor-pointer border border-white/30 shadow-lg opacity-0 group-hover:opacity-100 hover:!opacity-100"
|
||||
className={`${showRightButton ? 'opacity-0 group-hover:opacity-100 hover:!opacity-100' : 'hidden'} flex absolute right-2 top-[45%] -translate-y-1/2 w-12 h-12 z-30 bg-black/80 hover:bg-black/95 rounded-full items-center justify-center transition-all duration-300 cursor-pointer border border-white/30 shadow-lg`}
|
||||
data-testid="button-scroll-right"
|
||||
>
|
||||
<ChevronRight className="w-6 h-6 text-white" />
|
||||
@ -267,6 +277,7 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="flex space-x-2 md:space-x-3 overflow-x-auto scrollbar-hide pb-4 scroll-smooth px-4 md:px-0"
|
||||
onScroll={checkScrollPosition}
|
||||
style={{
|
||||
scrollbarWidth: 'none',
|
||||
msOverflowStyle: 'none',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user