veza/apps/web/src/features/player/components/player-bar/PlayerBarProgress.tsx

55 lines
1.5 KiB
TypeScript
Raw Normal View History

/**
* PlayerBarProgress Seek bar with 60fps (transform-based)
* KŌDŌ gradient: --chart-1 --chart-2
*/
import { useRef, useEffect } from 'react';
import { cn } from '@/lib/utils';
interface PlayerBarProgressProps {
currentTime: number;
duration: number;
onSeek: (pct: number) => void;
className?: string;
}
export function PlayerBarProgress({
currentTime,
duration,
onSeek,
className,
}: PlayerBarProgressProps) {
const barRef = useRef<HTMLDivElement>(null);
const pct = duration > 0 ? Math.max(0, Math.min(1, currentTime / duration)) : 0;
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (!barRef.current) return;
const rect = barRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
onSeek(Math.max(0, Math.min(1, x / rect.width)));
};
return (
<div
ref={barRef}
role="slider"
aria-label="Progression"
aria-valuemin={0}
aria-valuemax={duration}
aria-valuenow={currentTime}
tabIndex={0}
className={cn(
'absolute bottom-0 left-0 right-0 h-1.5 z-20 cursor-pointer',
'bg-[var(--sumi-border-default)] hover:bg-[var(--sumi-border-strong)] transition-colors duration-[var(--sumi-duration-fast)]',
className,
)}
onClick={handleClick}
>
<div
className="h-full rounded-r bg-[var(--sumi-accent)] transition-[transform] duration-75 ease-out will-change-transform"
style={{ transform: `scaleX(${pct})`, transformOrigin: 'left' }}
/>
</div>
);
}