80 lines
2.0 KiB
TypeScript
80 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useRef } from "react";
|
|
|
|
type CarouselProps = {
|
|
children: React.ReactNode;
|
|
ariaLabel: string;
|
|
};
|
|
|
|
function ChevronLeftIcon() {
|
|
return (
|
|
<svg viewBox="0 0 24 24" fill="none" className="h-5 w-5" aria-hidden>
|
|
<path
|
|
d="M14.5 6.5 9 12l5.5 5.5"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ChevronRightIcon() {
|
|
return (
|
|
<svg viewBox="0 0 24 24" fill="none" className="h-5 w-5" aria-hidden>
|
|
<path
|
|
d="M9.5 6.5 15 12l-5.5 5.5"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
export function Carousel({ children, ariaLabel }: CarouselProps) {
|
|
const trackRef = useRef<HTMLDivElement>(null);
|
|
|
|
const scroll = (direction: "prev" | "next") => {
|
|
const track = trackRef.current;
|
|
if (!track) return;
|
|
const amount = direction === "next" ? -280 : 280;
|
|
track.scrollBy({ left: amount, behavior: "smooth" });
|
|
};
|
|
|
|
const btnClass =
|
|
"absolute top-1/2 z-10 flex h-10 w-10 -translate-y-1/2 items-center justify-center rounded-full border border-white/40 bg-white/40 text-red shadow-sm backdrop-blur-md transition-colors hover:border-red/40 hover:bg-white/60 hover:text-red-dark";
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
type="button"
|
|
onClick={() => scroll("prev")}
|
|
aria-label="قبلی"
|
|
className={`${btnClass} right-1`}
|
|
>
|
|
<ChevronRightIcon />
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => scroll("next")}
|
|
aria-label="بعدی"
|
|
className={`${btnClass} left-1`}
|
|
>
|
|
<ChevronLeftIcon />
|
|
</button>
|
|
<div
|
|
ref={trackRef}
|
|
role="region"
|
|
aria-label={ariaLabel}
|
|
className="carousel-track flex items-stretch gap-4 overflow-x-auto scroll-smooth px-1 py-2"
|
|
>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|