From 5ff909949b17fccd6950a22f2633a99b17d63e4d Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 8 Apr 2026 14:19:58 +0200 Subject: [PATCH] bug-fixes --- src/PageManager.tsx | 25 +----- src/components/ImageGallery/index.tsx | 8 +- src/components/ImageWithLightbox/index.tsx | 77 ++----------------- .../Note/AsciidocArticle/AsciidocArticle.tsx | 8 +- src/components/NoteDrawer/index.tsx | 23 +++--- src/index.css | 6 ++ src/services/client.service.ts | 41 +--------- src/services/modal-manager.service.ts | 24 +----- 8 files changed, 49 insertions(+), 163 deletions(-) diff --git a/src/PageManager.tsx b/src/PageManager.tsx index 8b81042f..47e29b55 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -1,3 +1,7 @@ +// This file exports both React components and hooks alongside inline JSX in callbacks, +// making it incompatible with Vite's Fast Refresh auto-detection. Opting into explicit +// full-reload mode to suppress the "incompatible export" HMR warning. +// @refresh reset import { RefreshButton } from '@/components/RefreshButton' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' @@ -1435,37 +1439,16 @@ 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 } diff --git a/src/components/ImageGallery/index.tsx b/src/components/ImageGallery/index.tsx index a2f43c4f..f15a0b3a 100644 --- a/src/components/ImageGallery/index.tsx +++ b/src/components/ImageGallery/index.tsx @@ -108,7 +108,13 @@ export default function ImageGallery({
{imageContent} {createPortal( -
e.stopPropagation()}> +
e.stopPropagation()} + onPointerDown={(e) => e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + > { diff --git a/src/components/ImageWithLightbox/index.tsx b/src/components/ImageWithLightbox/index.tsx index 6e9092aa..e07eadb2 100644 --- a/src/components/ImageWithLightbox/index.tsx +++ b/src/components/ImageWithLightbox/index.tsx @@ -1,10 +1,9 @@ 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 { useCallback, useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { createPortal } from 'react-dom' import { preferBlossomPrimalDisplayUrl } from '@/lib/url' import { useTranslation } from 'react-i18next' @@ -38,66 +37,19 @@ export default function ImageWithLightbox({ } }, [autoLoadMedia]) - const logLightboxEvent = useCallback((stage: string, details?: Record) => { - 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) } - }, [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]) + }, [id, index]) const handlePhotoClick = (event: React.MouseEvent) => { - logLightboxEvent('thumbnail-click', { - defaultPreventedBefore: event.defaultPrevented - }) event.stopPropagation() event.preventDefault() - logLightboxEvent('set-open-index') setIndex(0) } @@ -132,22 +84,10 @@ export default function ImageWithLightbox({ {createPortal(
{ - 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() - }} + onClick={(e) => e.stopPropagation()} + onPointerDown={(e) => e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} > = 0} - close={() => { - logLightboxEvent('lightbox-close-callback') - setIndex(-1) - }} + close={() => setIndex(-1)} controller={{ closeOnBackdropClick: false, closeOnPullUp: true, diff --git a/src/components/Note/AsciidocArticle/AsciidocArticle.tsx b/src/components/Note/AsciidocArticle/AsciidocArticle.tsx index 25fa6a85..bb36ea1e 100644 --- a/src/components/Note/AsciidocArticle/AsciidocArticle.tsx +++ b/src/components/Note/AsciidocArticle/AsciidocArticle.tsx @@ -2122,7 +2122,13 @@ export default function AsciidocArticle({ {/* Image gallery lightbox */} {allImages.length > 0 && createPortal( -
e.stopPropagation()}> +
e.stopPropagation()} + onPointerDown={(e) => e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + > ({ diff --git a/src/components/NoteDrawer/index.tsx b/src/components/NoteDrawer/index.tsx index f633f35f..56a93d1c 100644 --- a/src/components/NoteDrawer/index.tsx +++ b/src/components/NoteDrawer/index.tsx @@ -3,7 +3,6 @@ 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 @@ -47,20 +46,26 @@ export default function NoteDrawer({ open, onOpenChange, noteId, initialEvent }: return ( { - logger.info('[LightboxTrace][NoteDrawer] onOpenChange', { - currentOpen: open, - nextOpen, - noteId: displayNoteId - }) - onOpenChange(nextOpen) - }} + onOpenChange={onOpenChange} registerWithModalManager={false} > { + // Prevent the drawer from closing when the user interacts with a lightbox portal. + // The lightbox renders into document.body (outside the Sheet DOM) so Radix UI + // would otherwise treat every click inside the lightbox as "outside" the drawer. + if (document.body.classList.contains('yarl__no_scroll')) { + e.preventDefault() + } + }} + onInteractOutside={(e) => { + if (document.body.classList.contains('yarl__no_scroll')) { + e.preventDefault() + } + }} >
{ const n = normalizeUrl(url) || url - // ── DIAGNOSTIC: catch any local-network WS attempt so we can trace its origin ── - if (isLocalNetworkUrl(n)) { - logger.warn('[DIAG] pool.ensureRelay called with LOCAL-NETWORK WS URL', { - url, - normalizedUrl: n, - stack: new Error('stack').stack?.split('\n').slice(1, 8).join(' | ') - }) - } const base = params?.connectionTimeout ?? RELAY_POOL_CONNECTION_TIMEOUT_MS const connectionTimeout = READ_ONLY_RELAY_CONNECT_BOOST_URLS.has(n) ? Math.max(base, RELAY_READ_ONLY_POOL_CONNECT_TIMEOUT_MS) @@ -1033,14 +1025,6 @@ class ClientService extends EventTarget { private recordSessionRelayFailure(url: string) { const n = normalizeAnyRelayUrl(url) || url if (!n) return - // ── DIAGNOSTIC: trace who is recording failures for local-network relays ── - if (isLocalNetworkUrl(n)) { - logger.warn('[DIAG] recordSessionRelayFailure for LOCAL-NETWORK relay', { - url, - normalizedUrl: n, - stack: new Error('stack').stack?.split('\n').slice(1, 8).join(' | ') - }) - } const prev = this.publishStrikeCount.get(n) ?? 0 if (prev >= ClientService.SESSION_RELAY_FAILURE_STRIKE_THRESHOLD) { return @@ -1811,9 +1795,9 @@ class ClientService extends EventTarget { eventIdSet.add(evt.id) events.push(evt) }) - events = events - .sort((a, b) => b.created_at - a.created_at) - .slice(0, mergedTimelineLimit) + events = needSort + ? events.sort((a, b) => b.created_at - a.created_at).slice(0, mergedTimelineLimit) + : events.slice(0, mergedTimelineLimit) eventIdSet = new Set(events.map((evt) => evt.id)) scheduleOuterFlush(!!_eosed) @@ -1943,15 +1927,6 @@ class ClientService extends EventTarget { relayReqLog?: { groupId?: string; onBatchEnd?: (rows: RelayOpTerminalRow[]) => void } ) { const originalDedupedRelays = Array.from(new Set(urls)) - // ── DIAGNOSTIC: trace local-network URLs entering subscribe() ── - const localInSubscribe = originalDedupedRelays.filter((u) => isLocalNetworkUrl(normalizeAnyRelayUrl(u) || u)) - if (localInSubscribe.length > 0) { - logger.warn('[DIAG] subscribe() received LOCAL-NETWORK relay URLs', { - localUrls: localInSubscribe, - allUrls: originalDedupedRelays, - stack: new Error('stack').stack?.split('\n').slice(1, 8).join(' | ') - }) - } let relays = originalDedupedRelays.filter((url) => !isHttpRelayUrl(url)) const filters = sanitizeSubscribeFiltersBeforeReq(filter) if (filters.length === 0) { @@ -2309,16 +2284,6 @@ class ClientService extends EventTarget { } = {} ) { let relays = Array.from(new Set(urls)) - // ── DIAGNOSTIC: trace local-network URLs entering _subscribeTimeline ── - const localInTimeline = relays.filter((u) => isLocalNetworkUrl(normalizeAnyRelayUrl(u) || u)) - if (localInTimeline.length > 0) { - logger.warn('[DIAG] _subscribeTimeline received LOCAL-NETWORK relay URLs', { - localUrls: localInTimeline, - allUrls: relays, - httpOnes: relays.filter((u) => isHttpRelayUrl(u)), - stack: new Error('stack').stack?.split('\n').slice(1, 10).join(' | ') - }) - } if (relayFiltersUseCapitalLetterTagKeys(filter as Filter)) { relays = relayUrlsStripExtendedTagReqBlocked(relays) if (relays.length === 0) { diff --git a/src/services/modal-manager.service.ts b/src/services/modal-manager.service.ts index 03e1eadb..087a1771 100644 --- a/src/services/modal-manager.service.ts +++ b/src/services/modal-manager.service.ts @@ -1,5 +1,3 @@ -import logger from '@/lib/logger' - class ModalManagerService { static instance: ModalManagerService @@ -15,19 +13,10 @@ class ModalManagerService { register(id: string, cb: () => void) { const modal = this.modals.find((m) => m.id === id) 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) { @@ -36,24 +25,13 @@ 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) { - logger.info('[LightboxTrace][ModalManager] pop noop', { modalCount: this.modals.length }) - return false - } + if (!modal) return false modal.cb() - logger.info('[LightboxTrace][ModalManager] pop close', { - id: modal.id, - modalCount: this.modals.length - }) return true } }