Browse Source

fix opening and closig of drawers and panels

imwald
Silberengel 3 months ago
parent
commit
21646d9b8a
  1. 47
      src/PageManager.tsx
  2. 33
      src/components/NoteDrawer/index.tsx

47
src/PageManager.tsx

@ -672,11 +672,11 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
setDrawerOpen(true) setDrawerOpen(true)
}, []) }, [])
const closeDrawer = () => { const closeDrawer = useCallback(() => {
if (!drawerOpen) return // Already closed
setDrawerOpen(false) setDrawerOpen(false)
// Clear noteId after animation completes (Sheet animation is 300ms) // Don't clear noteId here - let onOpenChange handle it when animation completes
setTimeout(() => setDrawerNoteId(null), 300) }, [drawerOpen])
}
const ignorePopStateRef = useRef(false) const ignorePopStateRef = useRef(false)
// Handle browser back button for primary note view // Handle browser back button for primary note view
@ -983,9 +983,10 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
closeDrawer() closeDrawer()
} }
// DO NOT update URL when closing panel - closing should NEVER affect the main page // DO NOT update URL when closing panel - closing should NEVER affect the main page
} else { } else if (newStack.length > 0) {
// Stack still has items - update drawer to show the top item's note (for mobile/single-pane) // Stack still has items - update drawer to show the top item's note (for mobile/single-pane)
if (isSmallScreen || panelMode === 'single') { // Only update drawer if drawer is currently open (not in the process of closing)
if ((isSmallScreen || panelMode === 'single') && drawerOpen && drawerNoteId) {
// Extract noteId from top item's URL or from state.url // Extract noteId from top item's URL or from state.url
const topItemUrl = newStack[newStack.length - 1]?.url || state?.url const topItemUrl = newStack[newStack.length - 1]?.url || state?.url
if (topItemUrl) { if (topItemUrl) {
@ -993,16 +994,20 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
topItemUrl.match(/\/notes\/(.+)$/) topItemUrl.match(/\/notes\/(.+)$/)
if (topNoteUrlMatch) { if (topNoteUrlMatch) {
const topNoteId = topNoteUrlMatch[topNoteUrlMatch.length - 1].split('?')[0].split('#')[0] const topNoteId = topNoteUrlMatch[topNoteUrlMatch.length - 1].split('?')[0].split('#')[0]
if (topNoteId) { if (topNoteId && topNoteId !== drawerNoteId) {
// Use setTimeout to ensure drawer update happens after stack state is committed // Use setTimeout to ensure drawer update happens after stack state is committed
setTimeout(() => { setTimeout(() => {
openDrawer(topNoteId) // Double-check drawer is still open before updating
if (drawerOpen) {
openDrawer(topNoteId)
}
}, 0) }, 0)
} }
} }
} }
} }
} }
// If newStack.length === 0, we're closing - don't reopen the drawer
return newStack return newStack
}) })
} }
@ -1220,14 +1225,16 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
// Single-pane mode or mobile: check if drawer is open and stack is empty - close drawer instead // Single-pane mode or mobile: check if drawer is open and stack is empty - close drawer instead
if (drawerOpen && secondaryStack.length === 0) { if (drawerOpen && secondaryStack.length === 0) {
// Close drawer and reveal the background page // Close drawer and reveal the background page
closeDrawer() setDrawerOpen(false)
setTimeout(() => setDrawerNoteId(null), 350)
return return
} }
// On mobile or single-pane: if stack has 1 item and drawer is open, close drawer and clear stack // On mobile or single-pane: if stack has 1 item and drawer is open, close drawer and clear stack
if ((isSmallScreen || panelMode === 'single') && secondaryStack.length === 1 && drawerOpen) { if ((isSmallScreen || panelMode === 'single') && secondaryStack.length === 1 && drawerOpen) {
// Close drawer (this will restore the URL to the correct primary page) // Close drawer (this will restore the URL to the correct primary page)
closeDrawer() setDrawerOpen(false)
setTimeout(() => setDrawerNoteId(null), 350)
// Clear stack // Clear stack
setSecondaryStack([]) setSecondaryStack([])
@ -1415,10 +1422,14 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
<NoteDrawer <NoteDrawer
open={drawerOpen} open={drawerOpen}
onOpenChange={(open) => { onOpenChange={(open) => {
setDrawerOpen(open)
// Only clear noteId when Sheet is fully closed (after animation completes)
// Use 350ms to ensure animation is fully done (animation is 300ms)
if (!open) { if (!open) {
closeDrawer() // Restore URL to current primary page
} else { const pageUrl = currentPrimaryPage === 'home' ? '/' : `/${currentPrimaryPage}`
setDrawerOpen(open) window.history.replaceState(null, '', pageUrl)
setTimeout(() => setDrawerNoteId(null), 350)
} }
}} }}
noteId={drawerNoteId} noteId={drawerNoteId}
@ -1522,10 +1533,14 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
<NoteDrawer <NoteDrawer
open={drawerOpen} open={drawerOpen}
onOpenChange={(open) => { onOpenChange={(open) => {
setDrawerOpen(open)
// Only clear noteId when Sheet is fully closed (after animation completes)
// Use 350ms to ensure animation is fully done (animation is 300ms)
if (!open) { if (!open) {
closeDrawer() // Restore URL to current primary page
} else { const pageUrl = currentPrimaryPage === 'home' ? '/' : `/${currentPrimaryPage}`
setDrawerOpen(open) window.history.replaceState(null, '', pageUrl)
setTimeout(() => setDrawerNoteId(null), 350)
} }
}} }}
noteId={drawerNoteId} noteId={drawerNoteId}

33
src/components/NoteDrawer/index.tsx

@ -1,3 +1,4 @@
import { useState, useEffect, useRef } from 'react'
import { Sheet, SheetContent } from '@/components/ui/sheet' import { Sheet, SheetContent } from '@/components/ui/sheet'
import NotePage from '@/pages/secondary/NotePage' import NotePage from '@/pages/secondary/NotePage'
@ -8,13 +9,41 @@ interface NoteDrawerProps {
} }
export default function NoteDrawer({ open, onOpenChange, noteId }: NoteDrawerProps) { export default function NoteDrawer({ open, onOpenChange, noteId }: NoteDrawerProps) {
if (!noteId) return null const [displayNoteId, setDisplayNoteId] = useState<string | null>(noteId)
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
useEffect(() => {
// Clear any pending timeout
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = null
}
if (noteId) {
// New noteId - show immediately
setDisplayNoteId(noteId)
} else if (!open && displayNoteId) {
// Closing - keep content visible during animation (350ms)
timeoutRef.current = setTimeout(() => {
setDisplayNoteId(null)
timeoutRef.current = null
}, 350)
}
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
}
}
}, [noteId, open])
if (!displayNoteId) return null
return ( return (
<Sheet open={open} onOpenChange={onOpenChange}> <Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent side="right" className="w-full sm:max-w-[1042px] overflow-y-auto p-0"> <SheetContent side="right" className="w-full sm:max-w-[1042px] overflow-y-auto p-0">
<div className="h-full"> <div className="h-full">
<NotePage id={noteId} index={0} hideTitlebar={false} /> <NotePage id={displayNoteId} index={0} hideTitlebar={false} />
</div> </div>
</SheetContent> </SheetContent>
</Sheet> </Sheet>

Loading…
Cancel
Save