raphyartsy/src/components/Slider.tsx

84 lines
2.6 KiB
TypeScript

import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
import { useKeenSlider } from "keen-slider/react";
import { useState, type MouseEvent } from "react";
interface SliderProps {
className?: React.ComponentProps<'div'>['className'];
children?: React.ReactNode;
}
export default function Slider({ className, children }: SliderProps) {
const [currentSlide, setCurrentSlide] = useState(0);
const [loaded, setLoaded] = useState(false);
const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>({
initial: 0,
slideChanged(slider) {
setCurrentSlide(slider.track.details.rel);
},
created() {
setLoaded(true);
},
});
const goPrev = (e: MouseEvent<unknown>) => {
e.stopPropagation();
if (currentSlide !== 0) {
instanceRef.current?.prev();
}
};
const goNext = (e: MouseEvent<unknown>) => {
e.stopPropagation();
if (instanceRef.current && currentSlide !== instanceRef.current.track.details.slides.length - 1) {
instanceRef.current.next();
}
};
return (
<div className={`${className} relative`}>
<div>
<div ref={sliderRef} className="flex overflow-hidden relative w-full">
{children}
</div>
{loaded && instanceRef.current && (
<>
<Arrow left onClick={goPrev} disabled={currentSlide === 0} />
<Arrow onClick={goNext} disabled={instanceRef.current ? currentSlide === instanceRef.current.track.details.slides.length - 1 : true} />
</>
)}
</div>
{loaded && instanceRef.current && (
<div className="flex justify-center py-2">
{Array.from({ length: instanceRef.current.track.details.slides.length }, (_, idx) => (
<button
key={idx}
onClick={() => instanceRef.current?.moveToIdx(idx)}
className={`w-2.5 h-2.5 bg-white rounded-full m-1 cursor-pointer ${currentSlide === idx ? "opacity-30" : ""}`}
></button>
))}
</div>
)}
</div>
);
}
interface ArrowProps {
disabled: boolean;
left?: boolean;
onClick: (e: MouseEvent<unknown>) => void;
}
function Arrow({ disabled, left, onClick }: ArrowProps) {
const Icon = left ? ChevronLeftIcon : ChevronRightIcon;
const position = left ? '-left-10' : 'left-auto -right-10';
return (
<Icon
onClick={onClick}
height={50}
width={50}
className={`absolute ${position} top-1/2 cursor-pointer -translate-y-1/2 ${disabled ? "opacity-30" : ""}`}
/>
);
}