82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { useState } from "react";
|
|
import Button from "./ui/Button";
|
|
import ChevronLeftIcon from "./icons/ChevronLeftIcon";
|
|
import ChevronRightIcon from "./icons/ChevronRightIcon";
|
|
import { projects } from "../data/projects";
|
|
import { motion } from "motion/react";
|
|
import { useSwipeable } from "react-swipeable";
|
|
|
|
export interface InteriorSliderProps {
|
|
unitTypeSlug: string;
|
|
projectSlug: string;
|
|
}
|
|
|
|
function InteriorSlider({ unitTypeSlug, projectSlug }: InteriorSliderProps) {
|
|
const images = projects
|
|
?.find((project) => project.slug === projectSlug)
|
|
?.types.find((type) => type.slug === unitTypeSlug)?.interiors;
|
|
|
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
|
|
const handlers = useSwipeable({
|
|
onSwipedLeft: () =>
|
|
images && setCurrentIndex(Math.min(currentIndex + 1, images.length - 1)),
|
|
onSwipedRight: () => setCurrentIndex(Math.max(currentIndex - 1, 0)),
|
|
preventScrollOnSwipe: true,
|
|
touchEventOptions: {
|
|
passive: false,
|
|
},
|
|
trackMouse: true,
|
|
});
|
|
|
|
if (!images) return null;
|
|
|
|
return (
|
|
<div className="group overflow-hidden relative h-full" {...handlers}>
|
|
<motion.div
|
|
className="flex h-full"
|
|
animate={{ x: `calc(-${currentIndex} * 100%)` }}
|
|
transition={{
|
|
duration: 0.5,
|
|
ease: "easeInOut",
|
|
}}
|
|
>
|
|
{images?.map((src, index) => (
|
|
<img
|
|
key={index}
|
|
src={src}
|
|
alt=""
|
|
className="size-full object-cover object-left flex-shrink-0 pointer-events-none"
|
|
/>
|
|
))}
|
|
</motion.div>
|
|
<Button
|
|
className="absolute 2xl:left-[2.778vw] left-10 top-1/2 -translate-y-1/2 max-md:hidden group-hover:opacity-100 opacity-0 transition-opacity duration-300"
|
|
disabled={currentIndex === 0}
|
|
variant="secondary"
|
|
onlyIcon
|
|
onClick={() => setCurrentIndex(Math.max(currentIndex - 1, 0))}
|
|
>
|
|
<div className="2xl:size-[1.389vw] size-5">
|
|
<ChevronLeftIcon />
|
|
</div>
|
|
</Button>
|
|
<Button
|
|
className="absolute 2xl:right-[2.778vw] right-10 top-1/2 -translate-y-1/2 max-md:hidden group-hover:opacity-100 2xl:opacity-0 transition-opacity duration-300"
|
|
disabled={currentIndex === images.length - 1}
|
|
variant="secondary"
|
|
onlyIcon
|
|
onClick={() =>
|
|
setCurrentIndex(Math.min(currentIndex + 1, images.length - 1))
|
|
}
|
|
>
|
|
<div className="2xl:size-[1.389vw] size-5">
|
|
<ChevronRightIcon />
|
|
</div>
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default InteriorSlider;
|