Commit Graph

46 Commits

Author SHA1 Message Date
mkfain 850f35c29d i18n: translate ComposeBox + ReplyComposeModal
Adds the compose.* namespace covering ComposeBox: placeholders
(default, poll, country-scoped, content warning), preview / edit toggle,
poll mode (Add option, Option N, Single/Multiple choice, Back to post,
Publish poll, success/failure toasts), voice recording (Cancel, Send,
Sending, mic-denied toast, voice-message tooltip), toolbar
(Attach file, Emoji/GIF, More, Poll, Spoiler, Emoji, Stickers tabs),
submit (Posting / Posted toasts, upload-failed / publish-failed),
and destination dropdown (Post to label, Global / community
explainer popover, Choose another country picker, search placeholder,
empty state, Set as default, default-updated toasts).

Also adds replyModal.* for ReplyComposeModal — the six title fallbacks
(New poll, New comment, Comment on profile, Reply to post, Quote post,
New post), three placeholder fallbacks, and the Bluesky disclaimer.

ComposeBox's hardcoded default placeholder ('What's on your mind?') and
submitLabel ('Post!') props moved from prop defaults to t() fallbacks
inside the component so existing call sites can keep passing translated
strings unchanged. Renamed an inner .map((t) => …) variable in the poll
type/duration row to .map((pt) => …) since t shadowed the i18next t.
Added rtl:rotate-180 to the 'Back to post' chevron since it visually
points left/back.

ar / es / zh / fa / ps / km / sn translations drafted inline; km, sn,
ps, fa still pending native-speaker review.
2026-05-23 19:16:53 -05:00
mkfain f08e3d6226 Add three-mode home feed with Agora / All Nostr / Following
The home /feed page now offers a top-left dropdown to switch between three
chronological streams:

- Agora: campaigns, pledges, donations, communities, comments on Agora
  entities, and #Agora-tagged kind 1 notes (the existing useAgoraFeed mix,
  widened for NIP-72 communities).
- All Nostr: the global kind 1 stream interleaved with the full Agora mix.
- Following: same content scoped to authors in the logged-in user's
  follow list (gracefully gated when the follow list is loading or empty).

Implementation:

- useMixedFeed orchestrates the three modes, paginating the Agora and
  kind 1 layers in lockstep and merging chronologically.
- useAgoraFeed now accepts an optional authors filter (server-side) so
  Following mode doesn't fetch and discard the global Agora mix. It also
  includes new community definitions (34550) and community-scoped
  comments (1111 with A=34550:...).
- FeedModeSwitcher is the new top-left picker: large text2xl trigger,
  shadcn DropdownMenu with iconified options and active checkmark.
  Following is disabled (with tooltip) for logged-out users.
- AGORA_DEFAULT_NOTE_TAGS moved to src/lib/agoraNoteTags.ts; ComposeBox
  now auto-attaches t:agora to every top-level kind 1 from anywhere in
  the app (replies, quotes-as-replies, polls, and comments are unaffected).
- Feed mode persistence upgraded from sessionStorage to localStorage so
  preference sticks across sessions.
- Feed entry added to TopNav as the first item.

The globe backdrop, hue rotation, and translucent card treatment are
removed for a cleaner solid-background presentation. Specialized
feed pages (kind-specific, tag-filtered) keep the original Follows /
Global tab pair unchanged.
2026-05-21 20:22:36 -05:00
lemon 3b9eef908f Tag default notes as Agora 2026-05-21 00:30:37 -07:00
Alex Gleason 908c5b248c Enable commenting on NIP-73 identifier /i/ pages
ExternalContentPage already supported fetching comments for non-URL
external roots (bitcoin:tx:..., isbn:..., iso3166:..., etc.), but the
inline ComposeBox and the FAB's ReplyComposeModal were both gated on
the URL-only commentRootUrl — leaving those pages with no way to post.

Widen ComposeBox's replyTo and ReplyComposeModal's event to accept
`#${string}` NIP-73 identifiers alongside URLs and events, route them
through the existing NIP-22 publish path (usePostComment already
handled string roots), and wire the page up to the combined
commentRoot.
2026-05-05 15:46:30 -05:00
Alex Gleason f4ae344b30 Unify follow list, follow set, and follow pack rendering
Kind 3 (NIP-02 follow list), kind 30000 (NIP-51 follow set), and kind 39089
(follow pack) are all the same semantic thing — an event containing a list of
p-tagged pubkeys — but were being rendered three different ways, with kind 3
having no rendering at all, kind 30000 routing to a bespoke ListDetailPage, and
kind 39089 using its own FollowPackDetailContent.

Merge the three into a single PeopleListContent (feed card) and
PeopleListDetailContent (full detail). The detail component hosts every
feature from the predecessors: Follow All with existing p-tag preservation,
Save-as-copy for non-owners, owner-mode member removal for kind 30000, the
Feed/Members/Comments tabs, sidebar integration, and the share/copy-link
menu. For kind 3 the event has no title of its own, so we fall back to the
author's display name.

Additional refinements bundled in:

- Register kinds 3 and 30000 at every previously-missing rendering point:
  KIND_HEADER_MAP, shellTitleForKind, CommentContext KIND_LABELS/ICONS,
  extraKinds specific labels and icons, and ExternalContentHeader fallbacks.
  Kind 3 and 30000 now share the packs feed toggle via extraFeedKinds.
- Add infinite scroll to the people-list Feed tab via useTabFeed +
  IntersectionObserver sentinel, replacing the useStreamPosts 40-post cap.
- Add Comments tab alongside Feed and Members, powered by useComments
  (NIP-22 kind 1111). Drop the redundant variant badge. Allow kind 39089
  packs to be pinned to the sidebar.
- Trim redundant chrome: drop the member-count pill in the feed card,
  drop the member-count line in the detail header, and stop pulling the
  author's 'about' and 'banner' into kind 3 follow list views.
- Add a dedicated FollowListCommentContext branch so comments on kind 3
  show '@Name's follow list' instead of 'a follow list'.
- Replace the three-dots DropdownMenu on the detail view with the shared
  PostActionBar (reply/repost/react/zap/share/more), matching other
  detail views.
- Promote EmbeddedPost from ReplyComposeModal into a shared component
  that dispatches to EmbeddedNote / EmbeddedNaddr, with a new
  EmbeddedPeopleListCard for kinds 3/30000/39089 so quote posts, reply
  indicators, hover cards, and the More menu all render follow lists
  correctly.
- Link the 'N following' count on profile pages to a naddr of the kind 3
  event (routing to the new detail view) instead of a bespoke modal.
  Delete FollowingListModal. Using naddr rather than nevent ensures the
  link always resolves to the latest replaceable event.

Delete ListDetailPage, FollowPackDetailContent, and FollowingListModal
entirely. All three kinds now route through AddrPostDetailPage →
PeopleListDetailContent.
2026-04-17 18:52:00 -05:00
Chad Curtis 3aa08ba93e Overhaul compose box UX: inline picker, draft autosave, prevent accidental dismiss
- Move emoji/GIF/sticker picker from popover to inline panel in all contexts
- Add pill-style tab highlights for inline picker (emoji, GIF, stickers)
- Auto-save compose drafts to localStorage with debounce, keyed by context
- Prevent accidental modal dismissal (backdrop click blocked)
- Theme emoji picker to match Ditto design system (search, nav, scrollbar)
- Fix emoji picker width (dynamicWidth + shadow DOM overrides)
- Create StickerPicker component with search bar
- Restructure modal layout: scrollable content, sticky toolbar, fixed picker
- Mobile keyboard handling (blur/refocus textarea around picker)
- Move Tenor attribution into GIF search bar as inline hint
- Bump picker height to 280px
- Auto-focus textarea on modal open (iOS keyboard fix)
- Remove rounded corners from feed compose box
2026-04-17 00:01:38 -05:00
Mary Kate Fain cdf3391aad Fix emoji/mention autocomplete dropdowns not clickable in compose modal
The autocomplete dropdowns are portaled to document.body to escape
overflow clipping, which places them outside the Radix Dialog DOM tree.
Clicks on them were treated as 'interact outside' the dialog, preventing
mouse selection of emoji and mention suggestions.

Add data-autocomplete-dropdown attribute to both dropdown containers and
check for it in handleInteractOutside to prevent modal dismissal.
2026-04-13 21:09:58 -05:00
Chad Curtis 0c29506402 Fix all 50 ESLint warnings by extracting non-component exports and adding missing deps
- Extract utility functions from component files into dedicated modules
  to fix react-refresh/only-export-components warnings:
  - parseBadgeDefinition -> src/lib/parseBadgeDefinition.ts
  - parseProfileBadges -> src/lib/parseProfileBadges.ts
  - getColors, paletteToTheme -> src/lib/colorMomentUtils.ts
  - parseDimToAspectRatio, eventToMediaItem -> src/lib/mediaUtils.ts
  - isAudioUrl, isImageUrl, isVideoUrl -> src/lib/mediaTypeDetection.ts
  - buildKindOptions, parseSelectedKinds -> src/lib/feedFilterUtils.ts
  - useVideoThumbnail -> src/hooks/useVideoThumbnail.ts
  - useEnvelopeDimensions -> src/hooks/useEnvelopeDimensions.ts
  - usePortalContainer -> src/hooks/usePortalContainer.ts
  - useAudioPlayer -> src/contexts/audioPlayerContextDef.ts
  - SubHeaderBar context/hooks -> src/components/SubHeaderBarContext.ts
  - EmotionDev hooks -> src/blobbi/dev/useEmotionDev.ts
  - BlobbiActions context def -> BlobbiActionsContextDef.ts

- Remove export from internal-only functions (useEventComments,
  parseEmojiPack, useScrollCarets, formatEffectSummary, getSortedEffectEntries)

- Fix react-hooks/exhaustive-deps warnings by adding missing dependencies
  to useEffect/useCallback/useMemo hooks across 14 files

- Fix logical expression dependency warnings by wrapping conditional
  values (tasks, pubkeys, authorPubkeys) in useMemo

- Move module-level constants (CORE_TAB_IDS, CORE_TAB_LABELS,
  DEFAULT_TAB_LABELS) out of ProfilePage component body

- Reorder usePushNotifications hooks so syncPreferences is defined
  before enable to fix block-scoped variable error
2026-04-05 11:57:31 -05:00
Dmitriy E 47831ffa64 fix: intermittent mobile compose modal collapse and unclickable input 2026-04-05 10:27:43 -05:00
Mary Kate 21df47eccb Merge branch 'fix/compose-preview-overflow' into 'main'
Fix compose preview overflow not being scrollable in modal

Closes #179

See merge request soapbox-pub/ditto!126
2026-03-28 00:07:25 +00:00
Mary Kate Fain 310993d57c Fix compose preview overflow not being scrollable in modal 2026-03-27 18:51:14 -05:00
Mary Kate Fain 872d319220 Fix compose modal closing when dismissing emoji picker on mobile
Prevent the compose modal from being accidentally dismissed when the user
taps the emoji/GIF picker overlay to close it.  On mobile this was very
easy to trigger, causing the draft to be lost.

Add onInteractOutside and onEscapeKeyDown handlers to the compose modal's
DialogContent that detect when a nested dialog (emoji picker) is open and
prevent the dismiss event from propagating to the parent modal.
2026-03-27 18:31:58 -05:00
Alex Gleason ebafc87fd5 Improve CommentContext consistency and unify event preview rendering
- Extract shared CommentContextRow wrapper to eliminate duplicated div/className/skeleton patterns
- Unify getKindLabel into getEventDisplayName so kind-to-label mappings exist in one place
- Fix inconsistent min-w-0 overflow-hidden between loading and content states
- Add hover card previews to addressable event roots (A tag) using EmbeddedNaddr
- Replace bespoke reply composer embed with shared EmbeddedNote/EmbeddedNaddr components
2026-03-24 20:42:44 -05:00
Alex Gleason 8e76650a5f Render nsite events correctly across all views
Add NsiteCard rendering to PostDetailPage, reply composer, quote
embeds, comment context labels, and external content headers so
kind 15128/35128 events display properly everywhere.
2026-03-24 20:23:17 -05:00
Alex Gleason 4ea657a7b7 Restyle Bluesky disclaimer as a cheeky amber warning 2026-03-23 22:10:55 -05:00
Alex Gleason 715c58ceba Restore original Bluesky disclaimer text with styled callout 2026-03-23 22:10:28 -05:00
Alex Gleason 4f9f2c10bf Style Bluesky disclaimer as a branded callout banner 2026-03-23 22:09:32 -05:00
Alex Gleason d1c434050f Add Bluesky disclaimer in compose modal when replying to bsky.app URLs 2026-03-23 22:08:46 -05:00
Alex Gleason 87a295c974 Hide images in compose modal reply indicator and external post embeds
Thread hideImage prop through LinkEmbed -> BlueskyEmbed -> ExternalPostCard
so images are suppressed in the compose dialog preview, matching the
behavior of normal post reply indicators.
2026-03-23 21:57:22 -05:00
Alex Gleason 6c9a584b46 Link avatar and display name to Bluesky profile /i/ page
Clicking the avatar, display name, or handle now navigates to
/i/{bsky.app/profile/handle} instead of the post's /i/ page.
Clicks stop propagation so the card-level navigation still works.
2026-03-23 21:55:00 -05:00
Alex Gleason 0c03b78b56 Show link preview in compose modal when commenting on external URLs
ReplyComposeModal now renders a LinkPreview card when the event is a URL,
so users see what they're commenting on. Previously the preview was skipped
entirely for URL-based comments.
2026-03-23 21:52:29 -05:00
Alex Gleason 85b47a7a62 Consolidate 4 duplicate vanish compact cards into VanishCardCompact
The same stripes + glitch icon + title + npub + reason layout was
duplicated across EmbeddedVanishCard, EmbeddedVanishPost,
VanishEventContent compact mode, and an inline version in NoteCard's
threaded branch. Extract a single VanishCardCompact component and
replace all four copies with it.

Net reduction of 76 lines.
2026-03-21 22:39:13 -05:00
Alex Gleason 7a53aa2238 Add vanish preview in reply composer for kind 62 events
When replying to a Request to Vanish event, the reply composer now
shows a styled vanish preview instead of the generic author+content
card that looked broken for nuked accounts.
2026-03-20 23:37:48 -05:00
Chad Curtis f1c15b64a2 Add poll creation to compose toolbar and polls page FAB 2026-03-17 19:55:18 +00:00
Alex Gleason 10bb16abfb Clean up avatar shape code: remove magic strings, type casts, and inconsistencies
- avatar.tsx: consolidate to single isEmojiShape boolean, fix AvatarFallback using same logic as Avatar
- avatarShape.ts: accept NostrMetadata directly in getAvatarShape (no cast needed)
- Remove 'as Record<string, unknown>' casts from all ~50 call sites
- Replace 'circle' magic string with empty string in form defaults and parseShape
- Use isValidAvatarShape instead of string comparison in save logic
- ProfileCard: extract IIFE overlay style into useMemo, use isEmojiShape throughout
2026-03-13 21:14:03 -05:00
Alex Gleason 3b79b384e5 Add avatar shapes: users can set a shape (circle, triangle, hexagon, star, etc.) for their avatar via kind 0 metadata
- New 'shape' property on kind 0 profile metadata with 7 predefined shapes:
  circle, triangle, inverted-triangle, hexagon, star, inverted-star, hexagram
- Avatar component updated with clip-path support for non-circle shapes
- Visual shape picker added to both EditProfileForm and ProfileSettings
- Shape applied across all 49 avatar render sites in the app
- New UserAvatar wrapper component for future simplified avatar rendering
- Unknown shape values gracefully fall back to circle (forward compatible)
2026-03-13 16:14:40 -05:00
Lemon 54c4d7e47c Fix GIF picker scroll inside dialogs by portaling into modal container
Radix Dialog's RemoveScroll blocks wheel events on elements outside the
Dialog's DOM tree. The GIF picker Popover was portaling to document.body,
placing it outside the RemoveScroll boundary. Trackpad scrolling was
blocked while scrollbar dragging still worked.

Added PortalContainerContext so PopoverContent can portal into the modal
element instead of document.body when rendered inside a dialog/modal.
2026-03-06 23:16:30 -08:00
Alex Gleason 9da62f46cf Change wall compose placeholder to 'Write on {user}'s wall' 2026-03-02 14:16:02 -06:00
Alex Gleason 64810d3acc Fix post composer dialog to autofocus textarea instead of X button 2026-03-02 10:17:27 -06:00
Mary Kate Fain 081d890e41 Fix reply modal overflowing viewport on long posts
Make the embedded parent post scrollable and cap the dialog at 85vh
so the compose area and submit button always remain visible.
2026-03-01 12:56:20 -06:00
Chad Curtis 71d08aadd1 Show profile card in reply modal and correct title for kind 0 wall posts
ReplyComposeModal now renders ProfilePreview instead of raw JSON content
when the reply target is a kind 0 event, and titles the modal 'Comment on
profile' rather than 'Reply to post'.
2026-03-01 04:05:26 -06:00
Chad Curtis 930a64d965 Set compose modal title to 'Share to feed' when sharing external content 2026-02-28 21:27:09 -06:00
Chad Curtis 38c7e00ca9 Share button on /i/ page opens compose modal pre-filled with URL 2026-02-28 21:27:09 -06:00
Alex Gleason a03045ec85 Add Wall tab to user profiles with NIP-22 comments on kind 0
Wall posts are kind 1111 comments targeting the profile owner's kind 0
event (A tag: 0:pubkey:). Comments are filtered by the target user's
kind 3 follow list to show only posts from people they follow. Uses
the same ComposeBox/ReplyComposeModal pattern as /i/:uri routes.

If the profile owner has no follow list, an empty state is shown.
2026-02-28 17:10:06 -06:00
Alex Gleason 930e4dc006 Use FAB + full compose dialog for comments on external content pages
Widen ComposeBox.replyTo and ReplyComposeModal.event to accept URL,
enabling the standard post composer for NIP-22 comments on external
content. Replace the inline CommentForm on /i/ pages with a FAB that
opens ReplyComposeModal, giving users the full compose experience
with file uploads, emoji picker, and content warnings.
2026-02-27 23:45:27 -06:00
Alex Gleason 439ab94ea3 Merge branch 'main' of gitlab.com:soapbox-pub/ditto-mew 2026-02-23 20:19:22 -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
Mary Kate Fain 379282ecea Fix horizontal overflow on posts with links when reposting
- Add overflow-hidden to NoteCard article elements in both normal and
  threaded layouts to clip content that exceeds card width
- Add overflow-hidden to NoteContent root div to prevent link preview
  cards and embedded content from pushing beyond container bounds
- Strip .xdc URLs in EmbeddedNote content preview (was missing from
  the media URL regex, causing raw long URLs to render in quote embeds)
- Add overflow-hidden to EmbedContentPreview paragraph for defense
  against long unbreakable strings
- Use disableEmbeds on NoteContent inside ReplyComposeModal's embedded
  post preview so URLs render as plain links instead of full preview
  cards that overflow the clamped container
- Add attachment indicator chips to EmbeddedNote (images, videos, apps,
  links) so stripped media URLs still have a visible presence
2026-02-23 16:46:49 -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
shakespeare.diy f43132b656 Remove border between modal title and content
- Removed border-b from modal header for cleaner look

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-19 06:53:14 -06:00
shakespeare.diy d3d6d56e49 Move preview toggle to top of compose modal
- Moved Edit/Preview toggle from toolbar to modal header
- Added controlled preview mode to ComposeBox component
- Toggle now appears next to close button in modal header
- Added border-bottom to header for visual separation
- ComposeBox can be controlled externally or use internal state
- Fixes layout issues and improves UX in modal

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-19 06:52:45 -06:00
shakespeare.diy ba43340e8c Fix quote posts being treated as replies
- When quotedEvent is present, don't pass event as replyTo in ComposeBox
- This ensures quote posts are published as kind 1 with q tags, not replies
- Repost (kind 6) was already working correctly

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 17:55:15 -06:00
shakespeare.diy 3f19edd7a1 Implement quote posts and removable embeds in compose box
- Added quotedEvent prop to ComposeBox for quote post support
- Auto-detect and display embeds: nevent, note, naddr, and link previews
- Add remove button (X) to clear any embed from compose
- Quote posts open ReplyComposeModal with quoted event embedded
- Updated RepostMenu to open quote dialog instead of toast
- Added NIP-18 quote tags (q tag) when publishing quotes
- Embeds shown at bottom of compose with EmbeddedNote/EmbeddedNaddr/LinkPreview
- Support for manually typed nostr: URIs in compose content
- Invalidate event stats after quote to update counts

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 17:39:18 -06:00
shakespeare.diy 9a375f3d3d Unify new post and reply into a single ComposeModal
ReplyComposeModal now handles both cases: when an event is passed it's a
reply (shows embedded post preview), when no event is passed it's a new
post. FloatingComposeButton reuses ReplyComposeModal instead of having
its own duplicate dialog.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:24:30 -06:00
shakespeare.diy 42446fe0c7 Move X close button to the right side on all compose/reply/interaction modals
Updated ReplyComposeModal, FloatingComposeButton, and InteractionsModal
to place the title on the left and the dismiss X button on the right,
matching the standard dialog layout pattern.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:22:50 -06:00
shakespeare.diy 7cdbf4a6e6 Add reply compose modal with embedded original post preview
- Created ReplyComposeModal component that shows the original post embedded
  in a compact card above the compose area, matching the reference design
- Updated ComposeBox to accept replyTo, forceExpanded, and hideAvatar props
- ComposeBox now generates proper NIP-10 reply tags (root/reply markers,
  p tags for thread participants)
- Wired reply buttons in NoteCard and PostDetailPage to open the modal
- Reply success invalidates both feed and replies query caches

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 21:35:26 -06:00