From 63f557c5663655f3648f1230e6d5961699f8d88a Mon Sep 17 00:00:00 2001 From: Silberengel Date: Sun, 24 May 2026 11:40:36 +0200 Subject: [PATCH] bug-fix swishing to close second panel --- src/PageManager.tsx | 54 +++++------------------ src/layouts/SecondaryPageLayout/index.tsx | 12 +---- 2 files changed, 12 insertions(+), 54 deletions(-) diff --git a/src/PageManager.tsx b/src/PageManager.tsx index 3af61752..e598134a 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -7,11 +7,7 @@ import { RefreshButton } from '@/components/RefreshButton' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' import logger from '@/lib/logger' -import { - MOBILE_SWIPE_BACK_EDGE_PX, - tryMobileSwipeBackFromGesture, - useMobileSwipeBackOnElement -} from '@/lib/mobile-swipe-back' +import { useMobileSwipeBackOnElement } from '@/lib/mobile-swipe-back' import { preventRadixSheetCloseForPortaledOverlay } from '@/lib/sheet-dismiss-guard' import { ChevronLeft } from 'lucide-react' import { NavigationService } from '@/services/navigation.service' @@ -2132,6 +2128,9 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { restorePrimaryTabAfterSecondaryClose() } + let lastPopSecondaryPageAt = 0 + const POP_SECONDARY_PAGE_DEBOUNCE_MS = 400 + /** Pop one secondary frame in React state before history.back (popstate can no-op when indices match). */ const popOneSecondaryStackFrame = () => { const pre = secondaryStackRef.current @@ -2153,6 +2152,10 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { /** UI-first back: sync stack / drawer immediately, then align browser history. */ const popSecondaryPage = () => { + const now = Date.now() + if (now - lastPopSecondaryPageAt < POP_SECONDARY_PAGE_DEBOUNCE_MS) return + lastPopSecondaryPageAt = now + navigationCounterRef.current += 1 if (primaryNoteView) { setPrimaryNoteView(null) @@ -2168,12 +2171,9 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { ignorePopStateRef.current = true window.history.back() } else { + // replaceState in hardClose already points at the primary URL — do not history.back() + // afterward or the browser returns to the note entry and popstate/sync reopens the panel. hardCloseSecondaryPanel() - const pathOnly = window.location.pathname.split('?')[0].split('#')[0] - if (!isPrimaryOnlyPathname(pathOnly)) { - ignorePopStateRef.current = true - window.history.back() - } } return } @@ -2230,40 +2230,6 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { enabled: mobileSecondaryPanelOpen }) - const mobileSecondaryOpen = isSmallScreen && (drawerOpen || secondaryStack.length > 0) - useEffect(() => { - if (!mobileSecondaryOpen) return - - let grab: { x: number; y: number; pointerId: number } | null = null - - const onPointerDown = (e: PointerEvent) => { - if ((e.button !== 0 && e.button !== -1) || e.clientX > MOBILE_SWIPE_BACK_EDGE_PX) return - grab = { x: e.clientX, y: e.clientY, pointerId: e.pointerId } - } - - const onPointerUp = (e: PointerEvent) => { - if (!grab || grab.pointerId !== e.pointerId) return - tryMobileSwipeBackFromGesture(grab, e.clientX, e.clientY, e.pointerId, () => - popSecondaryPageRef.current() - ) - grab = null - } - - const onPointerCancel = () => { - grab = null - } - - const capture = { capture: true } as const - document.addEventListener('pointerdown', onPointerDown, capture) - document.addEventListener('pointerup', onPointerUp, capture) - document.addEventListener('pointercancel', onPointerCancel, capture) - return () => { - document.removeEventListener('pointerdown', onPointerDown, capture) - document.removeEventListener('pointerup', onPointerUp, capture) - document.removeEventListener('pointercancel', onPointerCancel, capture) - } - }, [mobileSecondaryOpen]) - useEffect(() => { const shouldBeOpen = panelMode === 'single' && diff --git a/src/layouts/SecondaryPageLayout/index.tsx b/src/layouts/SecondaryPageLayout/index.tsx index ec446258..f1cd4ea1 100644 --- a/src/layouts/SecondaryPageLayout/index.tsx +++ b/src/layouts/SecondaryPageLayout/index.tsx @@ -8,13 +8,12 @@ import { isRadixDialogOpen, shouldIgnoreKeyboardShortcutEvent } from '@/lib/keyboard-shortcuts' -import { useMobileSwipeBackOnElement } from '@/lib/mobile-swipe-back' import { useSecondaryPage } from '@/PageManager' import { DeepBrowsingProvider } from '@/providers/DeepBrowsingProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider' import { cn } from '@/lib/utils' import { ChevronLeft } from 'lucide-react' -import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react' +import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' import { useTranslation } from 'react-i18next' const SecondaryPageLayout = forwardRef( @@ -42,13 +41,7 @@ const SecondaryPageLayout = forwardRef( ) => { const scrollAreaRef = useRef(null) const { isSmallScreen } = useScreenSize() - const { currentIndex, pop } = useSecondaryPage() - const [mobileSwipeRoot, setMobileSwipeRoot] = useState(null) - const mobileSwipeActive = - isSmallScreen && (index === undefined || currentIndex === index) - useMobileSwipeBackOnElement(mobileSwipeActive ? mobileSwipeRoot : null, pop, { - enabled: mobileSwipeActive - }) + const { currentIndex } = useSecondaryPage() const shouldRenderTitlebar = titlebar != null || (title != null && title !== '') || !hideBackButton @@ -97,7 +90,6 @@ const SecondaryPageLayout = forwardRef( return (