visualize_dataset / src /components /playback-bar.tsx
mishig's picture
mishig HF Staff
Sync from GitHub via hub-sync
461b74e verified
Raw
History Blame Contribute Delete
4.23 kB
import React from "react";
import { useTime } from "../context/time-context";
import {
FaPlay,
FaPause,
FaBackward,
FaForward,
FaUndoAlt,
FaArrowDown,
FaArrowUp,
} from "react-icons/fa";
const PlaybackBar: React.FC = () => {
const { duration, isPlaying, setIsPlaying, currentTime, seek } = useTime();
const sliderActiveRef = React.useRef(false);
const wasPlayingRef = React.useRef(false);
const sliderValueRef = React.useRef(currentTime);
const [sliderValue, setSliderValue] = React.useState(currentTime);
// Only update sliderValue from context if not dragging
React.useEffect(() => {
if (!sliderActiveRef.current) {
sliderValueRef.current = currentTime;
setSliderValue(currentTime);
}
}, [currentTime]);
const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const t = Number(e.target.value);
sliderValueRef.current = t;
setSliderValue(t);
// Seek videos immediately while dragging (no debounce)
seek(t);
};
const handleSliderMouseDown = () => {
sliderActiveRef.current = true;
wasPlayingRef.current = isPlaying;
setIsPlaying(false);
};
const handleSliderMouseUp = () => {
sliderActiveRef.current = false;
// Final seek to exact slider position
seek(sliderValueRef.current);
if (wasPlayingRef.current) {
setIsPlaying(true);
}
};
return (
<div className="sticky bottom-0 mt-auto w-full max-w-4xl mx-auto flex items-center gap-3 panel-raised bg-[var(--surface-0)]/90 backdrop-blur px-3 py-2">
<button
title="Jump backward 5 seconds"
onClick={() => seek(Math.max(0, currentTime - 5))}
className="hidden md:flex h-8 w-8 items-center justify-center rounded-md text-slate-400 hover:text-slate-100 hover:bg-white/5 transition-colors"
>
<FaBackward size={14} />
</button>
<button
className="flex h-9 w-9 items-center justify-center rounded-md bg-cyan-400/10 border border-cyan-400/30 text-cyan-300 hover:bg-cyan-400/15 transition-colors"
title={
isPlaying ? "Pause. Toggle with Space" : "Play. Toggle with Space"
}
onClick={() => setIsPlaying(!isPlaying)}
>
{isPlaying ? <FaPause size={14} /> : <FaPlay size={14} />}
</button>
<button
title="Jump forward 5 seconds"
onClick={() => seek(Math.min(duration, currentTime + 5))}
className="hidden md:flex h-8 w-8 items-center justify-center rounded-md text-slate-400 hover:text-slate-100 hover:bg-white/5 transition-colors"
>
<FaForward size={14} />
</button>
<button
title="Rewind from start"
onClick={() => seek(0)}
className="hidden md:flex h-8 w-8 items-center justify-center rounded-md text-slate-400 hover:text-slate-100 hover:bg-white/5 transition-colors"
>
<FaUndoAlt size={14} />
</button>
<input
type="range"
min={0}
max={duration}
step={0.01}
value={sliderValue}
onChange={handleSliderChange}
onMouseDown={handleSliderMouseDown}
onMouseUp={handleSliderMouseUp}
onTouchStart={handleSliderMouseDown}
onTouchEnd={handleSliderMouseUp}
className="flex-1 mx-1 h-1 accent-cyan-400 cursor-pointer focus:outline-none focus:ring-0"
aria-label="Seek video"
/>
<span className="w-16 text-right tabular text-[11px] text-slate-400 shrink-0">
{Math.floor(sliderValue)} / {Math.floor(duration)}
</span>
<div className="hidden lg:flex flex-col gap-y-0.5 ml-4 text-[10px] text-slate-500 select-none">
<p className="inline-flex items-center gap-1.5">
<kbd className="px-1.5 py-0.5 rounded border border-white/10 bg-white/5 text-slate-300 text-[10px]">
Space
</kbd>
<span>pause/unpause</span>
</p>
<p className="inline-flex items-center gap-1.5">
<span className="inline-flex items-center gap-0.5 text-slate-300">
<FaArrowUp size={10} />
<FaArrowDown size={10} />
</span>
<span>prev/next episode</span>
</p>
</div>
</div>
);
};
export default PlaybackBar;