Web:Common:Components:MediaViewer:Sub-Components:Added PlayerTimeline component

This commit is contained in:
Akmal Isomadinov 2023-03-17 23:54:39 +05:00
parent 2e0aa10efd
commit c21cf0a3be
3 changed files with 306 additions and 0 deletions

View File

@ -0,0 +1,9 @@
interface PlayerTimelineProps {
value: number;
duration: number;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
onMouseEnter: VoidFunction;
onMouseLeave: VoidFunction;
}
export default PlayerTimelineProps;

View File

@ -0,0 +1,180 @@
import { isMobile } from "react-device-detect";
import styled, { css } from "styled-components";
export const HoverProgress = styled.div`
display: none;
position: absolute;
left: 2px;
height: 6px;
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.3);
`;
const mobileCss = css`
margin-top: 16px;
input[type="range"]::-webkit-slider-thumb {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: visible;
opacity: 1;
background: #fff;
height: 10px;
width: 10px;
border-radius: 50%;
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: visible;
opacity: 1;
background: #fff;
height: 10px;
width: 10px;
border-radius: 50%;
cursor: pointer;
}
input[type="range"]::-ms-fill-upper {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: visible;
opacity: 1;
background: #fff;
height: 10px;
width: 10px;
border-radius: 50%;
cursor: pointer;
}
`;
export const PlayerTimelineWrapper = styled.div`
position: relative;
display: flex;
align-items: center;
margin-top: 92px;
height: 4px;
width: 100%;
cursor: pointer;
time {
display: none;
position: absolute;
left: 50%;
top: -25px;
font-size: 13px;
color: #fff;
pointer-events: none;
transform: translateX(-50%);
}
@media (hover: hover) {
&:hover {
/* height: 6px; */
input {
height: 6px;
}
${HoverProgress} {
display: block;
}
transition: 0.1s height ease-in;
}
&:hover time {
display: block;
}
}
input {
width: 100%;
height: 4px;
outline: none;
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
border-radius: 5px;
background: rgba(255, 255, 255, 0.3);
background-image: linear-gradient(#fff, #fff);
background-repeat: no-repeat;
z-index: 1;
&:hover {
cursor: pointer;
}
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: hidden;
opacity: 0;
background: #fff;
}
input[type="range"]::-moz-range-thumb {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: hidden;
opacity: 0;
background: #fff;
}
input[type="range"]::-ms-fill-upper {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
visibility: hidden;
opacity: 0;
background: #fff;
}
&:hover {
input[type="range"]::-webkit-slider-thumb {
visibility: visible;
height: 12px;
width: 12px;
opacity: 1 !important;
border-radius: 50%;
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
visibility: visible;
height: 12px;
width: 12px;
opacity: 1 !important;
border-radius: 50%;
cursor: pointer;
border: none;
}
input[type="range"]::-ms-fill-upper {
visibility: visible;
height: 12px;
width: 12px;
opacity: 1 !important;
border-radius: 50%;
cursor: pointer;
}
}
${isMobile && mobileCss}
`;

View File

@ -0,0 +1,117 @@
import React, { useRef } from "react";
import { formatTime } from "../../helpers";
import PlayerTimelineProps from "./PlayerTimeline.props";
import { HoverProgress, PlayerTimelineWrapper } from "./PlayerTimeline.styled";
function PlayerTimeline({
value,
duration,
onChange,
onMouseEnter,
onMouseLeave,
}: PlayerTimelineProps) {
const timelineTooltipRef = useRef<HTMLTimeElement>(null);
const timelineRef = useRef<HTMLDivElement>(null);
const hoverProgressRef = useRef<HTMLDivElement>(null);
const setTimeoutTimelineTooltipRef = useRef<NodeJS.Timeout>();
const showTimelineTooltip = () => {
if (!timelineTooltipRef.current) return;
const callback = () => {
if (timelineTooltipRef.current) {
timelineTooltipRef.current.style.removeProperty("display");
setTimeoutTimelineTooltipRef.current = undefined;
}
};
if (setTimeoutTimelineTooltipRef.current) {
clearTimeout(setTimeoutTimelineTooltipRef.current);
setTimeoutTimelineTooltipRef.current = setTimeout(callback, 500);
} else {
timelineTooltipRef.current.style.display = "block";
setTimeoutTimelineTooltipRef.current = setTimeout(callback, 500);
}
};
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (!timelineTooltipRef.current || !timelineRef.current) return;
const { clientWidth } = timelineRef.current;
const percent = Number(event.target.value) / 100;
const offsetX = clientWidth * percent;
const time = Math.floor(percent * duration);
const left =
offsetX < 20
? 20
: offsetX > clientWidth - 20
? clientWidth - 20
: offsetX;
timelineTooltipRef.current.style.left = `${left}px`;
timelineTooltipRef.current.innerText = formatTime(time);
showTimelineTooltip();
onChange(event);
};
const hadleMouseMove = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
if (
!timelineTooltipRef.current ||
!timelineRef.current ||
!hoverProgressRef.current
)
return;
const { clientWidth } = timelineRef.current;
const { max, min } = Math;
const offsetX = min(max(event.nativeEvent.offsetX, 0), clientWidth);
const percent = Math.floor((offsetX / clientWidth) * duration);
hoverProgressRef.current.style.width = `${offsetX}px`;
const left =
offsetX < 20
? 20
: offsetX > clientWidth - 20
? clientWidth - 20
: offsetX;
timelineTooltipRef.current.style.left = `${left}px`;
timelineTooltipRef.current.innerText = formatTime(percent);
};
return (
<PlayerTimelineWrapper
ref={timelineRef}
onMouseMove={hadleMouseMove}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<time ref={timelineTooltipRef}>00:00</time>
<HoverProgress ref={hoverProgressRef} />
<input
min="0"
max="100"
step="any"
type="range"
value={value}
onChange={handleOnChange}
style={{
backgroundSize: `${value}% 100%`,
}}
/>
</PlayerTimelineWrapper>
);
}
export default PlayerTimeline;