119 lines
3.9 KiB
TypeScript
119 lines
3.9 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
|
import { useSwipeable } from "react-swipeable";
|
|
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
import { Image } from "../../types/image";
|
|
import { isMobile } from "react-device-detect";
|
|
import Button from "../Button";
|
|
import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon";
|
|
import RightArrowSliderIcon from "../icons/RightArrowSliderIcon";
|
|
|
|
const images: Image[] = [
|
|
{ id: "1", src: "/images/aboutCompany/livingSolutionsSlider/1.png" },
|
|
{ id: "2", src: "/images/aboutCompany/livingSolutionsSlider/2.png" },
|
|
{ id: "3", src: "/images/aboutCompany/livingSolutionsSlider/3.png" },
|
|
{ id: "4", src: "/images/aboutCompany/livingSolutionsSlider/4.png" },
|
|
];
|
|
|
|
const getGapOffset = (screenWidth: number) => {
|
|
if (screenWidth > 1600) return 16;
|
|
if (screenWidth > 1280) return 24;
|
|
if (screenWidth > 640) return 16;
|
|
return 16;
|
|
};
|
|
|
|
const LivingSolutionSlider = () => {
|
|
const [selectedImageIndex, setSelectedImageIndex] = useState(-1);
|
|
const [rightImageOffset, setRightImageOffset] = useState("");
|
|
const [imageWidth, setImageWidth] = useState(0);
|
|
const imageRef = useRef<HTMLImageElement>(null);
|
|
|
|
const handlers = useSwipeable({
|
|
onSwipedLeft: next,
|
|
onSwipedRight: prev,
|
|
trackMouse: true,
|
|
});
|
|
|
|
function next() {
|
|
const lastIndex = isMobile ? images.length - 2 : images.length - 3;
|
|
|
|
if (selectedImageIndex === lastIndex) return;
|
|
setSelectedImageIndex((prev) => prev + 1);
|
|
}
|
|
|
|
function prev() {
|
|
if (selectedImageIndex === -1) return;
|
|
setSelectedImageIndex((prev) => prev - 1);
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (!imageRef.current) return;
|
|
const width = imageRef.current.width;
|
|
setImageWidth(width);
|
|
}, [imageRef.current?.width]);
|
|
|
|
useLayoutEffect(() => {
|
|
const screenWidth = window.innerWidth;
|
|
const gapOffset = getGapOffset(screenWidth);
|
|
|
|
const _rightImageOffset =
|
|
screenWidth > 1280
|
|
? `${"calc(clamp(315px, 7.0317rem + 19.0319vw, 485px)"} + ${
|
|
// ? `${"calc(clamp(315px, 6.9317rem + 17.0319vw, 420px)"} + ${
|
|
selectedImageIndex * (imageWidth + gapOffset)
|
|
}px)`
|
|
: `${(selectedImageIndex + 1) * (imageWidth + gapOffset)}px`;
|
|
|
|
setRightImageOffset(_rightImageOffset);
|
|
}, [imageWidth, selectedImageIndex, window.innerWidth]);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6 " {...handlers}>
|
|
<div
|
|
className="relative col-span-full overflow-x-hidden flex flex-col"
|
|
style={{ height: "clamp(30rem, 12.6318rem + 21.6933vw, 75rem)" }}
|
|
>
|
|
<div
|
|
className={`flex gap-4 w-full absolute h-full transition-all duration-300 ease-in-out select-none xl:px-0 px-4`}
|
|
style={{
|
|
right: `${rightImageOffset}`,
|
|
}}
|
|
>
|
|
{images.map((image) => (
|
|
<img
|
|
ref={imageRef}
|
|
src={image.src}
|
|
alt=""
|
|
key={image.id}
|
|
className="rounded-2xl sm:aspect-[6/5] object-cover 2xl:w-[calc(100vw*1/2)] xl:w-[calc(100vw*5/12)] pointer-events-none select-none w-[calc(100%-16px)]"
|
|
/>
|
|
))}
|
|
</div>
|
|
<Button
|
|
onClick={prev}
|
|
icon={<LeftArrowSliderIcon />}
|
|
className="absolute text-[#73787C] top-[calc(50%-22px)] xl:left-solution-slider-btn-offset left-6 hidden sm:block"
|
|
/>
|
|
<Button
|
|
onClick={next}
|
|
icon={<RightArrowSliderIcon />}
|
|
className="absolute text-[#73787C] top-[calc(50%-22px)] right-6 hidden sm:block"
|
|
/>
|
|
</div>
|
|
<div className="self-center gap-1 sm:hidden flex">
|
|
{images.map((image, index) => (
|
|
<div
|
|
key={image.id}
|
|
className={`transition-all duration-300 ease-in-out rounded-full h-2 ${
|
|
index - 1 === selectedImageIndex
|
|
? "w-6 bg-[#0D1922]"
|
|
: "w-2 bg-[#0D192266]"
|
|
}`}
|
|
></div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LivingSolutionSlider;
|