diff --git a/src/components/LightBox.tsx b/src/components/LightBox.tsx index f020f5f..4b798b8 100644 --- a/src/components/LightBox.tsx +++ b/src/components/LightBox.tsx @@ -1,10 +1,13 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; +import { Dispatch, SetStateAction, useCallback, useState } 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 { clamp } from "helpers/numbers"; +import { cIf, cJoin } from "helpers/className"; +import { useElementSize } from "hooks/useElementSize"; /* * ╭─────────────╮ @@ -12,6 +15,11 @@ import { Icon } from "components/Ico"; */ const SENSIBILITY_SWIPE = 0.5; +const TRANSLATION_PADDING = 100; +const SCALE_MAX = 5; +const SCALE_ON_DOUBLE_CLICK = 2; +const IMGWIDTH = 876; +const IMGHEIGHT = 1247; /* * ╭─────────────╮ @@ -56,6 +64,35 @@ export const LightBox = ({ }, }); + const [scale, setScale] = useState(1); + const [translation, setTranslation] = useState({ x: 0, y: 0 }); + const [isTranslating, setIsTranslating] = useState(false); + const [imgContainerRef, { width: containerWidth, height: containerHeight }] = + useElementSize(); + const [imgRef, { width: imgWidth, height: imgHeight }] = useElementSize(); + + const changeTranslation = useCallback( + (movementX: number, movementY: number) => { + const diffX = + Math.abs(containerWidth - IMGWIDTH * scale) - TRANSLATION_PADDING; + const diffY = + Math.abs(containerHeight - IMGHEIGHT * scale) + TRANSLATION_PADDING; + setTranslation((current) => ({ + x: clamp(current.x + movementX, -diffX / 2, diffX / 2), + y: clamp(current.y + movementY, -diffY / 2, diffY / 2), + })); + }, + [containerHeight, containerWidth, scale] + ); + + const changeScale = useCallback( + (deltaY: number) => + setScale((current) => + clamp(current * (deltaY > 0 ? 0.9 : 1.1), 1, SCALE_MAX) + ), + [] + ); + return ( <> {state && ( @@ -81,6 +118,28 @@ export const LightBox = ({ className={`grid h-full w-full grid-cols-[4em,1fr,4em] place-items-center overflow-hidden [grid-template-areas:"left_image_right"] first-letter:gap-4 mobile:grid-cols-2 mobile:[grid-template-areas:"image_image""left_right"]`} + ref={imgContainerRef} + onDragStart={(event) => event.preventDefault()} + onPointerDown={() => setIsTranslating(true)} + onPointerUp={() => setIsTranslating(false)} + onPointerMove={(event) => { + if (isTranslating) { + event.preventDefault(); + changeTranslation(event.movementX, event.movementY); + } + }} + onWheel={(event) => { + changeScale(event.deltaY); + changeTranslation(0, 0); + }} + onDoubleClick={() => { + if (scale === 1) { + setScale(SCALE_ON_DOUBLE_CLICK); + } else { + setScale(1); + setTranslation({ x: 0, y: 0 }); + } + }} >
{index > 0 && ( @@ -89,7 +148,16 @@ export const LightBox = ({
@@ -98,6 +166,24 @@ export const LightBox = ({