Commit Graph

4447 Commits

Author SHA1 Message Date
Chad Curtis 01932ff9cd include kinds 20/21/22 in search media filters and rename Vines to Shorts & Vines 2026-03-01 20:40:37 -06:00
Chad Curtis 5b0aa08df6 add kinds 21 and 22 to profile media query 2026-03-01 20:40:37 -06:00
Chad Curtis c8d198108f videos: horizontal scroll rows, fixed short thumb sizes, fetch 12/page 2026-03-01 20:40:37 -06:00
Chad Curtis 00f612e2f2 merge streams into videos page, remove streams sidebar entry 2026-03-01 20:40:37 -06:00
Chad Curtis ca8ceed831 add NIP-68 photos and NIP-71 videos with instagram/youtube style pages 2026-03-01 20:40:23 -06:00
Derek Ross cc3960354e Resolve kind 30030 emoji packs and fix picker theme for custom themes
Two fixes:

1. useCustomEmojis now resolves ['a', '30030:...'] references in the
   user's kind 10030 emoji list, fetching the referenced kind 30030
   emoji pack events and merging their emoji tags. Previously only
   inline emoji tags were extracted, missing subscribed packs.

2. EmojiPicker theme detection now reads the --background CSS variable
   lightness instead of checking for .dark class on <html>. Custom
   themes set class='custom' (not 'dark'), so the dark class check
   always returned false. Now works for all theme modes: light, dark,
   system, custom, and profile themes.
2026-03-01 21:38:10 -05:00
Mary Kate Fain 2a006145ca Add NIP-30 custom emoji packs support
- Sidebar: Add 'Emoji Packs' item linking to /emoji-packs feed (kind 30030)
- Feed: EmojiPackContent renders pack preview with emoji grid and add/remove button
- NoteCard: Kind 30030 events shown with SmilePlus header and pack content
- useUserEmojiPacks hook: Fetches user's kind 10030 list and resolves referenced
  kind 30030 packs into a flat emoji collection
- EmojiPicker: New 'Custom' tab shows user's NIP-30 emojis alongside native picker
- CustomEmojiPicker: Searchable grid of user's custom emojis grouped by pack
- ComposeBox: Custom emojis insert ':shortcode:' and add emoji tags to published events
- EmojiShortcodeAutocomplete: Suggests custom emojis alongside native ones as you type
- QuickReactMenu: Custom emoji reactions include NIP-30 emoji tags in kind 7 events
- Config: showEmojiPacks and feedIncludeEmojiPacks settings for sidebar/feed control
2026-03-01 20:36:53 -06:00
Alex Gleason 098ba92ae9 Fix off-by-one: use collapseAfter=0 to show exactly 1 ancestor post
collapseAfter=1 was allowing 2 posts before collapsing because the check
is depth >= collapseAfter, and the current depth's NoteCard always renders.
2026-03-01 20:35:22 -06:00
Alex Gleason 89d866fec8 Collapse ancestor chain to 1 post when focused event is a reaction
Add collapseAfter prop to AncestorThread. When set, ancestors beyond that
depth are hidden behind a 'Show earlier posts' button with a dotted thread
indicator. Reactions pass collapseAfter=1 so only the reacted-to post is
immediately visible.
2026-03-01 20:34:07 -06:00
Alex Gleason ce287f5e80 Show ancestor thread chain when navigating directly to a reaction event
The parentEventId was only computed for text notes (isTextNote), so kind 7
reactions never resolved their e-tag parent. Include isReaction in the
condition so the AncestorThread renders the reacted-to post above.
2026-03-01 20:32:07 -06:00
Alex Gleason b59b34a5c6 Fix reaction card alignment: center content against emoji bubble and use size-6 avatar
Add min-h-10 and flex items-center on the content side so the text line
vertically centers against the size-10 emoji bubble. Bump inline avatar
from size-5 to size-6 for better visual balance.
2026-03-01 20:29:36 -06:00
Alex Gleason 4774f0f079 Revert "Use avatar with emoji badge overlay for reaction cards in threads"
This reverts commit f58a0ceed4.
2026-03-01 20:28:17 -06:00
Alex Gleason f58a0ceed4 Use avatar with emoji badge overlay for reaction cards in threads
Replace the standalone emoji bubble with the user's normal avatar plus a
small reaction emoji badge at the bottom-right corner. This keeps the
avatar column aligned with other threaded posts while still making the
reaction visually distinct.
2026-03-01 20:18:10 -06:00
Mary Kate Fain e77849a78a Fix theme copy/edit losing background image and font
ThemeBuilderPage only tracked colors in local state, so importing,
editing, previewing, saving, and publishing a theme all dropped the
font and background properties. Now all code paths pass the full
ThemeConfig (colors + font + background) through applyCustomTheme
and into publishTheme/setActiveTheme.
2026-03-01 20:16:40 -06:00
Alex Gleason e6c971827b Flatten reaction card to a single-line layout for better vertical alignment
Move timestamp inline with name and remove the second row, so the emoji
bubble, avatar, name, 'reacted' label, and timestamp all sit on one line.
2026-03-01 20:14:25 -06:00
Alex Gleason aaae6b5893 Fix reaction emoji bubble alignment to match ancestor thread avatar column
Use size-10 in PostDetailContent to align with the threaded ancestor's
size-10 avatar, preventing a 4px horizontal offset of the thread line.
2026-03-01 20:12:34 -06:00
Alex Gleason 07a25874ae Render kind 7 reaction events as compact activity cards instead of posts
Reaction events now display with a prominent emoji bubble, small inline
avatar, author name, and 'reacted' label — making them visually distinct
from regular posts in both thread ancestors and standalone detail views.
2026-03-01 20:08:46 -06:00
Alex Gleason 616c2db094 Fix ditto-mew gitlab links 2026-03-01 20:03:26 -06:00
Derek Ross 209589e258 Revert "Broaden custom emoji query to include well-known profile relays"
This reverts commit f18e8aefae.
2026-03-01 20:39:11 -05:00
Derek Ross f18e8aefae Broaden custom emoji query to include well-known profile relays
Kind 10030 is a replaceable event that may only exist on relays the
user published to. The default pool (user's NIP-65 relays) may not
have it. Now queries both the default pool AND a broader set of
well-known relays (purplepag.es, relay.nostr.band, etc.) in parallel,
picking the most recent event across both sources.
2026-03-01 20:38:37 -05:00
Derek Ross f4069c7f47 Fix missing toggle for feedOnly entries with showKey in ContentSettings
The ContentTypeRow only rendered a Switch for entries with feedKey.
Entries with feedOnly=true and showKey (like Custom Emojis) had no
toggle rendered. Added a fallback branch that renders a Switch using
showKey for these display-only toggles.
2026-03-01 20:30:10 -05:00
Derek Ross addbece173 Add NIP-30 custom emoji picker support (kind 10030)
Integrate custom emojis from the user's kind 10030 emoji list into
the emoji picker, compose flow, reactions, and DMs:

Hook:
- useCustomEmojis: query kind 10030, extract emoji shortcode/url pairs

EmojiPicker:
- Accept customEmojis prop, render as dedicated 'Custom' tab via
  emoji-mart's custom categories feature
- Changed onSelect from string to EmojiSelection union type
  (native unicode | custom shortcode+url)

ComposeBox:
- Pass custom emojis to picker, insert :shortcode: on selection
- Scan content on publish for :shortcode: patterns, cross-reference
  against user's emoji list, add ['emoji', name, url] tags (NIP-30)

QuickReactMenu:
- Custom emoji reactions: content=':shortcode:', with emoji tag
- Optimistic cache update includes custom emoji URL/name

DMChatArea:
- Pass custom emojis to picker, insert :shortcode: text

Settings:
- Registered as 'Custom Emojis' in Other Stuff > Whimsy section
- showCustomEmojis toggle (default true) gates all custom emoji
  features — when disabled, no kind 10030 queries are made
- Fix pre-existing Bot icon missing import in sidebarItems
2026-03-01 20:28:08 -05:00
Alex Gleason 6033ed673d Add undo button to theme applied toast and allow clicking own themes 2026-03-01 18:30:51 -06:00
Derek Ross 13dcad1070 Update events blurb to mention creating events on Plektos 2026-03-01 19:29:12 -05:00
Derek Ross c307056e2f Use red badge for 'Can't Go' RSVP status in Activity tab 2026-03-01 19:27:01 -05:00
Alex Gleason c6ccdd3e31 Make theme mockup click-to-apply instead of copy button with redirect 2026-03-01 18:26:52 -06:00
Derek Ross 2e46d10755 Show all RSVP statuses in Activity tab, not just 'Going'
Activity feed now shows accepted, tentative, and declined RSVPs with
status-specific display:
- accepted: 'is going to' + green 'Going' badge
- tentative: 'might go to' + amber 'Maybe' badge
- declined: 'can't make it to' + muted 'Can't Go' badge

Previously only accepted RSVPs were shown, filtering out potentially
useful social signal from the follow list.
2026-03-01 19:26:35 -05:00
Derek Ross 4a16b0b223 Hide activity items when the referenced event couldn't be fetched
RSVPs whose calendar event fails to load from relays showed as
orphaned 'Alice is going to an event' headers with no event card
below. Now filtered out — only items with a successfully fetched
referenced event are displayed.
2026-03-01 19:24:01 -05:00
Derek Ross 4e0ae14242 Auto-paginate Activity tab when first pages have no accepted RSVPs
The relay pool returns non-deterministic results — sometimes the first
batch of 50 kind 31925 events contains only declined/tentative/malformed
RSVPs with zero accepted ones. The UI showed an empty state because the
scroll sentinel was never rendered, so the next page never fetched.

Now auto-fetches up to 5 additional pages when the accumulated results
have zero accepted RSVPs, ensuring we dig through the relay's data
before giving up.
2026-03-01 19:23:08 -05:00
Derek Ross 1e40024100 Include kind 31922 in general feed when events toggle is on
The events entry in extraKinds only registered kind 31923 (time-based),
so date-based calendar events (kind 31922) were missing from the
general feed. Added extraFeedKinds field to ExtraKindDef and used it
to include 31922 alongside 31923 when feedIncludeEvents is enabled.
2026-03-01 19:20:15 -05:00
Alex Gleason 817a0077cf Add AI Chat as a sidebar item
Registers 'ai-chat' in SIDEBAR_ITEMS with the Bot icon, linking to
/ai-chat. Requires authentication since the Shakespeare API needs a
logged-in Nostr account.
2026-03-01 18:18:08 -06:00
Derek Ross 1875d1ad0a Remove Activity tab debug logging
The intermittent empty results were caused by relay non-determinism —
different relay responses returned different subsets of RSVP events.
The code logic is correct; the variability is expected with the Nostr
relay pool.
2026-03-01 19:17:54 -05:00
Alex Gleason d109e63740 Expand set_theme tool to support full ThemeConfig (colors, font, background)
The tool now accepts the complete theme configuration:
- Colors (required): background, text, primary as HSL strings
- Font (optional): any of the 17 bundled font families
- Background image (optional): URL with cover/tile mode

The system prompt, tool executor, and badge UI are all updated to
reflect the richer theme capabilities.
2026-03-01 18:15:19 -06:00
Derek Ross 341246ef6c Fix Activity tab showing 'no follows' while follow list is loading
Two bugs causing the Activity tab to appear empty:

1. The 'no follows' early return fired while useFollowList was still
   loading. followedPubkeys was undefined (loading), which made
   hasFollows false, showing 'Follow some people...' even when the
   user has follows. Now checks followsLoading before showing that
   message — falls through to skeleton loading state instead.

2. showSkeleton used rsvpQuery.isPending which in TanStack Query v5
   is true for disabled queries AND on query key changes (causing
   skeleton flash during refetch). Changed to rsvpQuery.isLoading
   which is only true during the actual first fetch, so stale data
   shows while refetching.
2026-03-01 19:11:04 -05:00
Alex Gleason db6d0ec721 Change set_theme tool to apply custom themes via CoreThemeColors
The tool now accepts background, text, and primary as HSL color strings
and calls applyCustomTheme to set a fully custom theme, rather than
just switching between light/dark/system presets.
2026-03-01 18:08:12 -06:00
Derek Ross a8afb9cd58 Fix Activity tab query stability
The follower-rsvps query was unreliable due to:

1. Stale closure: followedPubkeys was captured at render time but the
   queryKey only included the user pubkey, not the actual follow list.
   When the follow list loaded asynchronously, the queryFn could run
   with an empty or stale array. Now the queryKey includes a stable
   hash of the first 20 followed pubkeys so it re-runs when the
   follow list actually changes.

2. followedPubkeys defaulting to []: when followData was undefined
   (still loading), the default [] made hasFollows false, but on the
   next render when followData arrived, the query might not re-fetch
   because the stale cached result from the empty run was returned.
   Now followedPubkeys is undefined until loaded, and isReady properly
   gates the query.

The React warning about setState during render in useLayoutOptions is
a known pattern used by all pages and is not specific to EventsFeedPage.
2026-03-01 19:07:59 -05:00
Alex Gleason b6256ed03d Add AI chat page with theme-setting tool
Adds /ai-chat route with a Shakespeare AI chat interface that supports
OpenAI-compatible tool calling. Includes a set_theme tool that lets the
AI switch between light, dark, and system themes on the user's behalf.
2026-03-01 18:03:06 -06:00
Alex Gleason 3cb0ea7368 Add sort:hot to hashtag feed via Ditto relay NIP-50 search 2026-03-01 17:55:27 -06:00
Derek Ross 7ce754a84a Fix Activity tab reliability and RSVP deduplication
Three issues causing intermittent empty Activity tab:

1. Query key collision: Activity used ['event-rsvps', ...] which
   collided with useEventRSVPs hook. When the detail page invalidated
   event-rsvps caches, it wiped the activity feed too. Renamed to
   ['follower-rsvps', ...].

2. Pagination breaking on filtered results: fetched 30 RSVPs but
   filtered for accepted-only after. If a batch had mostly declined/
   tentative, getNextPageParam saw 0 results and stopped paginating.
   Now tracks rawCount separately and continues paginating as long as
   raw events were returned.

3. Missing author+event deduplication: multiple RSVP updates from the
   same user for the same event created duplicate activity items. Now
   deduplicates by pubkey+eventCoord, keeping the latest.

Also fixed usePublishRSVP to use a stable d-tag (the event coordinate)
so updating an RSVP replaces the previous one rather than creating a
new addressable event each time.
2026-03-01 18:47:37 -05:00
Derek Ross 2da7f79d3f Fix back button on CalendarEventDetailPage to use browser history
navigate('/') always went to home. navigate(-1) goes back to wherever
the user came from (events feed, profile, search results, etc.).
2026-03-01 18:41:43 -05:00
Derek Ross 76bf856737 Add NIP-52 calendar event support (kind 31922/31923) with RSVPs
Implement full calendar event rendering, dedicated events page, and
RSVP functionality for NIP-52 calendar events:

Registration:
- FeedSettings: showEvents + feedIncludeEvents toggles
- extraKinds: kind 31923 registered as 'events' in social section
  with link to plektos.app for event creation/management
- Sidebar: Events entry with CalendarDays icon at /events
- Onboarding: added to content picker, pre-checked by default

Components:
- CalendarEventContent: rich card with cover image, title, date/time,
  location, description, participant count, hashtags. Handles both
  kind 31922 (date-based) and 31923 (time-based) with Intl formatting
- CalendarEventDetailPage: full detail view with RSVP UI (Going/Maybe/
  Can't Go buttons + optional note), attendee sections with avatar
  stacks, participant roles, share button, zap support
- RSVPAvatars: reusable overlapping avatar stack with tooltips

Hooks:
- useEventRSVPs: query kind 31925 RSVPs for an event, deduplicate by
  author, group by status (accepted/declined/tentative)
- useMyRSVP: check current user's RSVP status for an event
- usePublishRSVP: publish kind 31925 RSVP with cache invalidation

Pages:
- EventsFeedPage: two-tab layout — Upcoming (calendar events from
  follows/global with future-first sorting) and Activity (social feed
  showing 'Alice is going to [Event]' from followed users' RSVPs)

Wiring:
- NoteCard: isCalendarEvent detection + CalendarEventContent dispatch
- PostDetailPage: routes kind 31922/31923 to CalendarEventDetailPage
- AppRouter: /events route
2026-03-01 18:39:10 -05:00
Alex Gleason 0107998856 Replace hardcoded TRENDS_PUBKEY with config.nip85StatsPubkey in useTrending hooks 2026-03-01 17:37:35 -06:00
Derek Ross 10fb41dec9 Add CalendarEventContent component for NIP-52 calendar events 2026-03-01 18:25:05 -05:00
Derek Ross ec898f3a3d Add NIP-52 calendar event RSVP hooks (kind 31925) 2026-03-01 18:25:00 -05:00
Chad Curtis 060f2c4628 Merge branch 'feat/nip-a0-voice-messages' into 'main'
Add NIP-A0 voice message support (kind 1222/1244)

See merge request soapbox-pub/ditto!19
2026-03-01 22:48:19 +00:00
Derek Ross b9301d4ad6 Include voice message kinds in reply, comment, and notification queries
Kind 1222 (voice reply to kind 1) was missing from useReplies, and
kind 1244 (NIP-22 voice reply) was missing from useComments. Voice
messages were published correctly but never appeared because query
filters didn't include their kinds.

- useReplies: [1] -> [1, 1222]
- useComments: [1111] -> [1111, 1244]
- useWallComments: [1111] -> [1111, 1244]
- VinesFeedPage: [1111] -> [1111, 1244]
- useNotifications: added 1222, 1244
- useHasUnreadNotifications: added 1222, 1244
- useNativeNotifications: added 1222, 1244 with 'New voice message' title
2026-03-01 17:38:01 -05:00
Derek Ross c14241832d Replace avatar play button with dedicated play/pause button in VoiceMessagePlayer
The avatar was confusing as a dual-purpose element. Now uses a clean
circular play/pause button with primary color theming, separate from
the author info already shown by NoteCard's header.
2026-03-01 17:32:33 -05:00
Chad Curtis 41807e677e Remove NIP-65 write relay lookup from profile feed
Simplifies useProfileFeed by removing the useProfileWriteRelays hook
and always querying the default pool instead of the user's write relays.
2026-03-01 21:46:29 +00:00
Derek Ross 239d958e1f Add NIP-A0 voice message support (kind 1222/1244)
Implement recording, publishing, and rendering of NIP-A0 voice messages:

- VoiceMessagePlayer: compact waveform bar player when imeta waveform
  data is available, falls back to existing AudioVisualizer sinewave
- useVoiceRecorder: MediaRecorder hook with real-time amplitude capture,
  60s max duration, and waveform sampling for NIP-A0 imeta tags
- ComposeBox: mic button in toolbar with recording UI (live waveform,
  timer, cancel/send controls), publishes kind 1222 (root) or 1244
  (NIP-22 reply) with imeta waveform and duration fields
- NoteCard + PostDetailPage: render kind 1222/1244 via VoiceMessagePlayer
- Feed settings: voice messages registered in Other Stuff > Media with
  feed toggle (feedIncludeVoiceMessages), defaults to off
2026-03-01 16:36:14 -05:00
Mary Kate Fain f729b07202 Fix NoteMoreMenu dialog overflowing viewport on long posts
Cap the dialog at 85dvh with overflow-y-auto so it scrolls when
content is tall. Also add a hard max-h on the post preview text
to prevent line-clamp-3 failures with nested block elements from
NoteContent.
2026-03-01 14:05:34 -06:00