96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import { Dispatch, SetStateAction, useCallback } from "react";
|
|
import Hotkeys from "react-hot-keys";
|
|
import { useSwipeable } from "react-swipeable";
|
|
import { Img } from "./Img";
|
|
import { Button } from "./Inputs/Button";
|
|
import { Popup } from "./Popup";
|
|
import { Icon } from "components/Ico";
|
|
import { useIs3ColumnsLayout } from "hooks/useContainerQuery";
|
|
import { cIf, cJoin } from "helpers/className";
|
|
|
|
/*
|
|
* ╭─────────────╮
|
|
* ────────────────────────────────────────╯ CONSTANTS ╰──────────────────────────────────────────
|
|
*/
|
|
|
|
const SENSIBILITY_SWIPE = 0.5;
|
|
|
|
/*
|
|
* ╭─────────────╮
|
|
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
|
|
*/
|
|
|
|
interface Props {
|
|
setState: Dispatch<SetStateAction<boolean | undefined>> | Dispatch<SetStateAction<boolean>>;
|
|
state: boolean;
|
|
images: string[];
|
|
index: number;
|
|
setIndex: Dispatch<SetStateAction<number>>;
|
|
}
|
|
|
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
|
|
export const LightBox = ({ state, setState, images, index, setIndex }: Props): JSX.Element => {
|
|
const handlePrevious = useCallback(() => {
|
|
if (index > 0) setIndex(index - 1);
|
|
}, [index, setIndex]);
|
|
const is3ColumnsLayout = useIs3ColumnsLayout();
|
|
|
|
const handleNext = useCallback(() => {
|
|
if (index < images.length - 1) setIndex(index + 1);
|
|
}, [images.length, index, setIndex]);
|
|
|
|
const handlers = useSwipeable({
|
|
onSwipedLeft: (SwipeEventData) => {
|
|
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
|
|
handleNext();
|
|
},
|
|
onSwipedRight: (SwipeEventData) => {
|
|
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
|
|
handlePrevious();
|
|
},
|
|
});
|
|
|
|
return (
|
|
<>
|
|
{state && (
|
|
<Hotkeys
|
|
keyName="left,right"
|
|
allowRepeat
|
|
onKeyDown={(keyName) => {
|
|
if (keyName === "left") {
|
|
handlePrevious();
|
|
} else {
|
|
handleNext();
|
|
}
|
|
}}>
|
|
<Popup onClose={() => setState(false)} state={state} padding={false} fillViewport>
|
|
<div
|
|
{...handlers}
|
|
className={cJoin(
|
|
`grid h-full w-full place-items-center overflow-hidden first-letter:gap-4`,
|
|
cIf(
|
|
is3ColumnsLayout,
|
|
`grid-cols-[4em,1fr,4em] [grid-template-areas:"left_image_right"]`,
|
|
`grid-cols-2 [grid-template-areas:"image_image""left_right"]`
|
|
)
|
|
)}>
|
|
<div className="ml-4 [grid-area:left]">
|
|
{index > 0 && <Button onClick={handlePrevious} icon={Icon.ChevronLeft} />}
|
|
</div>
|
|
|
|
<Img className="max-h-full min-h-fit [grid-area:image]" src={images[index]} />
|
|
|
|
<div className="mr-4 [grid-area:right]">
|
|
{index < images.length - 1 && (
|
|
<Button onClick={handleNext} icon={Icon.ChevronRight} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Popup>
|
|
</Hotkeys>
|
|
)}
|
|
</>
|
|
);
|
|
};
|