Add mute and unmute functionality to video previews on cards

Integrates a mute/unmute toggle button into the video card component, allowing users to control audio during video previews. The state is managed with `useState` and the video element's `muted` property is updated accordingly.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2cd2c0bc-434c-4bc9-ad3f-b99d3897a0d1/4DOsXkx
This commit is contained in:
sebastjanartic 2025-09-02 15:41:22 +00:00
parent 45987ab28a
commit f4052654ae

View File

@ -1,4 +1,4 @@
import { Play } from "lucide-react"; import { Play, Volume2, VolumeX } from "lucide-react";
import { type Video } from "@shared/schema"; import { type Video } from "@shared/schema";
import { useState, useRef, useEffect } from "react"; import { useState, useRef, useEffect } from "react";
import Hls from "hls.js"; import Hls from "hls.js";
@ -46,6 +46,7 @@ function formatDate(date: Date | string): string {
export default function VideoCard({ video, onClick, className = "", hideOverlay = false }: VideoCardProps) { export default function VideoCard({ video, onClick, className = "", hideOverlay = false }: VideoCardProps) {
const [isHovered, setIsHovered] = useState(false); const [isHovered, setIsHovered] = useState(false);
const [showPreview, setShowPreview] = useState(false); const [showPreview, setShowPreview] = useState(false);
const [isMuted, setIsMuted] = useState(true);
const hoverTimeoutRef = useRef<NodeJS.Timeout>(); const hoverTimeoutRef = useRef<NodeJS.Timeout>();
const videoRef = useRef<HTMLVideoElement>(null); const videoRef = useRef<HTMLVideoElement>(null);
const hlsRef = useRef<Hls | null>(null); const hlsRef = useRef<Hls | null>(null);
@ -171,7 +172,7 @@ export default function VideoCard({ video, onClick, className = "", hideOverlay
objectFit: 'cover' objectFit: 'cover'
}} }}
autoPlay autoPlay
muted={window.innerWidth >= 768 ? false : true} muted={isMuted}
loop loop
playsInline playsInline
controls={false} controls={false}
@ -192,6 +193,26 @@ export default function VideoCard({ video, onClick, className = "", hideOverlay
}} }}
/> />
{/* Mute/Unmute button */}
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setIsMuted(!isMuted);
if (videoRef.current) {
videoRef.current.muted = !isMuted;
}
}}
className="absolute top-2 right-2 z-20 bg-black/50 hover:bg-black/70 text-white border-none p-2 rounded-full transition-all duration-200 opacity-75 hover:opacity-100"
data-testid="button-mute-toggle"
>
{isMuted ? (
<VolumeX className="w-4 h-4" />
) : (
<Volume2 className="w-4 h-4" />
)}
</button>
{/* Video scrubbing progress bar - only show during preview */} {/* Video scrubbing progress bar - only show during preview */}
{duration > 0 && ( {duration > 0 && (
<div className="absolute bottom-1 left-2 right-2 h-2 bg-black/40 rounded-full overflow-hidden backdrop-blur-sm border border-white/20"> <div className="absolute bottom-1 left-2 right-2 h-2 bg-black/40 rounded-full overflow-hidden backdrop-blur-sm border border-white/20">