Commit Graph

727 Commits

Author SHA1 Message Date
Alex Gleason bc9fd431b8 Fix _@domain.com profile URLs linking to npub instead of /domain.com
The _@ prefix denotes the root/default user for a domain. These users
should link to /domain.com (which the profile page resolves as a NIP-05
identifier), not the npub. The domain feed lives at /timeline/domain.com,
not /domain.com.
2026-02-23 19:42:43 -06:00
Alex Gleason 64cf10f381 Fix useProfileUrl to call useNip05Verify directly instead of peeking cache
The cache-peek approach always returned npub because the cache was empty
at render time. Replace it with a proper hook that calls useNip05Verify,
relying on TanStack Query's deduplication to avoid redundant requests.

Also fix the dot separator in NoteCard to hide when NIP-05 is unverified,
and refactor ProfileSearchDropdown to pass the verified URL through
onClick rather than recomputing it in an event handler.
2026-02-23 19:39:13 -06:00
Alex Gleason d3d44689d6 Verify NIP-05 identifiers before displaying them
Add useNip05Verify hook that uses Nostrify's NIP05.lookup() to verify
that a claimed NIP-05 identifier resolves to the correct pubkey via
.well-known/nostr.json. Update Nip05Badge and all raw nip05 display
sites to suppress display when verification fails or is pending.
2026-02-23 19:14:34 -06:00
Alex Gleason f260b6192f fix: remove invalidateQueries after settings write to prevent theme revert
After updating encrypted settings, the onSuccess handler was calling
invalidateQueries which triggered a relay refetch. The relay would often
return the old event (before the new one propagated), causing NostrSync
to see a new lastSync timestamp and overwrite the locally-set theme
with the old value from Nostr.

The setQueryData call already keeps the cache up to date in-place,
so the invalidateQueries was purely counterproductive.
2026-02-23 18:04:27 -06:00
Alex Gleason 5a816369d0 Don't embed target event into kind 6 reposts 2026-02-23 17:55:18 -06:00
Alex Gleason 308deb3281 Restore nip85StatsPubkey as a configurable setting
The pubkey was incorrectly hardcoded in the previous commit. Restore it
to AppConfig, the Zod schema, defaultConfig objects, all three
useNip85Stats hooks, and the Stats Source section in AdvancedSettings.
The NIP-85 Only Mode toggle (and its nip85OnlyMode config field) remains
removed — NIP-85 is always used.
2026-02-23 17:14:19 -06:00
Alex Gleason 6e36097142 Remove NIP-85 toggle — NIP-85 stats are now always used
Remove nip85StatsPubkey and nip85OnlyMode from AppConfig, AppProvider
schema, and all defaultConfig objects. The stats pubkey is now a
hardcoded constant in useNip85Stats. Remove the Stats Source section
from AdvancedSettings (UI toggle and pubkey input). Simplify
useEventStats to use NIP-85 exclusively — delete the direct-query
fallback, computeStats, extractZapAmount, and parseBolt11Amount.
Simplify useComments to remove the NIP-85-driven limit heuristic and
the nip85Stats return value.
2026-02-23 16:59:29 -06:00
Alex Gleason cc25fee53d Restore useRepostStatus and decouple useEventInteractions from NIP-85
useRepostStatus is the correct pattern (matching useUserReaction) for
tracking the current user's own repost status via a targeted relay query
with optimistic cache support. useEventInteractions now only fetches raw
interaction events for the InteractionsModal — NIP-85 involvement and the
hasNip85Stats query-key trick are removed entirely.
2026-02-23 16:51:37 -06:00
Alex Gleason 17c23e2d78 Merge branch 'unrepost' into 'main'
Add ability to unrepost a post

See merge request soapbox-pub/ditto-mew!10
2026-02-23 22:44:20 +00:00
Alex Gleason 6087c1a821 Derive repost status from useEventInteractions instead of a dedicated hook
Remove useRepostStatus (which made a separate relay query per post) and
instead look up the current user's pubkey in the reposts list already
fetched by useEventInteractions. Add eventId to RepostEntry so the
deletion event ID is available without an extra query.
2026-02-23 16:44:09 -06:00
Alex Gleason 3a9fc4d499 Merge branch 'follow-button-hover-card' into 'main'
Add follow button to profile hover card

See merge request soapbox-pub/ditto-mew!11
2026-02-23 22:34:55 +00:00
Alex Gleason 5986a13639 Simplify client tag (no fake names) 2026-02-23 16:21:57 -06:00
Mary Kate Fain 49daa1faad Add follow button to profile hover card
Create a reusable FollowButton component and add it to the
ProfileHoverCard, positioned over the banner image. The button
uses the existing useFollowActions hook for safe kind 3 mutations
and automatically hides for the user's own profile or when logged out.
2026-02-23 16:19:40 -06:00
Mary Kate Fain 7a8ee981bd Add ability to unrepost a post
Query the user's own kind 6 events to detect existing reposts, then
show an 'Undo repost' option in the popover menu and highlight the
repost button green when active. Unreposting publishes a kind 5
deletion event (NIP-09) with optimistic UI updates.
2026-02-23 15:55:44 -06:00
Alex Gleason d4bac9f255 Merge branch 'orient' into 'main'
Align 'Vibed with Shakespeare' footer text to the left

See merge request soapbox-pub/ditto-mew!6
2026-02-23 21:33:56 +00:00
Alex Gleason af643cbad3 Merge branch 'trends-infinite-scroll' into 'main'
Home page use Hot feed

See merge request soapbox-pub/ditto-mew!8
2026-02-23 21:33:36 +00:00
Alex Gleason 053e1888d0 Merge branch 'add-copy-npub-button' into 'main'
Add copy three dots menu to your own profile

See merge request soapbox-pub/ditto-mew!4
2026-02-23 21:32:51 +00:00
Mary Kate Fain efab0a4dee Rename 'Ditto' theme to 'Dark' and use Palette icon 2026-02-23 14:50:04 -06:00
Mary Kate Fain dc2724ccc9 Show hot sorted feed instead of global feed for logged-out users 2026-02-23 14:26:44 -06:00
Mary Kate Fain fe58061e28 Add infinite scroll pagination to trends feeds (hot, rising, controversial) 2026-02-23 14:23:39 -06:00
Mary Kate Fain 5a569c3ddd Remove floating Join button on mobile when logged out
The FloatingComposeButton now returns null for logged-out users,
removing the floating Join CTA from mobile. The topbar Join and
other login CTAs are unchanged.
2026-02-23 14:16:52 -06:00
Mary Kate Fain 2bcc695134 Align 'Vibed with Shakespeare' footer text to the left 2026-02-23 14:10:32 -06:00
Alex Gleason 319783d636 Refetch author profile on post detail, profile page, and hover card mount 2026-02-23 14:10:10 -06:00
Alex Gleason a87b6c3c02 Show skeleton loading states for avatars and names while profile is fetching
Replace the '?' avatar fallback and 'Anonymous' name placeholder with skeleton
loaders in ComposeBox and LeftSidebar during initial profile load. Expose
isLoading from useCurrentUser and useLoggedInAccounts to support this.
2026-02-23 13:37:44 -06:00
Alex Gleason cc74443010 Render DittoLogo using CSS mask with primary color 2026-02-23 13:10:47 -06:00
Mary Kate Fain b5dcd7085e Fix emoji picker crash caused by HTMLElement illegal constructor
Bypass @emoji-mart/react wrapper which creates new Picker() in useEffect,
causing 'Failed to construct HTMLElement: Illegal constructor' when React
remounts the component (e.g. opening popover in reply or compose box).
Instead, manage the emoji-mart Picker Web Component imperatively via refs.
2026-02-23 12:42:59 -06:00
Mary Kate Fain d64f29e52d Show three-dot menu on own profile for copy npub access, hide mute/report for self 2026-02-23 12:32:57 -06:00
Mary Kate Fain 8a00c4dd33 Add copy npub button to profile header for all profiles 2026-02-23 12:30:03 -06:00
Mary Kate Fain f735b0fde7 Add emoji shortcode autocomplete in compose box
Type a colon followed by at least 2 characters (e.g. :fi) to trigger
an inline emoji autocomplete dropdown. Navigate with arrow keys, select
with Enter/Tab, or dismiss with Escape. Uses the existing emoji-mart
data for search by shortcode, name, and keywords.
2026-02-23 12:20:00 -06:00
Alex Gleason 97ce94cc2f Merge branch 'full-emoji-picker' into 'main'
Replace hardcoded emoji picker with emoji-mart for full emoji support

See merge request soapbox-pub/ditto-mew!2
2026-02-23 18:13:47 +00:00
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