Commit Graph

56 Commits

Author SHA1 Message Date
Alex Gleason 6d71fcaa45 Move image quality setting to Network Settings page
Remove the inline toggle from the post composer toolbar and add
imageQuality to AppConfig instead. The setting now lives in
Settings > Network under 'Image Uploads' with a Compressed/Original
pill toggle, persisted to localStorage like other app settings.
2026-03-23 00:44:30 -05:00
Alex Gleason 4b1f015d97 Include kind 62 vanish events in the home feed
Register kind 62 in the EXTRA_KINDS feed system so Request to Vanish
events from followed users appear in the home feed. Enabled by default
via the feedIncludeVanish toggle, and can be disabled in feed settings.
2026-03-20 23:35:50 -05:00
Alex Gleason d0f458f985 Go back to using Shakespeare's corsProxy (we don't even use it in Ditto yet) 2026-03-20 19:14:13 -05:00
Alex Gleason d92be3e341 Swap out default favicon and link-preview APIs 2026-03-20 16:23:50 -05:00
Alex Gleason 8a6b524e85 Update default corsProxy 2026-03-20 16:09:18 -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
Dirk Rost b9c590598d Merge main into feature/development-feed and fix lint issues
Resolve merge conflicts from badges, books, help, and emojis rename.
Fix biome lint: add type="button" to all buttons, use template literals,
format new components with project conventions.
2026-03-13 16:34:36 -05:00
Alex Gleason b3b2e4f077 Move Plausible config into AppConfig (supports .env and ditto.json) 2026-03-11 14:35:47 -05:00
Derek Ross 04fa292fbb Add Nostr Badges (NIP-58) as a new content type
Implement badge definitions (kind 30009) and profile badges (kind 30008)
as a new Whimsy content type with feed page, NoteCard rendering, sidebar
entry, dedicated detail page with awardee list, and a Badges core profile
tab showing a user's accepted badges with links to badge definitions.
2026-03-08 17:46:13 -04:00
Chad Curtis c7f3211b7d Add user lists, follow packs, home feed tabs, and list-based feed filtering
- Add NIP-51 Follow Sets management (useUserLists, UserListsPage at /lists)
- Add Follow Packs support (useFollowPacks) for curated people lists
- Add FeedEditModal for creating/editing home feed tabs with author scope,
  kind picker, and list/pack author population
- Add AddToListDialog accessible from the note more-menu
- Unify home feed tab resolution with profile tabs via useResolveTabFilter,
  supporting $follows variable expansion
- Wire People filter in Search and FeedEditModal with list/pack picker
- Extract shared ScopeToggle, ListPackPicker, parseSelectedKinds primitives
  into SavedFeedFiltersEditor to eliminate duplication across three call sites
- Cache savedFeeds in AppConfig for instant tab render on load
- Strip orphaned profile-destination entries from encrypted settings on read
2026-03-06 17:23:47 -06:00
Alex Gleason 35bc1a0438 Add configurable homepage route and show all items in mobile sidebar
- Add homePage config field (default: 'feed') that determines which
  sidebar item renders at the '/' route
- Any sidebar item can be set as the homepage via Feed settings
- The feed is always accessible at /feed when not configured as home
- Normalize sidebar item IDs: every item follows path === '/' + id
  (feed path changed from '/' to '/feed', emoji-packs renamed to emojis)
- Remove BOTTOM_NAV_ITEMS filter from MobileDrawer so all sidebar
  items are visible on mobile (feed, notifications, search included)
- Mobile bottom nav dynamically reflects the configured homepage icon
- Homepage setting syncs across devices via encrypted settings
- Add emoji-packs -> emojis migration for existing sidebar orders
2026-03-05 15:23:43 -06:00
Alex Gleason f1191299e8 Add Sentry integration with lazy loading and user-configurable DSN
Sentry SDK is loaded via dynamic import() only when a DSN is configured
and error reporting is enabled, keeping it out of the initial bundle.
Users can control error reporting via a toggle and DSN field in
Advanced Settings, with the DSN synced across devices via encrypted
NIP-78 settings. The ErrorBoundary now reports fatal crashes to Sentry
with component stack context, and a beforeSend hook censors nsec
private keys before any data leaves the browser.
2026-03-03 17:25:14 -06:00
Derek Ross 1cbb7b7428 Add Development feed with NIP-34 git repos, patches, PRs, custom NIPs, and app submissions
New 'Development' section under Other Stuff in Content Settings that
aggregates developer-focused Nostr content: git repository announcements
(kind 30617), patches (kind 1617), pull requests (kind 1618), custom
NIP proposals (kind 30817), and app submissions (kind 31733).

Adds /dev route using KindFeedPage with external links to Gitworkshop
and NostrHub. Five new card components render each kind in the feed.
2026-03-03 13:23:34 -05:00
Mary Kate Fain 1098057905 Merge main into feat/nip-38-user-statuses
Resolve merge conflicts in 5 files, keeping both NIP-38 user statuses
and music/podcasts/events features from main:
- src/App.tsx
- src/contexts/AppContext.ts
- src/lib/extraKinds.ts
- src/lib/schemas.ts
- src/test/TestApp.tsx
2026-03-01 23:33:51 -06:00
Mary Kate Fain d46ce9d012 Merge origin/main into feature/music-podcasts
Resolve conflicts in AppRouter, NoteCard, sidebarItems, and PostDetailPage
by keeping both music/podcast features and main's additions (books,
calendar events).
2026-03-01 23:26:54 -06:00
Derek Ross bac91af1f8 Add user statuses to Settings > Content as a display toggle
Register kind 30315 in extraKinds as a feedOnly entry with showKey
(not feedKey) so statuses appear as a toggle in Other Stuff > Social
but are NOT included in the main feed query. The toggle controls
whether statuses are displayed on NoteCard author rows and profile
pages.

- extraKinds: registered with showKey='showUserStatuses', feedOnly=true
- ContentSettings: handle feedOnly entries with showKey as display toggles
- NoteCard: gate useUserStatus behind feedSettings.showUserStatuses
- ProfilePage: gate status display behind feedSettings.showUserStatuses
- Defaults: showUserStatuses=true (enabled by default)
2026-03-02 00:06:05 -05:00
Mary Kate Fain ba4ddff11b Merge remote-tracking branch 'origin/main' into feat/nip-52-calendar-events
# Conflicts:
#	src/AppRouter.tsx
#	src/components/InitialSyncGate.tsx
#	src/components/NoteCard.tsx
#	src/lib/sidebarItems.tsx
2026-03-01 23:01:39 -06:00
Derek Ross 6f31a681d7 feat: add podcast and music 2026-03-01 23:59:57 -05:00
Mary Kate Fain 068b3a667b Merge remote-tracking branch 'origin/main' into emoji-packs
# Conflicts:
#	src/components/NoteCard.tsx
#	src/contexts/AppContext.ts
#	src/lib/sidebarItems.tsx
#	src/test/TestApp.tsx
2026-03-01 22:13:51 -06:00
Mary Kate Fain 84d69b4426 Merge remote-tracking branch 'origin/feat/nip-30-custom-emoji-picker' into emoji-packs
# Conflicts:
#	src/App.tsx
#	src/components/ComposeBox.tsx
#	src/components/EmojiPicker.tsx
#	src/components/InitialSyncGate.tsx
#	src/components/QuickReactMenu.tsx
#	src/contexts/AppContext.ts
#	src/lib/schemas.ts
#	src/lib/sidebarItems.tsx
#	src/test/TestApp.tsx
2026-03-01 22:02:03 -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
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
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
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
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
Alex Gleason d0b49e78b6 Add appId/client config, use appName for client tags and zap comments
- Remove defaultZapComment config; derive from appName instead
- Add appId (string) for NIP-78 d-tag prefixes (e.g. ${appId}/metadata)
- Add client (optional NIP-89 addr) as third element of client tags
- Update useNostrPublish and useEncryptedSettings to use config.appName
  and config.client for client tags instead of location.hostname
- Replace hardcoded 'ditto-metadata' d-tag with ${config.appId}/metadata
- Remove Default Zap Comment setting from AdvancedSettings UI
2026-03-01 13:44:31 -06:00
Chad Curtis eaa337de01 Fix missing followsFeedShowReplies in FeedSettings literals 2026-02-28 20:59:56 -06:00
Alex Gleason 713bf52cfb Add configurable appName to AppConfig, replacing hardcoded 'Ditto' in page titles and UI text
All runtime references to 'Ditto' now use config.appName, which defaults
to 'Ditto' and can be overridden at build-time via ditto.json. This
covers useSeoMeta titles across all pages, the welcome screen, feed CTA,
Nostr Connect app name, encrypted settings event title, and the
AdvancedSettings zap comment placeholder.
2026-02-28 17:09:37 -06:00
Alex Gleason 01b071d1c3 Add PUBLIC_DIR env var to merge external public files at build time
Files in the external directory take precedence over the built-in
public/ directory. Works in both dev (middleware) and build (post-copy)
modes. Also fix missing magicMouse property in TestApp.
2026-02-28 15:29:29 -06:00
Alex Gleason 6248b584e3 Rename 'active themes' to 'profile themes' in feed settings and labels 2026-02-27 16:07:58 -06:00
Alex Gleason e423cc8ec1 Render theme events (kind 16767/36767) as feed posts with full interactions
Migrate themes from a standalone card to the standard NoteCard rendering
pattern (like treasures), so theme events appear as interactive posts
with reply, repost, reaction, and zap buttons.

- Create ThemeContent component for inline theme color preview
- Add ThemeHeader for 'shared a theme' / 'updated their theme' labels
- Support both kind 36767 (definitions) and 16767 (active themes) in feeds
- Convert extraKinds themes entry to use subKinds pattern with toggles
- Create ThemesPage wrapper (like TreasuresPage) for sub-kind filtering
- Update ContentSettings to sync both sub-kind feed toggles
2026-02-27 15:58:05 -06:00
Alex Gleason 8fae0cf97a Add /webxdc feed page and sidebar menu item
Query NIP-94 kind 1063 events filtered by #m tag for
application/x-webxdc MIME type. Includes infinite scroll,
pull-to-refresh, embedded webxdc launcher, and onboarding
content selection.
2026-02-26 22:21:33 -06:00
Alex Gleason 14f75ed50d Add auto-share theme toggle: automatically publish custom theme changes to profile 2026-02-26 19:53:46 -06:00
Mary Kate Fain bac31a5b6d Add profile theme sharing: publish kind 30203, scoped themes on profiles, feed cards, and content settings 2026-02-25 13:49:55 -06:00
Mary Kate Fain b8d7d8a730 Redesign sidebar navigation with section grouping, customization, and mobile consistency
- Desktop: Remove redundant Home/Search nav items (logo serves as Home, inline
  search covers both quick lookup and full search page navigation)
- Add visual section grouping with labeled separators (Explore, You, Settings)
- Replace ugly dashed 'Add' button with subtle 'More...' inline link
- Add edit mode with drag-and-drop reordering (@dnd-kit) and remove buttons
  for content-type items in the Explore section
- Hover-to-remove on desktop content-type items outside edit mode
- Mobile: Replace avatar menu trigger with standard hamburger icon
- Mobile: Add search icon to top bar right side
- Mobile: Redesign bottom nav as 4-tab layout (Home, Explore, Notifications, You)
- Mobile: Explore tab opens bottom sheet with content type links (vaul Drawer)
- Mobile drawer: Replace profile header with logo, restructure to match desktop
  sections, add 'Manage...' link for settings, remove redundant Profile link
- Add sidebarOrder to AppConfig for persisting custom item order
- Extend useFeedSettings hook with orderedRoutes, addToSidebar, removeFromSidebar
2026-02-25 08:54:37 -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 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
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
Alex Gleason f453df10a0 Replace CORS proxy HTML scraping with configurable OEmbed link preview endpoint
Link previews now fetch from a dedicated link preview service (default:
https://fetch.ditto.pub/link/{url}) that returns OEmbed JSON, instead of
fetching raw HTML through a CORS proxy and parsing OG tags client-side.

- Add linkPreviewUrl config with RFC 6570 URI template support
- Rewrite useLinkPreview to consume OEmbed responses
- Update LinkPreview to render OEmbed fields (thumbnail_url, provider_name, etc.)
- Use ExternalFavicon component for link preview favicons (consistent with rest of app)
- Add linkPreviewUrl setting to Advanced Settings UI
- Generalize faviconUrl.ts into templateUrl() with {url} variable support
2026-02-21 16:28:23 -06:00
Alex Gleason 325fd02d3b Switch to my link worker for favicon fetching 2026-02-21 16:07:36 -06:00
Alex Gleason 0c583d19af Fix CI: resolve ESLint errors and Node.js 22 localStorage test failures 2026-02-21 15:25:18 -06:00
Alex Gleason cfb5659020 Replace DomainFavicon with ExternalFavicon using configurable favicon URL template
The old DomainFavicon component had a multi-step fallback chain (HTML scraping,
direct URL guessing, then the configured provider) which meant the configurable
setting was almost never reached. The new ExternalFavicon component uses the
configured favicon URL template directly via RFC 6570 URI templates.

- Rename config field faviconProvider -> faviconUrl
- Add faviconUrl() utility with uri-templates for RFC 6570 support
- Remove local Favicon component from ProfileRightSidebar
- Update all consumers to use ExternalFavicon
2026-02-21 15:14:30 -06:00
Chad Curtis ffc7672183 Add Magic: The Gathering deck lists as extra kind (NIP-MG, kind 37381)
Support kind 37381 addressable events for MTG deck sharing per NIP-MG spec.
Includes MagicDeckContent component with card list rendering, format/archetype
badges, commander/companion display, sideboard, foil indicators, and
expand/collapse for large decks. Adds /decks route and sidebar navigation.
2026-02-21 05:03:46 -06:00
Chad Curtis 9074c9b763 Move articles to Media section with sidebar/page toggle
Articles (kind 30023) now have both a showArticles sidebar toggle and
feedIncludeArticles feed toggle, matching the pattern of other content
types like Vines and Streams. Added FileText icon to all icon maps.
2026-02-21 01:06:41 -06:00
Chad Curtis 1e9bd782aa Add Notes section for feed content organization (posts, reposts, articles)
- Add 'feed' section to EXTRA_KINDS for Posts (kind 1), Reposts (kind 6),
  and Articles (kind 30023) as feed-only toggles
- Add feedIncludePosts, feedIncludeReposts, feedIncludeArticles to FeedSettings
  (posts and reposts default to enabled, articles disabled)
- Add 'Notes' collapsible section in ContentSettings above 'Other Stuff'
- Feed kinds are now fully dynamic from settings instead of hardcoded
- Repost unwrapping accepts any event kind, not just kind 1
- Add article (kind 30023) card rendering with title, image, and summary
- Update all feed hooks for consistency (useFeed, useProfileFeed,
  useStreamPosts, DomainFeedPage, HashtagPage)
2026-02-21 00:36:58 -06:00
Chad Curtis eb483469bb Add NIP-36 content warning support with blur/hide/show settings
Respect content-warning tags on events. Users can choose how to handle
them in Settings > Content > Sensitive Content:

- Blur (default): Shows a grey placeholder overlay with the warning
  reason in quotes. Media is not loaded until the user clicks reveal.
- Hide: Removes content-warned posts from the feed entirely.
- Show: Ignores content warnings and displays everything normally.

The setting syncs across devices via encrypted NIP-78 settings.
2026-02-20 16:45:33 -06:00
Chad Curtis 4882a90403 Add NIP-53 live stream support with HLS player and live chat
Implement kind 30311 live streaming events: HLS video player (hls.js),
kind 1311 live chat with real-time subscriptions, stream detail page with
collapsible description on mobile, desktop sidebar chat, streams feed page,
and full extra-kinds integration with sidebar nav and settings.
2026-02-20 14:52:48 -06:00
Chad Curtis 3e7ba143f9 Add user-configurable settings for Blossom servers, zap comment, favicon provider, CORS proxy, and NIP-46 relays
- Add blossomServers (array), defaultZapComment, faviconProvider, corsProxy to AppConfig
- Blossom servers: multi-server support with add/remove UI matching relay list pattern
- Default zap comment changed from 'Zapped with MKStack!' to 'Zapped with Mew!'
- NIP-46 nostrconnect now uses the user's write relay list instead of hardcoded relay
- CORS proxy and favicon provider use {href} URI template pattern
- New 'System' section in Advanced Settings for zap comment, favicon provider, CORS proxy
- Fix ghost button hover text color on light/pink themes across settings panels
- Fix pre-existing TSC errors: appRelays array typing, muteHelpers dead code, ProfilePage FeedItem type, EditProfileForm useFieldArray, FeedSettingsForm/ContentSettings feedKey narrowing, LeftSidebar icon type
2026-02-19 17:51:51 -06:00