Implement control visibility logic in ChannelPlayer: add functionality to hide and reveal controls based on user interaction, enhancing the user experience during video playback. This includes managing visibility on mouse movements and video play/pause events.
This commit is contained in:
@@ -21,6 +21,33 @@ export function ChannelPlayer({
|
||||
const [playing, setPlaying] = useState(false)
|
||||
const [muted, setMuted] = useState(true)
|
||||
const [volume, setVolume] = useState(1)
|
||||
const [controlsVisible, setControlsVisible] = useState(true)
|
||||
const hideTimerRef = useRef<number | null>(null)
|
||||
const overControlsRef = useRef(false)
|
||||
|
||||
const clearHideTimer = useCallback(() => {
|
||||
if (hideTimerRef.current !== null) {
|
||||
window.clearTimeout(hideTimerRef.current)
|
||||
hideTimerRef.current = null
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Прячем панель и курсор после бездействия — но не когда курсор на панели или видео на паузе.
|
||||
const scheduleHide = useCallback(() => {
|
||||
clearHideTimer()
|
||||
hideTimerRef.current = window.setTimeout(() => {
|
||||
if (!overControlsRef.current && videoRef.current && !videoRef.current.paused) {
|
||||
setControlsVisible(false)
|
||||
}
|
||||
}, 2500)
|
||||
}, [clearHideTimer])
|
||||
|
||||
const revealControls = useCallback(() => {
|
||||
setControlsVisible(true)
|
||||
scheduleHide()
|
||||
}, [scheduleHide])
|
||||
|
||||
useEffect(() => clearHideTimer, [clearHideTimer])
|
||||
|
||||
const seekToLiveEdge = useCallback(() => {
|
||||
const video = videoRef.current
|
||||
@@ -110,7 +137,14 @@ export function ChannelPlayer({
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="group relative aspect-video w-full overflow-hidden rounded-md border border-border bg-black"
|
||||
onMouseMove={revealControls}
|
||||
onMouseLeave={() => {
|
||||
clearHideTimer()
|
||||
if (videoRef.current && !videoRef.current.paused) setControlsVisible(false)
|
||||
}}
|
||||
className={`relative aspect-video w-full overflow-hidden rounded-md border border-border bg-black ${
|
||||
controlsVisible ? '' : 'cursor-none'
|
||||
}`}
|
||||
>
|
||||
<video
|
||||
ref={videoRef}
|
||||
@@ -119,11 +153,31 @@ export function ChannelPlayer({
|
||||
className="h-full w-full"
|
||||
onClick={togglePlay}
|
||||
onDoubleClick={toggleFullscreen}
|
||||
onPlay={() => setPlaying(true)}
|
||||
onPause={() => setPlaying(false)}
|
||||
onPlay={() => {
|
||||
setPlaying(true)
|
||||
scheduleHide()
|
||||
}}
|
||||
onPause={() => {
|
||||
setPlaying(false)
|
||||
clearHideTimer()
|
||||
setControlsVisible(true)
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="absolute inset-x-0 bottom-0 flex items-center gap-3 bg-gradient-to-t from-black/70 to-transparent px-3 py-2 text-white opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
overControlsRef.current = true
|
||||
clearHideTimer()
|
||||
setControlsVisible(true)
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
overControlsRef.current = false
|
||||
scheduleHide()
|
||||
}}
|
||||
className={`absolute inset-x-0 bottom-0 flex items-center gap-3 bg-gradient-to-t from-black/70 to-transparent px-3 py-2 text-white transition-opacity ${
|
||||
controlsVisible ? 'opacity-100' : 'pointer-events-none opacity-0'
|
||||
}`}
|
||||
>
|
||||
<button type="button" onClick={togglePlay} aria-label="play/pause">
|
||||
{playing ? <Pause className="h-5 w-5" /> : <Play className="h-5 w-5" />}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user