| @@ -448,7 +448,7 @@ function FlipBook({ pages, onClose }: { pages: string[]; onClose: () => void }) | |||
| const [spread, setSpread] = useState(0); | |||
| const [flipping, setFlipping] = useState<'forward' | 'backward' | null>(null); | |||
| const audioRef = useRef<AudioContext | null>(null); | |||
| const touchStartX = useRef<number | null>(null); | |||
| const dragStartX = useRef<number | null>(null); | |||
| const getCtx = () => { | |||
| if (!audioRef.current) { | |||
| @@ -493,13 +493,14 @@ function FlipBook({ pages, onClose }: { pages: string[]; onClose: () => void }) | |||
| return () => window.removeEventListener('keydown', onKey); | |||
| }, [onClose, goNext, goPrev]); | |||
| const onTouchStart = (e: React.TouchEvent) => { touchStartX.current = e.touches[0].clientX; }; | |||
| const onTouchEnd = (e: React.TouchEvent) => { | |||
| if (touchStartX.current === null) return; | |||
| const dx = e.changedTouches[0].clientX - touchStartX.current; | |||
| const onPointerDown = (e: React.PointerEvent) => { dragStartX.current = e.clientX; }; | |||
| const onPointerUp = (e: React.PointerEvent) => { | |||
| if (dragStartX.current === null) return; | |||
| const dx = e.clientX - dragStartX.current; | |||
| if (Math.abs(dx) > 50) (dx < 0 ? goNext() : goPrev()); | |||
| touchStartX.current = null; | |||
| dragStartX.current = null; | |||
| }; | |||
| const onPointerCancel = () => { dragStartX.current = null; }; | |||
| // Pages visible underneath the flipping overlay | |||
| const visibleLeft = flipping === 'backward' ? getPage(prevLeftIdx) : getPage(leftIdx); | |||
| @@ -516,10 +517,11 @@ function FlipBook({ pages, onClose }: { pages: string[]; onClose: () => void }) | |||
| return ( | |||
| <div | |||
| className="fixed inset-0 z-50 flex items-center justify-center bg-black/95" | |||
| onTouchStart={onTouchStart} | |||
| onTouchEnd={onTouchEnd} | |||
| style={{ perspective: '2500px' }} | |||
| className="fixed inset-0 z-50 flex items-center justify-center bg-black/95 select-none" | |||
| onPointerDown={onPointerDown} | |||
| onPointerUp={onPointerUp} | |||
| onPointerCancel={onPointerCancel} | |||
| style={{ perspective: '2500px', touchAction: 'pan-y' }} | |||
| > | |||
| <style dangerouslySetInnerHTML={{ __html: ` | |||
| @keyframes flipBookForward { from { transform: rotateY(0deg); } to { transform: rotateY(-180deg); } } | |||
| @@ -542,13 +544,35 @@ function FlipBook({ pages, onClose }: { pages: string[]; onClose: () => void }) | |||
| }} | |||
| > | |||
| {/* Static left page */} | |||
| <div className="absolute left-0 top-0 w-1/2 h-full bg-white overflow-hidden"> | |||
| {visibleLeft && <img src={visibleLeft} className={pageImgClass} alt="" draggable={false} />} | |||
| </div> | |||
| {visibleLeft ? ( | |||
| <div className="absolute left-0 top-0 w-1/2 h-full bg-white overflow-hidden"> | |||
| <img src={visibleLeft} className={pageImgClass} alt="" draggable={false} /> | |||
| </div> | |||
| ) : ( | |||
| <div | |||
| className="absolute left-0 top-0 w-1/2 h-full overflow-hidden" | |||
| style={{ | |||
| background: 'linear-gradient(135deg, #4a3826 0%, #2e2114 55%, #1a1108 100%)', | |||
| boxShadow: 'inset 0 0 80px rgba(0,0,0,0.55)', | |||
| }} | |||
| aria-hidden | |||
| /> | |||
| )} | |||
| {/* Static right page */} | |||
| <div className="absolute right-0 top-0 w-1/2 h-full bg-white overflow-hidden"> | |||
| {visibleRight && <img src={visibleRight} className={pageImgClass} alt="" draggable={false} />} | |||
| </div> | |||
| {visibleRight ? ( | |||
| <div className="absolute right-0 top-0 w-1/2 h-full bg-white overflow-hidden"> | |||
| <img src={visibleRight} className={pageImgClass} alt="" draggable={false} /> | |||
| </div> | |||
| ) : ( | |||
| <div | |||
| className="absolute right-0 top-0 w-1/2 h-full overflow-hidden" | |||
| style={{ | |||
| background: 'linear-gradient(225deg, #4a3826 0%, #2e2114 55%, #1a1108 100%)', | |||
| boxShadow: 'inset 0 0 80px rgba(0,0,0,0.55)', | |||
| }} | |||
| aria-hidden | |||
| /> | |||
| )} | |||
| {/* Spine */} | |||
| <div className="absolute left-1/2 top-0 -translate-x-1/2 w-2 h-full bg-gradient-to-r from-black/40 via-black/20 to-black/40 z-10 pointer-events-none" /> | |||