Commit Graph

1712 Commits

Author SHA1 Message Date
Chad Curtis e6f5bb926c Fix safe area insets in mobile drawer
When a theme background image is active, the rounded panel containers
were visually extending into the status bar (top) and home indicator
(bottom). Safe area insets were applied inside child elements but the
outer wrapper painted behind them. Move the insets to the outer wrapper
so the panels sit entirely within the safe area.
2026-03-16 02:40:36 -05:00
Chad Curtis 947bbfccb0 Add deep linking for ditto.pub Android App Links
- Add Android intent-filter with autoVerify for https://ditto.pub/*
- Create DeepLinkHandler component to handle appUrlOpen events at runtime
- Mount DeepLinkHandler in AppRouter inside BrowserRouter context
- Add public/.well-known/assetlinks.json with pub.ditto.app package and signing cert fingerprint
2026-03-16 01:39:56 -05:00
Alex Gleason 0305a53116 Reduce bottom overscroll padding from 50vh to 10vh 2026-03-16 00:03:36 -05:00
Alex Gleason d7461e0488 Add bottom overscroll padding to center column for visual comfort and bottom bar clearance 2026-03-15 23:17:15 -05:00
Alex Gleason 80a2d3d846 Remove 'View on njump.me' from profile dropdown menu 2026-03-15 04:33:14 -05:00
Alex Gleason 93c1d81c06 Add relay hint to 'a' tag in generic reposts of addressable events 2026-03-15 04:26:09 -05:00
Alex Gleason 53c1fb1090 Fix quote posts for addressable events: use naddr instead of nevent
Addressable events (kinds 30000-39999) like lists get new event IDs when
updated, causing nevent references to break. Use naddr coordinates
(kind:pubkey:d-tag) which remain stable across updates.
2026-03-15 04:24:48 -05:00
Alex Gleason f92f50d5e0 Fix quote posts not loading: include relay hints in nevent URIs and q tags 2026-03-15 04:19:02 -05:00
Alex Gleason 1fbdd2f729 Merge branch 'main' of gitlab.com:soapbox-pub/ditto 2026-03-15 04:13:56 -05:00
Alex Gleason eb0f4270b1 Show tombstone when quoted posts can't be loaded
Replace silent null returns in EmbeddedNote and EmbeddedNaddr with a
visible tombstone UI showing 'This post could not be loaded' with a
dashed border and icon, so users know a quote was referenced even when
the event can't be fetched from relays.
2026-03-15 03:41:21 -05:00
Chad Curtis 42ef548b0a Fix video not rendering in reply chains 2026-03-15 03:24:09 -05:00
Chad Curtis a5345f4c61 Add .qt video format support 2026-03-15 03:19:13 -05:00
Alex Gleason d2e1a10fd2 Merge branch 'main' of gitlab.com:soapbox-pub/ditto 2026-03-15 03:14:54 -05:00
Chad Curtis 05e1e05740 Add Ditto tab (enabled by default) and disable Global tab by default
- Add 'ditto' CoreFeedTab that renders the same hot-sorted curated feed
  (useInfiniteHotFeed) previously shown only to logged-out visitors
- Change Global tab default from enabled to disabled
- Update useFeedTab to default to 'ditto' instead of 'global' when logged out
- Add showDittoFeed localStorage toggle in Feed.tsx and ContentSettings.tsx
- Add Ditto Feed toggle row in ContentSettings FeedTabsSection
2026-03-15 02:55:08 -05:00
Alex Gleason 449723e25f Remove List icon from list cards in feeds and embeds
The icon next to the list title adds visual noise without helping. The
PartyPopper icon is kept for starter packs (kind 39089) where it has
distinct meaning.
2026-03-15 02:44:43 -05:00
Alex Gleason 7c83e42001 De-emphasize author on list/follow-pack cards in feeds and embeds
For kind 30000 (lists) and 39089 (starter packs), replace the prominent
avatar + bold name header with a content-first layout: the list title,
description, and member avatars are shown as the hero, followed by a
subtle small author attribution line (tiny avatar, muted text, timestamp).

This applies to both normal and threaded layouts, as well as compact/embed
mode used in quote posts and inline embeds.
2026-03-15 02:39:19 -05:00
Alex Gleason 434e4ad806 Fix lists not rendering in quote posts
When a kind 30000 list is quoted, ComposeBox encodes it as a nevent
which routes through EmbeddedNote. EmbeddedNote had no kind-specific
handling, so lists appeared as generic text cards instead of the rich
card with title, member avatars, and description.

Add the same NOTECARD_KINDS check (kind 30000, 39089) that EmbeddedNaddr
already uses, delegating to NoteCard compact for these kinds.
2026-03-15 02:32:13 -05:00
Alex Gleason a66211845f Add share/repost/quote dropdown to list page, rename Follow Sets to Lists
Replace the single Share button on the list detail page with a dropdown
menu offering Share (copy link / native share), Repost (kind 16 generic
repost), and Quote post (opens composer with quoted event).

Also rename all user-facing 'Follow Sets' terminology to 'Lists' across
the UI: UserListsPage, ListDetailPage, FollowPackDetailContent,
AddToListDialog, and SavedFeedFiltersEditor.
2026-03-15 02:15:01 -05:00
Chad Curtis 5a28692e55 Remove isPending disabled prop causing switch flicker on toggle 2026-03-14 19:13:32 -05:00
Chad Curtis e3cd2365c6 Fix toggle flicker: initialize local state once from settings, persist in background 2026-03-14 19:11:47 -05:00
Chad Curtis 801e966abe Fix toggle flicker with optimistic local state 2026-03-14 19:09:40 -05:00
Chad Curtis b76bf7b198 Condense notifications and add per-type notification preferences
- Group reactions, reposts, and zaps on the same post into a single condensed
  row with stacked actor avatars (up to 5 + overflow count); single-actor
  interactions use the original compact layout
- Deduplicate actors by pubkey within groups
- Sum zap totals across all actors in a zap group
- Add notificationPreferences per-type settings (reactions, reposts, zaps,
  mentions, comments, onlyFollowing) to EncryptedSettings and Zod schema
- Per-type kind toggles and onlyFollowing applied at relay query level (kinds
  array + authors filter), not client-side; query key includes kindsKey and
  authorsKey so preference changes trigger a fresh fetch
- Default push notifications to enabled
- Notification settings UI matches ContentSettings exactly: section headers
  with accent underline, p-4 wrapper, broken border rows (border-b on outer
  wrapper div), sub-section labels, w-[52px] switch column, KindBadges
- Add 'Only from people I follow' toggle under Filter sub-section
- Filter and push notification prefs also respected in useNativeNotifications
  web push subscription via stable ref
2026-03-14 19:06:31 -05:00
Chad Curtis 287b35d337 Use 2x2 grid layout for ScopeToggle when there are more than 3 options 2026-03-14 17:36:30 -05:00
Chad Curtis a3e5b94e69 Fix profile tab editor missing people filter and tab feed using paginated query
- ProfileTabEditModal: add 'People' scope option with AuthorFilterDropdown and
  ListPackPicker so users can pick specific pubkeys as tab authors, matching
  the filter options available on the normal search filter
- useProfileFeed: add useTabFeed hook that runs a paginated useInfiniteQuery
  with full NostrFilter support (kinds, authors, NIP-50 search)
- ProfileSavedFeedContent: replace useStreamPosts with useTabFeed so custom
  tab content uses cursor-based pagination (like the posts tab) instead of
  streaming, fixing search-keyed queries and enabling infinite scroll
2026-03-14 17:34:21 -05:00
Chad Curtis bf9cef5bb5 Allow adding app default servers/relays to personal lists 2026-03-14 16:19:23 -05:00
Alex Gleason b094e01337 Extract shared parseBlossomServerList into appBlossom.ts
Deduplicates the kind 10063 tag parsing logic that was repeated in both
NostrSync.tsx and useInitialSync.ts. Both now call the shared function
from lib/appBlossom.ts.
2026-03-14 15:55:29 -05:00
Chad Curtis f200359059 Implement BUD-03 kind 10063 Blossom server list management
Blossom servers now work exactly like relays:
- App default servers (APP_BLOSSOM_SERVERS) can be toggled on/off
- User's kind 10063 server list is fetched and synced from Nostr
- NostrSync fetches kind 10063 on login and applies it to config
- useInitialSync fetches kind 10063 in parallel on first login
- BlossomSettings UI mirrors RelayListManager with two sections:
  App Blossom Servers (with enable toggle) + Your Blossom Servers
- User changes publish a kind 10063 replaceable event to Nostr
- getEffectiveBlossomServers() merges app + user servers like getEffectiveRelays()
- Migration from old blossomServers[] to blossomServerMetadata handled in AppProvider
2026-03-14 12:34:59 -05:00
Chad Curtis c36174d9de Paginate FollowsList in search accounts tab to fix perf with 1000+ follows 2026-03-14 11:50:11 -05:00
Chad Curtis 396007d455 Remove unused eslint-disable directive in SearchPage 2026-03-14 11:45:06 -05:00
Chad Curtis a827744ddc Remove focus ring from reaction buttons and add double-click to heart react 2026-03-14 11:43:53 -05:00
Chad Curtis 4684491b9f fix: apply search query filter to all streamed event kinds
Non-kind-1 events (articles, photos, videos, etc.) bypassed the client-side
search check via an early return, so streamed events of any extra kind passed
through regardless of the search query. Remove the early return and apply the
query filter to all kinds, also checking title/summary/subject/alt tags for
non-text events. Reply filtering still only applies to kind 1/1111.
2026-03-14 11:29:39 -05:00
Chad Curtis b4f88ec448 fix: align filter grid labels and rename Platform to Protocol
The Protocol label used flex layout for the HelpTip icon while the other
three labels did not, causing vertical misalignment of the selects below
them. Give all four labels the same flex items-center gap-1 classes.
Also rename Platform to Protocol.
2026-03-14 11:22:00 -05:00
Chad Curtis 97fe74be07 fix: unwrap repost events before rendering in search feed
Kind 6/16 repost events were passed raw to NoteCard without extracting the
embedded original event, so reposts showed nothing. Mirrors the same
parseRepostContent + repostedBy pattern used in useFeed/Feed.tsx.
2026-03-14 11:19:15 -05:00
Chad Curtis 79ea07098d fix: use all picker kinds when kind filter is set to 'all'
parseKindFilter returned undefined for 'all', causing useStreamPosts to fall
back to the user's enabled feed-settings kinds instead of every kind in the
kind picker list. Now kindsOverride always contains explicit kind numbers:
all picker kinds when filter is 'all', or the specific selection otherwise.
2026-03-14 11:15:59 -05:00
Chad Curtis cf1edc3230 fix: always include kind 1 in default search kinds
getEnabledFeedKinds only returns user-toggled extra kinds, never kind 1.
The fallback paths for videos/images/all were missing kind 1 entirely,
so searches returned no results unless the user had explicitly enabled
extra feed kinds.
2026-03-14 11:13:11 -05:00
Chad Curtis b789c0e821 fix: resolve search input focus loss, lag, and add-to-feed button regressions
- Prevent focus steal on first keystroke: the add-to-feed bookmark button was
  conditionally mounted when searchQuery became non-empty, causing a DOM mutation
  mid-keystroke that stole focus from the input

- Eliminate searchParams feedback loop: the state→URL sync effect had searchParams
  in its dependency array, causing a cascade of extra re-renders on every keystroke
  after the debounce settled

- Eliminate per-keystroke re-renders: raw input state now lives in a dedicated
  SearchInput child component with its own internal debounce; SearchPage only
  holds the debounced value and re-renders when typing stops, not on every character
2026-03-14 11:11:33 -05:00
Alex Gleason 78cf05f623 Use lowercase 'k' for thousands in short number format 2026-03-14 02:39:52 -05:00
Alex Gleason 0ffe2de89d Use short number format for large stats (e.g. 1.7K, 314K, 2M) 2026-03-14 02:39:14 -05:00
Alex Gleason 09091441c6 Linkify URLs and hashtags in user bios on profile pages
Add BioContent component that tokenizes bio text to render URLs as
clickable links and hashtags as internal navigation links, while
preserving NIP-30 custom emoji support. Applied to ProfilePage,
ProfileHoverCard, and ProfileCard read-only bio displays.
2026-03-14 01:30:57 -05:00
Alex Gleason 71f9a6c354 Expand vine slides to fill screen when bottom nav hides on scroll
The vine-slide-height CSS class statically subtracted 3.5rem for the
bottom nav. Added a vine-slide-height-expanded class without that
subtraction, toggled by scroll direction so the video fills the full
viewport when the bottom nav slides away.
2026-03-14 01:18:08 -05:00
Alex Gleason f74d333d63 Fix mobile bottom nav not hiding on swipe in Vines page
The Vines page uses an internal snap-scroll container instead of window
scroll, so useScrollDirection (which listened to window.scrollY) never
detected any scroll movement. Add a scrollContainer option to
LayoutOptions so pages with custom scroll containers can communicate
the element to MobileBottomNav, which passes it to useScrollDirection.
2026-03-14 01:08:45 -05:00
Dirk Rost 33c95f6ace Merge branch 'fix/youtube-thumbnails-again' into 'main'
Fix YouTube thumbnail gray placeholder with off-screen probing

See merge request soapbox-pub/ditto!69
2026-03-14 05:59:03 +00:00
Lemon d3457f5868 Fix YouTube thumbnail gray placeholder with off-screen probing 2026-03-14 05:59:03 +00:00
Alex Gleason 8782d8e1bc Change mobile bottom nav items to Search, Notifications, and Profile
Replace Feed/Home button with Profile, which shows the user's avatar at
a small size. Search and Notifications remain. Logged-out users see a
generic User icon for Profile instead of the avatar.
2026-03-14 00:52:52 -05:00
Alex Gleason 59311e6b2c Restore mobile bottom nav with scroll-to-hide behavior
Bring back the mobile bottom navigation bar with Home, Notifications, and
Search buttons. The nav slides out of view when scrolling down and reappears
on upward scroll, keeping the viewport uncluttered while reading. Search
retains the popover account search sheet for fast profile lookup without
navigating away. Updated CSS height calculations for full-screen pages
(AI chat, vines, livestream) and FAB positioning to account for the nav.
2026-03-13 22:47:17 -05:00
Alex Gleason 3727975178 Move 'Set a status' into profile menu on mobile drawer 2026-03-13 22:30:17 -05:00
Alex Gleason e95a63fcf6 Fix emoji picker touch scrolling on mobile in avatar shape dialog 2026-03-13 22:16:59 -05:00
Alex Gleason 2373848d2e Use drop-shadow border for emoji-shaped avatars on profile pages
Replace border/ring with a crisp drop-shadow outline (via emojiAvatarBorderStyle)
so the border follows the emoji mask shape without clipping. Shrink emoji avatars
by the border width so they match the visual footprint of bordered circular ones.
2026-03-13 21:58:45 -05:00
Alex Gleason f23faa7ef3 Fix mute list not being honored: parse public tags and support NIP-04
The mute list (kind 10000) was only reading encrypted content, ignoring
public tags in the event's tags array. Per NIP-51, mute items can be
stored as either public tags or private encrypted content. Most Nostr
clients store mutes as public tags, so these were being silently ignored.

Changes:
- Parse both public tags and encrypted content from kind 10000 events
- Add NIP-04 backward compatibility (detect by '?iv=' in ciphertext)
- Deduplicate items that appear in both public and private sections
- Apply same fixes to useInitialSync for login-time bootstrapping

Fixes: https://gitlab.com/soapbox-pub/ditto/-/work_items/96
2026-03-13 21:42:56 -05:00
Alex Gleason d6aec14936 Fix edit profile avatar/banner hover: keep pencil badge visible and replace camera icons with pencil 2026-03-13 21:23:10 -05:00