Browse Source

bug-fixes

imwald
Silberengel 4 weeks ago
parent
commit
fa8c6e052c
  1. 21
      src/PageManager.tsx
  2. 78
      src/components/ImageWithLightbox/index.tsx
  3. 14
      src/components/NoteDrawer/index.tsx
  4. 23
      src/services/modal-manager.service.ts

21
src/PageManager.tsx

@ -1435,16 +1435,37 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { @@ -1435,16 +1435,37 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
const onPopState = (e: PopStateEvent) => {
if (ignorePopStateRef.current) {
logger.info('[LightboxTrace][PageManager] popstate ignored', {
reason: 'ignorePopStateRef',
pathname: window.location.pathname,
state: e.state
})
ignorePopStateRef.current = false
return
}
logger.info('[LightboxTrace][PageManager] popstate received', {
pathname: window.location.pathname,
state: e.state,
secondaryStackLength: secondaryStackRef.current.length,
drawerOpen,
drawerNoteId,
panelMode,
isSmallScreen
})
// If the side panel has frames, this popstate is almost certainly stack navigation — do not let
// modalManager steal it (history.forward + return), which leaves the URL changed and the panel stale.
if (secondaryStackRef.current.length === 0) {
const closeModal = modalManager.pop()
logger.info('[LightboxTrace][PageManager] modalManager.pop result', {
closeModal,
pathname: window.location.pathname,
state: e.state
})
if (closeModal) {
ignorePopStateRef.current = true
logger.info('[LightboxTrace][PageManager] modal popped, forcing history.forward')
window.history.forward()
return
}

78
src/components/ImageWithLightbox/index.tsx

@ -1,9 +1,10 @@ @@ -1,9 +1,10 @@
import { randomString } from '@/lib/random'
import { cn } from '@/lib/utils'
import logger from '@/lib/logger'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import modalManager from '@/services/modal-manager.service'
import { TImetaInfo } from '@/types'
import { useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom'
import { useTranslation } from 'react-i18next'
import Lightbox from 'yet-another-react-lightbox'
@ -28,15 +29,59 @@ export default function ImageWithLightbox({ @@ -28,15 +29,59 @@ export default function ImageWithLightbox({
const { autoLoadMedia } = useContentPolicy()
const [display, setDisplay] = useState(autoLoadMedia)
const [index, setIndex] = useState(-1)
const logLightboxEvent = useCallback((stage: string, details?: Record<string, unknown>) => {
logger.info('[LightboxTrace]', {
stage,
id,
imageUrl: image.url,
index,
pathname: window.location.pathname,
search: window.location.search,
hash: window.location.hash,
...details
})
}, [id, image.url, index])
useEffect(() => {
if (index >= 0) {
logLightboxEvent('modal-register')
modalManager.register(id, () => {
logLightboxEvent('modal-callback-close')
setIndex(-1)
})
} else {
logLightboxEvent('modal-unregister')
modalManager.unregister(id)
}
}, [index])
}, [id, index, logLightboxEvent])
useEffect(() => {
if (index < 0) return
const onCaptureKeydown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
logLightboxEvent('escape-keydown-capture', {
defaultPrevented: event.defaultPrevented,
eventPhase: event.eventPhase
})
}
}
const onPopState = (event: PopStateEvent) => {
logLightboxEvent('window-popstate-while-open', {
hasState: !!event.state,
state: event.state
})
}
window.addEventListener('keydown', onCaptureKeydown, true)
window.addEventListener('popstate', onPopState)
return () => {
window.removeEventListener('keydown', onCaptureKeydown, true)
window.removeEventListener('popstate', onPopState)
}
}, [index, logLightboxEvent])
if (!display) {
return (
@ -53,8 +98,12 @@ export default function ImageWithLightbox({ @@ -53,8 +98,12 @@ export default function ImageWithLightbox({
}
const handlePhotoClick = (event: React.MouseEvent) => {
logLightboxEvent('thumbnail-click', {
defaultPreventedBefore: event.defaultPrevented
})
event.stopPropagation()
event.preventDefault()
logLightboxEvent('set-open-index')
setIndex(0)
}
@ -74,10 +123,22 @@ export default function ImageWithLightbox({ @@ -74,10 +123,22 @@ export default function ImageWithLightbox({
createPortal(
<div
data-lightbox-overlay
onClick={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onTouchStart={(e) => e.stopPropagation()}
onClick={(e) => {
logLightboxEvent('overlay-click', { target: (e.target as HTMLElement)?.tagName })
e.stopPropagation()
}}
onPointerDown={(e) => {
logLightboxEvent('overlay-pointerdown', { target: (e.target as HTMLElement)?.tagName })
e.stopPropagation()
}}
onMouseDown={(e) => {
logLightboxEvent('overlay-mousedown', { target: (e.target as HTMLElement)?.tagName })
e.stopPropagation()
}}
onTouchStart={(e) => {
logLightboxEvent('overlay-touchstart', { target: (e.target as HTMLElement)?.tagName })
e.stopPropagation()
}}
>
<Lightbox
index={index}
@ -88,7 +149,10 @@ export default function ImageWithLightbox({ @@ -88,7 +149,10 @@ export default function ImageWithLightbox({
}]}
plugins={[Zoom, Captions]}
open={index >= 0}
close={() => setIndex(-1)}
close={() => {
logLightboxEvent('lightbox-close-callback')
setIndex(-1)
}}
controller={{
closeOnBackdropClick: false,
closeOnPullUp: true,

14
src/components/NoteDrawer/index.tsx

@ -3,6 +3,7 @@ import { Sheet, SheetContent } from '@/components/ui/sheet' @@ -3,6 +3,7 @@ import { Sheet, SheetContent } from '@/components/ui/sheet'
import NotePage from '@/pages/secondary/NotePage'
import { useSecondaryPage } from '@/PageManager'
import type { Event } from 'nostr-tools'
import logger from '@/lib/logger'
interface NoteDrawerProps {
open: boolean
@ -44,7 +45,18 @@ export default function NoteDrawer({ open, onOpenChange, noteId, initialEvent }: @@ -44,7 +45,18 @@ export default function NoteDrawer({ open, onOpenChange, noteId, initialEvent }:
if (!displayNoteId) return null
return (
<Sheet open={open} onOpenChange={onOpenChange} registerWithModalManager={false}>
<Sheet
open={open}
onOpenChange={(nextOpen) => {
logger.info('[LightboxTrace][NoteDrawer] onOpenChange', {
currentOpen: open,
nextOpen,
noteId: displayNoteId
})
onOpenChange(nextOpen)
}}
registerWithModalManager={false}
>
<SheetContent side="right" className="w-full sm:max-w-[1042px] overflow-y-auto p-0">
<div className="min-h-full">
<NotePage

23
src/services/modal-manager.service.ts

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
import logger from '@/lib/logger'
class ModalManagerService {
static instance: ModalManagerService
@ -15,9 +17,17 @@ class ModalManagerService { @@ -15,9 +17,17 @@ class ModalManagerService {
if (modal) {
// already registered, update callback
modal.cb = cb
logger.info('[LightboxTrace][ModalManager] updated modal callback', {
id,
modalCount: this.modals.length
})
return
}
this.modals.push({ id, cb })
logger.info('[LightboxTrace][ModalManager] register', {
id,
modalCount: this.modals.length
})
}
unregister(id: string) {
@ -26,13 +36,24 @@ class ModalManagerService { @@ -26,13 +36,24 @@ class ModalManagerService {
modal.cb()
this.modals = this.modals.filter((m) => m.id !== id)
logger.info('[LightboxTrace][ModalManager] unregister', {
id,
modalCount: this.modals.length
})
}
pop() {
const modal = this.modals.pop()
if (!modal) return false
if (!modal) {
logger.info('[LightboxTrace][ModalManager] pop noop', { modalCount: this.modals.length })
return false
}
modal.cb()
logger.info('[LightboxTrace][ModalManager] pop close', {
id: modal.id,
modalCount: this.modals.length
})
return true
}
}

Loading…
Cancel
Save