From b9fa335300e84a216b717149b2e0b2a589c95ab8 Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Thu, 28 Aug 2025 20:20:12 +0000 Subject: [PATCH] Add swipe gesture to navigate between videos within the player Implement touch and mouse drag gestures for seamless video navigation, allowing users to swipe left or right to move to the next or previous video, respectively. 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/aSWZcEZ --- client/src/components/bunny-video-modal.tsx | 132 +++++++++++++++++++- client/src/components/video-grid.tsx | 6 + 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/client/src/components/bunny-video-modal.tsx b/client/src/components/bunny-video-modal.tsx index f244b47..a3b17bf 100644 --- a/client/src/components/bunny-video-modal.tsx +++ b/client/src/components/bunny-video-modal.tsx @@ -14,6 +14,8 @@ interface BunnyVideoModalProps { isOpen: boolean; onClose: () => void; onEdit?: () => void; + videos?: Video[]; + onVideoChange?: (video: Video) => void; } function formatDuration(seconds: number): string { @@ -49,8 +51,11 @@ function formatDate(date: Date | string): string { return `Pred ${Math.floor(diffDays / 30)} mesec${Math.floor(diffDays / 30) > 1 ? 'i' : 'em'}`; } -export default function BunnyVideoModal({ video, isOpen, onClose, onEdit }: BunnyVideoModalProps) { +export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos = [], onVideoChange }: BunnyVideoModalProps) { const [showShareMenu, setShowShareMenu] = useState(false); + const [isDragging, setIsDragging] = useState(false); + const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); + const [dragOffset, setDragOffset] = useState(0); useEffect(() => { const handleEscape = (e: KeyboardEvent) => { @@ -137,6 +142,100 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit }: Bunn setShowShareMenu(false); }; + // Navigation functions + const getCurrentVideoIndex = () => { + if (!video || !videos.length) return -1; + return videos.findIndex(v => v.id === video.id); + }; + + const navigateToVideo = (direction: 'next' | 'prev') => { + const currentIndex = getCurrentVideoIndex(); + if (currentIndex === -1) return; + + let newIndex; + if (direction === 'next') { + newIndex = currentIndex + 1 >= videos.length ? 0 : currentIndex + 1; + } else { + newIndex = currentIndex - 1 < 0 ? videos.length - 1 : currentIndex - 1; + } + + const newVideo = videos[newIndex]; + if (newVideo && onVideoChange) { + onVideoChange(newVideo); + } + }; + + // Touch and mouse drag handlers + const handleDragStart = (clientX: number, clientY: number) => { + setIsDragging(true); + setDragStart({ x: clientX, y: clientY }); + setDragOffset(0); + }; + + const handleDragMove = (clientX: number, clientY: number) => { + if (!isDragging) return; + + const deltaX = clientX - dragStart.x; + const deltaY = Math.abs(clientY - dragStart.y); + + // Only allow horizontal drag if it's more horizontal than vertical + if (deltaY < Math.abs(deltaX)) { + setDragOffset(deltaX); + } + }; + + const handleDragEnd = () => { + if (!isDragging) return; + + const threshold = 100; // minimum drag distance to trigger navigation + + if (Math.abs(dragOffset) > threshold && videos.length > 1) { + if (dragOffset > 0) { + navigateToVideo('prev'); // drag right = previous video + } else { + navigateToVideo('next'); // drag left = next video + } + } + + setIsDragging(false); + setDragOffset(0); + }; + + // Mouse events + const handleMouseDown = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) return; // only on video area + handleDragStart(e.clientX, e.clientY); + }; + + const handleMouseMove = (e: React.MouseEvent) => { + handleDragMove(e.clientX, e.clientY); + }; + + const handleMouseUp = () => { + handleDragEnd(); + }; + + // Touch events + const handleTouchStart = (e: React.TouchEvent) => { + if (e.touches.length !== 1) return; + const touch = e.touches[0]; + handleDragStart(touch.clientX, touch.clientY); + e.preventDefault(); + }; + + const handleTouchMove = (e: React.TouchEvent) => { + if (e.touches.length !== 1) return; + if (!isDragging) return; + const touch = e.touches[0]; + handleDragMove(touch.clientX, touch.clientY); + e.preventDefault(); + }; + + const handleTouchEnd = (e: React.TouchEvent) => { + handleDragEnd(); + e.preventDefault(); + }; + if (!isOpen || !video) return null; return ( @@ -231,7 +330,17 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit }: Bunn
{/* Main video player */}
-
+
{video.videoUrlIframe ? (