Show video playback controls when user interacts with the video

Implement logic to temporarily display video playback controls on click and hover events within the BunnyVideoModal component. Add new state variables `showControls` and `controlsTimeout` to manage the visibility and auto-hiding of controls. Update the video player container's className to include `cursor-pointer` and an `onClick` handler `handleVideoClick` which triggers `showControlsTemporarily`. The `onMouseEnter` and `onMouseLeave` handlers on the video player container also manage control visibility and timeouts. Navigation buttons now conditionally render with `opacity-100` or `opacity-0 pointer-events-none` based on the `showControls` state.

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/dDOZBYz
This commit is contained in:
sebastjanartic 2025-08-28 20:37:41 +00:00
parent e081f95816
commit b643ba2a2c

View File

@ -53,6 +53,8 @@ function formatDate(date: Date | string): string {
export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos = [], onVideoChange }: BunnyVideoModalProps) { export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos = [], onVideoChange }: BunnyVideoModalProps) {
const [showShareMenu, setShowShareMenu] = useState(false); const [showShareMenu, setShowShareMenu] = useState(false);
const [showControls, setShowControls] = useState(true);
const [controlsTimeout, setControlsTimeout] = useState<NodeJS.Timeout | null>(null);
// Navigation functions // Navigation functions
const getCurrentVideoIndex = () => { const getCurrentVideoIndex = () => {
@ -77,6 +79,21 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos
} }
}; };
// Controls visibility logic
const showControlsTemporarily = () => {
setShowControls(true);
if (controlsTimeout) {
clearTimeout(controlsTimeout);
}
const timeout = setTimeout(() => {
setShowControls(false);
}, 3000); // Hide after 3 seconds
setControlsTimeout(timeout);
};
const handleVideoClick = () => {
showControlsTemporarily();
};
useEffect(() => { useEffect(() => {
const handleEscape = (e: KeyboardEvent) => { const handleEscape = (e: KeyboardEvent) => {
@ -259,7 +276,16 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos
{/* Main video player */} {/* Main video player */}
<div className="flex-1"> <div className="flex-1">
<div <div
className="relative w-full h-0 pb-[56.25%] bg-black rounded-lg overflow-hidden" className="relative w-full h-0 pb-[56.25%] bg-black rounded-lg overflow-hidden cursor-pointer"
onClick={handleVideoClick}
onMouseEnter={() => setShowControls(true)}
onMouseLeave={() => {
if (controlsTimeout) {
clearTimeout(controlsTimeout);
}
const timeout = setTimeout(() => setShowControls(false), 1000);
setControlsTimeout(timeout);
}}
> >
{video.videoUrlIframe ? ( {video.videoUrlIframe ? (
<iframe <iframe
@ -278,12 +304,12 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos
)} )}
{/* Navigation buttons */} {/* Navigation buttons - show/hide with controls */}
{videos.length > 1 && ( {videos.length > 1 && (
<> <>
<Button <Button
onClick={() => navigateToVideo('prev')} onClick={() => navigateToVideo('prev')}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-80 text-white border-none p-2 rounded-full z-20" className={`absolute left-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-80 text-white border-none p-2 rounded-full z-20 transition-opacity duration-300 ${showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
size="sm" size="sm"
data-testid="button-prev-video" data-testid="button-prev-video"
> >
@ -291,7 +317,7 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos
</Button> </Button>
<Button <Button
onClick={() => navigateToVideo('next')} onClick={() => navigateToVideo('next')}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-80 text-white border-none p-2 rounded-full z-20" className={`absolute right-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-80 text-white border-none p-2 rounded-full z-20 transition-opacity duration-300 ${showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
size="sm" size="sm"
data-testid="button-next-video" data-testid="button-next-video"
> >
@ -299,8 +325,8 @@ export default function BunnyVideoModal({ video, isOpen, onClose, onEdit, videos
</Button> </Button>
{/* Video counter */} {/* Video counter - always visible but subtle */}
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-50 rounded-full px-3 py-1 text-white text-sm pointer-events-none z-10"> <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-30 rounded-full px-3 py-1 text-white text-sm pointer-events-none z-10">
{getCurrentVideoIndex() + 1} od {videos.length} {getCurrentVideoIndex() + 1} od {videos.length}
</div> </div>
</> </>