126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
|
import { ArrowLeftIcon } from '../icons/ArrowLeftIcon';
|
|
import { ArrowRightIcon } from '../icons/ArrowRightIcon';
|
|
import { delay } from 'framer-motion';
|
|
|
|
export const SliderControls = forwardRef<
|
|
{ left: () => void; right: () => void },
|
|
{
|
|
slidesCount: number;
|
|
width: number;
|
|
height: number;
|
|
slide: number;
|
|
onLeftClick: () => void;
|
|
onRightClick: () => void;
|
|
className?: string;
|
|
}
|
|
>(
|
|
(
|
|
{
|
|
slidesCount,
|
|
height,
|
|
width,
|
|
slide = 0,
|
|
onLeftClick,
|
|
onRightClick,
|
|
className,
|
|
},
|
|
ref,
|
|
) => {
|
|
const length = 2 * Math.PI * (height / 2) + (width - height) * 2;
|
|
|
|
const prevBtnRef = useRef<HTMLButtonElement>(null);
|
|
const nextBtnRef = useRef<HTMLButtonElement>(null);
|
|
const rectRef = useRef<SVGRectElement>(null);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
left: () => prevBtnRef.current?.click(),
|
|
right: () => nextBtnRef.current?.click(),
|
|
}));
|
|
|
|
return (
|
|
<div className={'flex items-center gap-2 ' + className}>
|
|
<div className="relative flex justify-center max-sm:order-2">
|
|
<svg
|
|
width={width}
|
|
height={height}
|
|
viewBox={`0 0 ${width} ${height}`}
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="bg-[#14161F] rounded-full fill-none"
|
|
>
|
|
<rect
|
|
x="1"
|
|
y="1"
|
|
width={width - 2}
|
|
height={height - 2}
|
|
rx={(height - 2) / 2}
|
|
stroke="#3D425C"
|
|
strokeLinecap="butt"
|
|
/>
|
|
<rect
|
|
className="transition-all duration-300"
|
|
ref={rectRef}
|
|
x="1"
|
|
y="1"
|
|
width={width - 2}
|
|
height={height - 2}
|
|
rx={(height - 2) / 2}
|
|
stroke="white"
|
|
strokeLinecap="butt"
|
|
strokeDasharray={`calc(${length}/${slidesCount}*${slide + 1}) ${length - (length / slidesCount) * (slide + 1)}`}
|
|
strokeDashoffset={`-${height / 2}`}
|
|
/>
|
|
</svg>
|
|
<p className="absolute self-center font-medium h4">
|
|
{Math.round(slide) + 1} из {slidesCount}
|
|
</p>
|
|
</div>
|
|
<button
|
|
ref={prevBtnRef}
|
|
onClick={() => {
|
|
if (slide === 0) {
|
|
rectRef.current!.classList.remove(
|
|
'transition-all',
|
|
'duration-300',
|
|
);
|
|
rectRef.current!.setAttribute('stroke-dasharray', `${length} 0`);
|
|
delay(() => {
|
|
rectRef.current!.classList.add(
|
|
'transition-all',
|
|
'duration-300',
|
|
);
|
|
}, 1);
|
|
}
|
|
onLeftClick();
|
|
}}
|
|
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F]"
|
|
>
|
|
<ArrowLeftIcon />
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
if (slide + 1 === slidesCount) {
|
|
rectRef.current!.classList.remove(
|
|
'transition-all',
|
|
'duration-300',
|
|
);
|
|
rectRef.current!.setAttribute('stroke-dasharray', `0 ${length}`);
|
|
delay(() => {
|
|
rectRef.current!.classList.add(
|
|
'transition-all',
|
|
'duration-300',
|
|
);
|
|
}, 1);
|
|
}
|
|
onRightClick();
|
|
}}
|
|
ref={nextBtnRef}
|
|
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F] max-sm:order-2"
|
|
>
|
|
<ArrowRightIcon />
|
|
</button>
|
|
</div>
|
|
);
|
|
},
|
|
);
|