sudo-archive/src/components/video/controls/VolumeControl.tsx

90 lines
2.8 KiB
TypeScript
Raw Normal View History

2023-01-09 20:51:24 +00:00
import { Icon, Icons } from "@/components/Icon";
import {
makePercentage,
makePercentageString,
useProgressBar,
} from "@/hooks/useProgressBar";
2023-01-10 18:53:55 +00:00
import { canChangeVolume } from "@/utils/detectFeatures";
import { useCallback, useEffect, useRef, useState } from "react";
2023-01-08 16:51:38 +00:00
import { useVideoPlayerState } from "../VideoContext";
2023-01-09 20:51:24 +00:00
interface Props {
className?: string;
}
export function VolumeControl(props: Props) {
2023-01-08 16:51:38 +00:00
const { videoState } = useVideoPlayerState();
const ref = useRef<HTMLDivElement>(null);
2023-01-09 20:51:24 +00:00
const [storedVolume, setStoredVolume] = useState(1);
const [hoveredOnce, setHoveredOnce] = useState(false);
2023-01-08 16:51:38 +00:00
2023-01-09 20:51:24 +00:00
const commitVolume = useCallback(
(percentage) => {
videoState.setVolume(percentage);
setStoredVolume(percentage);
2023-01-08 16:51:38 +00:00
},
2023-01-09 20:51:24 +00:00
[videoState, setStoredVolume]
2023-01-08 16:51:38 +00:00
);
2023-01-09 20:51:24 +00:00
const { dragging, dragPercentage, dragMouseDown } = useProgressBar(
ref,
commitVolume,
true
);
2023-01-10 18:53:55 +00:00
useEffect(() => {
if (!videoState.leftControlHovering) setHoveredOnce(false);
}, [videoState, setHoveredOnce]);
2023-01-09 20:51:24 +00:00
const handleClick = useCallback(() => {
if (videoState.volume > 0) {
videoState.setVolume(0);
setStoredVolume(videoState.volume);
} else {
videoState.setVolume(storedVolume > 0 ? storedVolume : 1);
}
}, [videoState, setStoredVolume, storedVolume]);
2023-01-10 18:53:55 +00:00
const handleMouseEnter = useCallback(async () => {
if (await canChangeVolume()) setHoveredOnce(true);
2023-01-09 20:51:24 +00:00
}, [setHoveredOnce]);
let percentage = makePercentage(videoState.volume * 100);
if (dragging) percentage = makePercentage(dragPercentage);
const percentageString = makePercentageString(percentage);
2023-01-08 16:51:38 +00:00
return (
2023-01-09 20:51:24 +00:00
<div className={props.className}>
2023-01-08 16:51:38 +00:00
<div
2023-01-09 20:51:24 +00:00
className="pointer-events-auto flex cursor-pointer items-center"
onMouseEnter={handleMouseEnter}
>
<div className="px-4 text-2xl text-white" onClick={handleClick}>
<Icon icon={percentage > 0 ? Icons.VOLUME : Icons.VOLUME_X} />
</div>
<div
2023-01-10 18:53:55 +00:00
className={`linear -ml-2 w-0 overflow-hidden transition-[width,opacity] duration-300 ${
hoveredOnce || dragging ? "!w-24 opacity-100" : "w-4 opacity-0"
2023-01-09 20:51:24 +00:00
}`}
>
<div
ref={ref}
2023-01-09 23:27:04 +00:00
className="flex h-10 w-20 items-center px-2"
2023-01-09 20:51:24 +00:00
onMouseDown={dragMouseDown}
>
<div className="relative h-1 flex-1 rounded-full bg-gray-500 bg-opacity-50">
<div
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-bink-500"
style={{
width: percentageString,
}}
>
<div className="absolute h-3 w-3 translate-x-1/2 rounded-full bg-white" />
</div>
</div>
</div>
</div>
</div>
2023-01-08 16:51:38 +00:00
</div>
);
}