Commit Graph

4447 Commits

Author SHA1 Message Date
Mary Kate Fain edd13e26f7 Fix emoji picker closing when expanding to full picker
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.
2026-02-23 12:07:53 -06:00
Mary Kate Fain c046e33f6b Replace hardcoded emoji picker with emoji-mart for full emoji support 2026-02-23 12:05:21 -06:00
Alex Gleason 45048912e1 Merge branch 'feat/read-more-truncation' into 'main'
Truncate long posts in feed with Read more button

See merge request soapbox-pub/ditto-mew!1
2026-02-23 18:05:15 +00:00
Mary Kate Fain d37e050f9c Truncate long posts in feed with Read more button 2026-02-23 11:57:54 -06:00
Alex Gleason 1f035f4a6e Rename Mew to Ditto across entire codebase
- Update all branding: titles, meta tags, OG tags, manifest
- Rename MewLogo component to DittoLogo
- Update Capacitor config: appId to pub.ditto.app, hostname to ditto.pub
- Migrate Android Java package from com.mew.app to pub.ditto.app
- Rename MewNotificationPlugin to DittoNotificationPlugin
- Update all localStorage keys from mew: to ditto: prefix
- Update Nostr encrypted settings d-tag from mew-metadata to ditto-metadata
- Update all page titles, zap comments, and UI strings
- Rename ic_stat_mew.xml drawable to ic_stat_ditto.xml
- Update build script references (mew.apk -> ditto.apk)
- Update all domain references (mew.shakespeare.wtf -> ditto.pub)
2026-02-23 11:50:00 -06:00
Alex Gleason 0d48221476 Validate encrypted settings with Zod to prevent corrupted data from crashing the app
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.
2026-02-23 11:37:17 -06:00
Alex Gleason f826379d95 Fix crash when theme from localStorage has no matching tokens 2026-02-23 11:15:47 -06:00
Chad Curtis 75667f3c10 Replace event filtering with smart pagination cursor to prevent data loss
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.
2026-02-23 05:42:54 -06:00
Chad Curtis 87b215f2e9 Fix query key mismatch in useDeleteEvent preventing cache invalidation after deletion 2026-02-23 05:36:51 -06:00
Chad Curtis 68fbcfbe55 Add Blossom server redundancy: mirroring, URL preference, and media fallback
- 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
2026-02-23 05:19:07 -06:00
Chad Curtis 79d366b240 Add virtual gamepad controls and fullscreen toggle for webxdc games 2026-02-23 01:17:35 -06:00
Chad Curtis 986dffadda Add virtual gamepad controls and fullscreen toggle for webxdc games 2026-02-23 00:57:42 -06:00
Alex Gleason dd9c51ea80 Merge branch 'main' of gitlab.com:soapbox-pub/ditto-mew 2026-02-22 22:40:47 -06:00
Alex Gleason f45e585c8f Migrate theme definitions from CSS to JS 2026-02-22 22:39:10 -06:00
Chad Curtis 79f0ccb689 Fix FAB disappearing after navigating home -> profile -> home
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.
2026-02-22 20:34:00 -06:00
Alex Gleason 30b4f219d4 Merge branch 'main' of gitlab.com:soapbox-pub/ditto-mew 2026-02-22 18:05:46 -06:00
Alex Gleason 75585b2c42 Remove nostr-wasm 2026-02-22 18:05:36 -06:00
Chad Curtis 59c7d57060 Hide 'no replies' empty state for reply events in thread view 2026-02-22 18:03:43 -06:00
Chad Curtis 8ab67882f1 Fix duplicate replies in post details and remove sticky header 2026-02-22 17:46:15 -06:00
Chad Curtis 24c577e152 Show zap amount in native notifications, navigate to /notifications on tap
- 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)
2026-02-22 17:40:33 -06:00
Chad Curtis 891edd63ee Fix lint errors: revert lazy nostr-wasm init, remove unused imports 2026-02-22 17:32:03 -06:00
Chad Curtis 782d3c882f Add threaded NoteCard variant, scroll-to-focus with highlight pulse 2026-02-22 17:24:56 -06:00
Chad Curtis 0b2c7e44fe Add threaded variant to NoteCard, remove duplicate AncestorNote 2026-02-22 17:18:13 -06:00
Chad Curtis fa0bcb9fed Simplify replies to flat NoteCards in discussion order 2026-02-22 17:13:18 -06:00
Chad Curtis 817c9fc64d Group linear reply chains with connected treatment, keep branches flat 2026-02-22 17:11:27 -06:00
Chad Curtis 128f53d1e0 Show full ancestor thread chain and order replies by conversation flow 2026-02-22 17:07:11 -06:00
Chad Curtis 6c8eea5f56 Add break-all to compose textarea so npub text wraps inline 2026-02-22 16:57:46 -06:00
Chad Curtis bca82dcdc7 Fix mention autocomplete not clickable inside compose modal
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.
2026-02-22 16:56:39 -06:00
Chad Curtis 34a094c42d Fix mention detection reliability and prevent feed from clearing
- 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
2026-02-22 16:48:36 -06:00
Chad Curtis 848c5132e3 Centralize DITTO_RELAY const and fix URL consistency
- 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
2026-02-22 16:42:08 -06:00
Alex Gleason aa19eab80b Merge branch 'main' of gitlab.com:soapbox-pub/ditto-mew 2026-02-22 16:34:41 -06:00
Alex Gleason b4a7ca5cc9 Use application/x-webxdc MIME type; accept legacy application/vnd.webxdc+zip as alias 2026-02-22 16:33:18 -06:00
Chad Curtis e0287459ab Add pull-to-refresh and FAB to profile page 2026-02-22 16:08:14 -06:00
Chad Curtis 250b3a07b0 Fix profile feed not loading by removing piggybacked kind 0 filter
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.
2026-02-22 16:02:00 -06:00
Alex Gleason 8e53b94fc2 Implement joinRealtimeChannel using ephemeral kind 20932 events 2026-02-22 14:56:54 -06:00
Alex Gleason 44854909bc Update webxdc kind from 4079 to 4932 2026-02-22 14:52:52 -06:00
Chad Curtis a23efc654b Fix image skeleton not filling full image frame on single images 2026-02-22 04:29:09 -06:00
Chad Curtis bb1a0b8465 Remove dead code: FeedSettingsForm, MuteSettings, useProfileFollowing 2026-02-22 03:27:28 -06:00
Chad Curtis bcd4e4bb80 Add infinite scroll to notifications, skeleton loading for images
- 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
2026-02-22 03:16:46 -06:00
Chad Curtis 65fc03db8c Replace duplicated notification cards with NoteCard
ReferencedPostCard, FullNoteCard, and ActionButtons were identical
copies of NoteCard's rendering. Use NoteCard directly with
className='border-0' for inline notification display. -330 lines.
2026-02-22 02:55:27 -06:00
Chad Curtis d2fd1c9737 Consolidate Feed: merge KindFeedPage into Feed with props
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.
2026-02-22 02:51:34 -06:00
Chad Curtis e9c100435f DRY extra-kind feeds with main feed using shared components
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.
2026-02-22 02:47:44 -06:00
Chad Curtis 13fedc213a Reuse shared Lightbox for MTG card gallery, fix safe area 2026-02-22 02:38:29 -06:00
Chad Curtis b122b0b1af Fit single images to natural aspect ratio capped at 85dvh 2026-02-22 02:02:38 -06:00
Chad Curtis 580b5ae46e Fix whitespace stripped around URLs containing naddr1 identifiers
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.
2026-02-22 01:49:38 -06:00
Chad Curtis d746ffaab3 Use dedicated media:true search query for profile media tab and sidebar
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.
2026-02-22 01:43:45 -06:00
Chad Curtis ea0f01da98 Optimize profile page load performance and reduce relay queries
- 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
2026-02-22 01:26:47 -06:00
Chad Curtis ceb48fc9c6 Optimize profile page queries to match main feed patterns
- 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
2026-02-22 00:18:02 -06:00
Chad Curtis e459583a08 Remove unused pubkey prop from ProfileRightSidebar 2026-02-21 23:37:34 -06:00
Chad Curtis 9b128bada5 Consolidate profile metadata, following, and pins into single query
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.
2026-02-21 23:27:50 -06:00