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:
Leonid Pershin
2026-07-25 06:43:19 +03:00
parent 0ac2973f46
commit 19013a61dc
@@ -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>