117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import { useState, useRef, useEffect } from "react";
|
|
import { ILayoutCard } from "../../types/layoutCard";
|
|
import FavoriteSliderCard from "./FavoriteSliderCard";
|
|
import Button from "../Button";
|
|
import RightArrowIcon from "../icons/RightArrowIcon";
|
|
import LeftArrowIcon from "../icons/LeftArrowIcon";
|
|
import { useSwipeable } from "react-swipeable";
|
|
|
|
interface FavoritesSliderProps {
|
|
cards: ILayoutCard[];
|
|
}
|
|
|
|
const FavoritesSlider = ({ cards }: FavoritesSliderProps) => {
|
|
const [offset, setOffset] = useState(0);
|
|
const cardRef = useRef<HTMLDivElement | null>(null);
|
|
const [cardWidth, setCardWidth] = useState(0);
|
|
const [buttonTopPos, setButtonTopPos] = useState(0);
|
|
const [cols, setCols] = useState(2);
|
|
|
|
const handlers = useSwipeable({
|
|
trackMouse: true,
|
|
onSwipedRight: () => handleOnLeftBtnClick(),
|
|
onSwipedLeft: () => handleOnRightBtnClick(),
|
|
});
|
|
|
|
const handleOnLeftBtnClick = () => {
|
|
if (0 > offset) {
|
|
setOffset((prev) => prev + 1);
|
|
}
|
|
};
|
|
|
|
const handleOnRightBtnClick = () => {
|
|
if (offset > -cards.length + cols + 1) {
|
|
setOffset((prev) => prev - 1);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const screenWidth = window.innerWidth;
|
|
if (screenWidth >= 1024) {
|
|
setCols(4);
|
|
} else {
|
|
setCols(2);
|
|
}
|
|
}, [window.innerWidth]);
|
|
|
|
useEffect(() => {
|
|
const cardElement = cardRef.current;
|
|
if (cardElement) {
|
|
const gap = 16;
|
|
const width = cardElement.clientWidth + gap;
|
|
const buttonHeight = cardElement.clientHeight;
|
|
const _buttonTopPos = buttonHeight / 2 + 20;
|
|
setCardWidth(width);
|
|
setButtonTopPos(_buttonTopPos);
|
|
}
|
|
}, [cardRef.current]);
|
|
|
|
return (
|
|
<div className="w-[calc(100vw - 48px)] relative ">
|
|
<div
|
|
className="absolute -left-2 z-30"
|
|
style={{ top: `${buttonTopPos}px` }}
|
|
>
|
|
<Button
|
|
buttonType="primary"
|
|
isCircleRounded
|
|
icon={<LeftArrowIcon />}
|
|
onClick={handleOnLeftBtnClick}
|
|
/>
|
|
</div>
|
|
<div
|
|
className="absolute -right-2 z-30"
|
|
style={{ top: `${buttonTopPos}px` }}
|
|
>
|
|
<Button
|
|
buttonType="primary"
|
|
isCircleRounded
|
|
icon={<RightArrowIcon />}
|
|
onClick={handleOnRightBtnClick}
|
|
/>
|
|
</div>
|
|
<div className="w-full overflow-hidden" {...handlers}>
|
|
<div
|
|
className="transition-all ease-in-out duration-300"
|
|
style={{ transform: `translateX(${offset * cardWidth}px)` }}
|
|
>
|
|
<div className="flex w-fit gap-4">
|
|
{Array.from({ length: Math.floor(cards.length / cols) }).map(
|
|
(_, index) => {
|
|
return (
|
|
<div
|
|
className="grid lg:grid-cols-4 grid-cols-2 gap-4 w-[calc(100vw-48px)] h-fit"
|
|
key={index}
|
|
>
|
|
{cards
|
|
.slice(index * cols, cols + index * cols)
|
|
.map((card) => (
|
|
<FavoriteSliderCard
|
|
elementRef={cardRef}
|
|
card={card}
|
|
key={card.id}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FavoritesSlider;
|