File size: 2,225 Bytes
ec4551b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import { FC, ReactNode, useCallback, useState } from 'react';
import clsx from 'clsx';
import {
ChevronLeftIcon,
ChevronRightIcon,
} from '@gitroom/frontend/components/ui/icons';
export const SliderComponent: FC<{
className: string;
list: ReactNode[];
}> = ({ className, list }) => {
const [show, setShow] = useState(0);
const goToPrevious = useCallback(() => {
setShow((prev) => (prev > 0 ? prev - 1 : prev));
}, []);
const goToNext = useCallback(() => {
setShow((prev) => (prev < list.length - 1 ? prev + 1 : prev));
}, [list.length]);
const canGoPrevious = show > 0;
const canGoNext = show < list.length - 1;
return (
<div className={clsx(className, 'relative')}>
{list[show]}
{/* Left Arrow */}
{canGoPrevious && (
<button
onClick={goToPrevious}
className="absolute top-[50%] start-[10px] -translate-y-[50%] flex items-center justify-center w-8 h-8 rounded-full bg-black/60 hover:bg-black/80 text-white transition-colors backdrop-blur-sm cursor-pointer"
aria-label="Previous slide"
>
<ChevronLeftIcon size={18} />
</button>
)}
{/* Right Arrow */}
{canGoNext && (
<button
onClick={goToNext}
className="absolute top-[50%] end-[10px] -translate-y-[50%] flex items-center justify-center w-8 h-8 rounded-full bg-black/60 hover:bg-black/80 text-white transition-colors backdrop-blur-sm cursor-pointer"
aria-label="Next slide"
>
<ChevronRightIcon size={18} />
</button>
)}
{/* Pagination Dots */}
{list.length > 1 && (
<div className="absolute bottom-[10px] left-[50%] -translate-x-[50%] flex gap-2">
{list.map((_, index) => (
<button
key={index}
onClick={() => setShow(index)}
className={clsx(
'w-2 h-2 rounded-full transition-colors cursor-pointer',
index === show
? 'bg-white'
: 'bg-transparent border border-white'
)}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
)}
</div>
);
};
|