VideoPlayer.tsx

1'use client'
2
3import { useRef, useState } from 'react'
4import { Play, Pause, Volume2, Volume1, VolumeX, Volume } from 'lucide-react'
5
6interface VideoPlayerProps {
7	src: string
8}
9
10export function VideoPlayer({ src }: VideoPlayerProps) {
11	const videoRef = useRef<HTMLVideoElement>(null)
12	const [isPlaying, setIsPlaying] = useState(false)
13	const [progress, setProgress] = useState(0)
14	const [volume, setVolume] = useState(1)
15
16	const togglePlay = () => {
17		if (videoRef.current) {
18			if (isPlaying) {
19				videoRef.current.pause()
20			} else {
21				videoRef.current.play()
22			}
23			setIsPlaying(!isPlaying)
24		}
25	}
26
27	const handleTimeUpdate = () => {
28		if (videoRef.current) {
29			const progress =
30				(videoRef.current.currentTime / videoRef.current.duration) * 100
31			setProgress(progress)
32		}
33	}
34
35	const handleProgressClick = (e: React.MouseEvent<HTMLDivElement>) => {
36		if (videoRef.current) {
37			const rect = e.currentTarget.getBoundingClientRect()
38			const x = e.clientX - rect.left
39			const percentage = x / rect.width
40			videoRef.current.currentTime = percentage * videoRef.current.duration
41		}
42	}
43
44	const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
45		const newVolume = parseFloat(e.target.value)
46		setVolume(newVolume)
47		if (videoRef.current) {
48			videoRef.current.volume = newVolume
49		}
50	}
51
52	const getVolumeIcon = () => {
53		if (volume === 0) return <VolumeX className="h-4 w-4" />
54		if (volume < 0.3) return <Volume className="h-4 w-4" />
55		if (volume < 0.7) return <Volume1 className="h-4 w-4" />
56		return <Volume2 className="h-4 w-4" />
57	}
58
59	return (
60		<div className="markdown-video-player group relative overflow-hidden rounded-lg bg-gray-900">
61			<video
62				ref={videoRef}
63				src={src}
64				className="w-full"
65				onTimeUpdate={handleTimeUpdate}
66				onClick={togglePlay}
67			/>
68
69			<div className="absolute bottom-0 left-0 right-0 bg-black/50 p-2 opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100">
70				<div className="flex items-center gap-2">
71					<button
72						onClick={togglePlay}
73						className="text-white transition-colors hover:text-purple-400"
74					>
75						{isPlaying ?
76							<Pause className="h-6 w-6" />
77						:	<Play className="h-6 w-6" />}
78					</button>
79
80					<div
81						className="h-1 flex-1 cursor-pointer rounded-full bg-gray-700"
82						onClick={handleProgressClick}
83					>
84						<div
85							className="h-full rounded-full bg-purple-500"
86							style={{ width: `${progress}%` }}
87						/>
88					</div>
89
90					<div className="flex w-24 items-center gap-1">
91						<span className="text-white">{getVolumeIcon()}</span>
92						<input
93							type="range"
94							min="0"
95							max="1"
96							step="0.1"
97							value={volume}
98							onChange={handleVolumeChange}
99							className="w-full"
100						/>
101					</div>
102				</div>
103			</div>
104		</div>
105	)
106}
107