From d77bee813d568c7e0eb546e359c18ddcce180f85 Mon Sep 17 00:00:00 2001 From: matty Date: Sat, 24 Jan 2026 17:05:14 +0000 Subject: [PATCH] restore mobile swipe navigation in modal --- packages/pl-fe/src/modals/media-modal.tsx | 43 +++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/pl-fe/src/modals/media-modal.tsx b/packages/pl-fe/src/modals/media-modal.tsx index 7ba851be9..9d7389b15 100644 --- a/packages/pl-fe/src/modals/media-modal.tsx +++ b/packages/pl-fe/src/modals/media-modal.tsx @@ -1,6 +1,6 @@ import { Link } from '@tanstack/react-router'; import clsx from 'clsx'; -import React, { type RefCallback, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { type RefCallback, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { fetchStatusWithContext } from 'pl-fe/actions/statuses'; @@ -119,6 +119,40 @@ const MediaModal: React.FC = (props) => { } }, [handleChangeIndex, index]); + // Touch swipe handling + const touchStartX = useRef(null); + const touchStartY = useRef(null); + const carouselRef = useRef(null); + + const handleTouchStart = useCallback((e: React.TouchEvent) => { + if (zoomedIn) return; + touchStartX.current = e.touches[0].clientX; + touchStartY.current = e.touches[0].clientY; + }, [zoomedIn]); + + const handleTouchEnd = useCallback((e: React.TouchEvent) => { + if (zoomedIn || touchStartX.current === null || touchStartY.current === null) return; + + const touchEndX = e.changedTouches[0].clientX; + const touchEndY = e.changedTouches[0].clientY; + const deltaX = touchEndX - touchStartX.current; + const deltaY = touchEndY - touchStartY.current; + + // Only trigger if horizontal swipe is greater than vertical (to avoid conflicts with scroll) + // and if the swipe distance is significant enough + const minSwipeDistance = 50; + if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > minSwipeDistance) { + if (deltaX > 0) { + handleChangeIndex(index - 1); // Swipe right = previous + } else { + handleChangeIndex(index + 1); // Swipe left = next + } + } + + touchStartX.current = null; + touchStartY.current = null; + }, [zoomedIn, handleChangeIndex, index]); + const handleDownload = () => { const mediaItem = hasMultipleImages ? media[index as number] : media[0]; window.open(mediaItem?.url); @@ -333,7 +367,12 @@ const MediaModal: React.FC = (props) => { )} -
+