The popover's mouse-leave timeout was firing during the DOM transition
from the quick-select bar to the full emoji-mart picker, causing it to
close immediately. Added an expanded state flag that disables the
hover-to-close behavior when the full picker is shown.
Encrypted settings synced via NIP-78 were parsed with a bare JSON.parse()
and cast with 'as EncryptedSettings', allowing invalid data (e.g. theme as
an object instead of a string) to pass through unchecked and crash the UI
when applied to classList.add(). Now both useEncryptedSettings and
useInitialSync validate decrypted JSON with a shared EncryptedSettingsSchema,
gracefully dropping invalid fields instead of propagating them.
Instead of discarding events from out-of-sync relays, keep all events
for display and compute the pagination cursor from the main timestamp
cluster. Outlier events are still shown but don't drag the cursor
backward, preventing pagination gaps without losing data.
- Add blossom.ditto.pub and blossom.dreamith.to as primary servers
- Mirror uploads to all configured servers via BUD-04 (fire-and-forget)
- Prefer first configured server for upload URLs
- Fall back to alternative Blossom servers when images/videos fail to load
The useLayoutOptions cleanup effect was unconditionally resetting the
layout store on unmount. During page transitions, React runs the new
page's render (which sets the store) before the old page's cleanup
effect fires. The unconditional reset would clobber the new page's
options, causing showFAB to be wiped.
Now the cleanup only resets if the store still holds this component's
options, preventing it from interfering with the incoming page.
- Extract zap amount from kind 9735 events in NostrPoller.java (checks
amount tag then falls back to description tag's zap request)
- Format amounts compactly (e.g. 1.5K sats, 2M sats)
- Set data URI on notification PendingIntent so tapping opens /notifications
- Handle deep link intent in MainActivity (both onCreate and onNewIntent)
- Remove dead localNotificationActionPerformed listener from TypeScript
(only fired for Capacitor-API notifications, not natively posted ones)
Render dropdown inline with absolute positioning instead of portaling
to document.body, which placed it behind the modal overlay. Also set
overflow-visible on DialogContent so the dropdown isn't clipped.
- Make detectMention accept explicit text/cursor params to avoid relying
on DOM textarea state that can be stale during React render cycles
- Re-attach textarea listeners when content changes to handle element
remounts (e.g. preview mode toggle)
- Prevent feed from going empty during background refetches by keeping
previous data as placeholder (placeholderData)
- Extend feed gcTime to 30 minutes so cache survives navigation
- Export DITTO_RELAY from appRelays.ts, replacing hardcoded relay URLs
- Normalize all relay URLs to use trailing slashes, preventing NPool
from opening duplicate connections to the same relay
- Add cache-based fallback to mention search: when relay search returns
nothing, scan already-fetched author profiles in the query cache
The profile feed query was sending a kind 0 (metadata) filter alongside
the feed filter in a single query. Since kind 0 resolves almost instantly,
relays would EOSE early, triggering the 100ms pool eoseTimeout before
slower relays could deliver the actual feed events. The profile page
already fetches kind 0 via useAuthor/NostrBatcher, so it was redundant.
- Convert useNotifications from useQuery to useInfiniteQuery with
timestamp-based cursor pagination (20 per page)
- Batch-fetch referenced events per page and seed the query cache
- Add intersection observer + auto page-2 prefetch to NotificationsPage
- Render referenced posts via NoteCard (same as main feed)
- Add skeleton loading state to ImageGallery grid tiles with fade-in
- Remove 3-second delay from notification queries
ReferencedPostCard, FullNoteCard, and ActionButtons were identical
copies of NoteCard's rendering. Use NoteCard directly with
className='border-0' for inline notification display. -330 lines.
KindFeedPage is now a thin wrapper passing kinds/header to Feed.
Removes InfiniteFeed, FeedTabs, and useFeedTabs intermediary files.
Net -47 lines vs original with same tabs, infinite scroll, mute
filtering, and pull-to-refresh on all feed pages.
Extract InfiniteFeed, FeedTabs, and useFeedTabs so KindFeedPage
reuses the same useFeed hook, infinite scroll, pull-to-refresh,
mute filtering, and Follows/Community/Global tabs as the main feed.
URLs like https://following.party/naddr1... were having all surrounding
whitespace removed because naddr-embed tokens from URLs were treated as
block-level elements. Only bare naddr1 identifiers (without a URL) should
strip surrounding whitespace; URL-sourced ones are inline and need their
spacing preserved.
Replaces client-side media URL extraction with a dedicated NIP-50
search query (media:true) routed to relay.ditto.pub. This provides
more accurate media detection using the relay's index-time analysis.
Also fixes a bug where the Posts tab could flash 'No posts yet' when
navigating to a profile — filterByTab was a dependency of the feedItems
memo, so switching tabs could momentarily empty the list when the first
page was mostly replies.
- Defer bookmark/pin queries in NoteMoreMenu until menu is opened
- Move RightSidebar outside Suspense to prevent default sidebar queries on profile pages
- Split profile metadata: kind 0 piggybacked on feed query, kind 3+10001 fetched separately
- Share single feed query across posts/replies/media tabs (filter client-side)
- Reduce feed page size from 60 to 15 to match main feed
- Fix pagination using raw event count instead of filtered count
- Remove duplicate pinned events query from usePinnedNotes
- Add staleTime to useMuteList to prevent refetch on every navigation
- Add skeleton loading for banner, avatar, name, and pinned posts
- Stabilize streak calculation to use raw feed data across all tabs
- Combine profile metadata (kinds 0, 3, 10001) into useProfileFeed's first page query, eliminating the separate useProfileData REQ
- Add cacheEvents seeding to useProfileFeed so post detail views resolve from cache
- Add filterOutOfSyncEvents to prevent pagination gaps from slow relays
- Fix pagination cursor to use raw query timestamp instead of post-filter timestamp
- Extract filterOutOfSyncEvents to feedUtils for shared use by both feeds
- Fix pinned notes to fetch by ID instead of relying on feed page data
- Only mount usePinnedNotes for own profile to avoid query races
- Show sidebar media skeletons until media is found or all pages exhausted
Replace three separate relay queries (useAuthor kind 0, useProfileFollowing
kind 3, usePinnedNotes kind 10001) with a single useProfileData hook that
fetches all three kinds for the profile pubkey in one request. Seeds the
individual caches so downstream hooks (useAuthor in NoteCards, usePinnedNotes
for togglePin mutation) find data already cached. Pinned events are resolved
from the feed data instead of a separate ID lookup query.