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:
parent
45987ab28a
commit
f4052654ae
@ -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">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user