Commit Graph

570 Commits

Author SHA1 Message Date
Chad Curtis f64ef2aed7 Fix outro wording: weird -> fun 2026-02-20 22:08:19 -06:00
Chad Curtis d5772de200 Revise outro text to be warmer and more playful 2026-02-20 22:06:50 -06:00
Chad Curtis f279b456c0 Shorten outro text 2026-02-20 22:06:37 -06:00
Chad Curtis c17815ea0b Add follow packs step and sentimental outro to onboarding
After saving settings, onboarding now checks the user's kind 3 follow
list. If empty, it shows suggested follow packs (starting with
naddr1qvzqqqyckypzpyexz3t34l966ngh5xg7u2q788hthdqmj0av3lv8s2tz9t43zt6d)
with member avatars and a Follow All button. Users with an existing
follow list skip this step.

The final step is now a warm outro thanking the user and inviting them
into the app, replacing the old spinner-only done screen.
2026-02-20 22:06:04 -06:00
Chad Curtis 1c640e3202 Use ChestIcon for treasures in onboarding content picker 2026-02-20 21:56:20 -06:00
Chad Curtis 3bcbd53100 Use lucide icons in onboarding and disable follow packs by default
Replace emoji icons with lucide-react components (Clapperboard, BarChart3,
MapPin, Palette, Users, Radio) in the content type picker. Remove follow
packs from the default selection for new users.
2026-02-20 21:53:29 -06:00
Chad Curtis ff43177aa5 Decrypt and apply encrypted settings before releasing sync overlay
useInitialSync now fetches the kind 30078 event, decrypts it with the
user's NIP-44 signer, and applies theme/feedSettings/contentWarningPolicy
to the config before transitioning out of the sync screen. It also seeds
the TanStack query cache so useEncryptedSettings and NostrSync don't
redundantly re-fetch or re-decrypt the same event.
2026-02-20 21:49:44 -06:00
Chad Curtis 726af608a0 Add initial sync screen with setup questionnaire for new devices
When a user logs in, show a sync spinner while fetching their settings
from Nostr relays. If existing settings are found (returning user on a
new device), apply them and proceed. If no settings exist (fresh account),
walk through a brief questionnaire for theme, content preferences, and
content safety policy. Uses sessionStorage to avoid re-showing on refresh.
2026-02-20 21:47:25 -06:00
Chad Curtis 7bd397a68b Fix theme not applying to feed/tabs until refresh
The body had an inline background style from the preloader that
overrode CSS variables. Now main.tsx removes the inline style
after React mounts, letting Tailwind's bg-background class take
over so theme changes apply instantly.
2026-02-20 21:31:13 -06:00
Chad Curtis 190a0dba9b Optimize feed load performance: caching, code splitting, and instant rendering
- Cache follow list and author profiles in localStorage for instant feed on return visits
- Prefetch profile images via <link rel=preload> for instant avatar rendering
- Replace Radix Avatar with lightweight component that renders <img> immediately
- Lazy-load route components (React.lazy) reducing main bundle from 1.7MB to 920KB
- Dynamic import hls.js (1.3MB) only when visiting stream pages
- Remove unused Buffer polyfill
- Add pre-React loading spinner in index.html outside #root for seamless handoff
- Fix 3-5s feed rerender caused by NostrSync relay/settings sync
- Fix Zod 4 strict mode rejecting feedSettings with extra/missing keys from localStorage
- Fix useLocalStorage skip update when value reference unchanged
- Reduce eoseTimeout from default to 600ms
2026-02-20 21:23:07 -06:00
Chad Curtis 87173f8432 Truncate long display names on profile page header 2026-02-20 18:28:29 -06:00
Chad Curtis 60a23aa0b3 Fix reply context overflow breaking sticky nav on mobile
Long unbroken names (raw npubs used as display names) in 'Replying to'
overflowed the container, pushing the page wider than the viewport and
making sticky/fixed nav elements scroll off-screen horizontally.

Truncate author names at 200px, add overflow-hidden on the container,
and shrink-0 on static text to prevent wrapping issues.
2026-02-20 17:59:06 -06:00
Chad Curtis 6066b5ec49 Replace polling notification system with persistent WebSocket subscription
Replaces the AlarmManager-based polling (wake every 60s, open/close WebSocket
connections) with a persistent WebSocket subscription to a Nostr relay. Events
are delivered in real-time via the open connection. A partial WakeLock keeps
the connection alive through Doze mode (same approach as Signal without FCM).

- Add NotificationRelayService: foreground service with persistent WebSocket,
  exponential backoff reconnection, network-aware reconnect, relay rotation
  on failure, and SharedPreferences config listener
- Refactor NostrPoller into notification dispatcher with metadata caching
  (SharedPreferences-based, avoids redundant WebSocket connections for
  repeat authors)
- Remove NotificationService (AlarmManager scheduler) and PollAlarmReceiver
  (WakeLock-based polling)
- Remove SCHEDULE_EXACT_ALARM permission (no longer needed)
- Disable web-layer background refetch on native (persistent connection
  handles it)
2026-02-20 17:43:26 -06:00
Chad Curtis afa7ede1c9 Respect content warning policy in profile media grid
CW media squares show a blurred placeholder with a shield icon instead
of loading the actual image/video. When policy is 'hide', CW media is
excluded from the grid entirely.
2026-02-20 17:01:26 -06:00
Chad Curtis 9b0313f83f Match CW settings layout to other settings rows: label left, radio right 2026-02-20 16:57:42 -06:00
Chad Curtis 469dd406d7 Contain blur within rounded box, don't let it bleed outside 2026-02-20 16:55:18 -06:00
Chad Curtis e41ce2e10b Fix content warning overlay: move overlay outside overflow-hidden container and check NIP-32 l tags for CW reason 2026-02-20 16:54:09 -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 3314f01b5e Fix failing tests and ESLint config
- Update NoteContent tests to use inline URLs (mid-sentence) instead of
  end-of-line URLs that render as LinkPreview cards without accessible links
- Update mention styling assertion from text-gray-500 to text-muted-foreground
  to match the actual NostrMention component classes
- Add android/ to ESLint ignores to prevent linting build output artifacts
2026-02-20 15:20:18 -06:00
Chad Curtis 5bbbc5022a Fix mobile live stream layout: viewport-locked chat above bottom nav
Lock main element to viewport height on mobile with body scroll disabled,
collapsible description with author under details, zap button inline with
title, and chat input sitting directly above the bottom nav with no gaps.
2026-02-20 15:14:05 -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
Alex Gleason ee9a1e34c3 Always route search queries to relay.ditto.pub (for now) 2026-02-20 00:11:03 -06:00
Alex Gleason 77ff88c2f6 Render NIP-30 custom emoji in all remaining display name locations
Apply EmojifiedText to mentions inside embedded/quote posts,
embedded note author names, and all other secondary UI locations
where display names were still rendered as plain text.
2026-02-19 21:43:56 -06:00
Alex Gleason 6180bbf0c3 Fix 30 ESLint errors: remove unused imports/variables, replace any types, use const 2026-02-19 20:14:01 -06:00
Alex Gleason be7cfbab67 Render NIP-30 custom emoji in display names, post text, and bios
Add emojify/EmojifiedText utilities that replace :shortcode: patterns with
inline images using emoji tags from kind 0 and kind 1 events. Applied to
display names across NoteCard, PostDetailPage, ProfilePage, ProfileHoverCard,
InteractionsModal, NotificationsPage, and NoteContent @mentions. Also
emojifies about/bio text in ProfilePage and ProfileHoverCard.

Remove string-level truncation from getDisplayName to avoid breaking
shortcodes mid-pattern (CSS truncate handles visual overflow). Use
em-relative sizing and align-text-bottom for proper inline alignment.
2026-02-19 19:06:14 -06:00
Alex Gleason 7e3f104ace Fix NIP-30 custom emoji reactions rendering as raw :shortcode: text
Custom emoji reactions from kind 7 events with emoji tags were displaying
the raw shortcode text (e.g., ':soapbox:') instead of rendering the image.
Add custom emoji resolution throughout the reaction pipeline: data hooks
now extract emoji URLs from event tags, and all rendering locations
(ReactionButton, PostDetailPage stats, InteractionsModal, Notifications)
now display custom emojis as inline images.
2026-02-19 18:39:43 -06:00
Chad Curtis d58f4bb632 Resolve raw hex identifiers as event ID or pubkey in search and routing
Detect 64-char hex strings in the search bar and NIP19Page route.
Query relays to check if the hex is an event ID first, then fall back
to treating it as a pubkey if a kind-0 profile is found.
2026-02-19 18:17:56 -06:00
Chad Curtis 8fe07e65cc Add Nostr identifier detection in search and profile search, improve DomainFeedPage header
Detect NIP-19 and NIP-05 identifiers in the search bar and profile
search dropdown, navigating directly to the appropriate route instead
of performing a text search. Refactor DomainFeedPage header to use
back navigation, show user count inline, and match border styling.
2026-02-19 18:13:17 -06:00
Chad Curtis 223d8822a4 Fix NIP-05 resolution for leading @ prefix and case-insensitive name lookup 2026-02-19 18:08:01 -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
Chad Curtis 325e1b9be1 Remove verified badge, use brain icon for difficulty, put terrain next to difficulty 2026-02-19 17:11:38 -06:00
Chad Curtis a8b8243868 Use NoteContent for rich text rendering in polls and fix word-break overflow 2026-02-19 17:10:23 -06:00
Chad Curtis 4fd50d545f Remove sticky positioning from extra kind page headers 2026-02-19 17:06:32 -06:00
Chad Curtis 54b27e4c09 Include extra kinds in profile media grid, extract vine URLs from imeta tags 2026-02-19 17:05:05 -06:00
Chad Curtis 448c051e33 Include media-native kinds like vines in profile media tab filter 2026-02-19 17:02:28 -06:00
Chad Curtis 09d722ddd2 Add object-cover to VideoPlayer to fill container without borders 2026-02-19 17:00:36 -06:00
Chad Curtis 95c3a5accc Fix desktop compose to open modal, cache right sidebar data, render vine videos on detail page 2026-02-19 16:54:16 -06:00
Chad Curtis f125abeef8 Restore avatar in compact ComposeBox feed view 2026-02-19 16:42:25 -06:00
Chad Curtis 9f6022e5e9 Render link previews for end-of-line URLs, skeleton load notifications, use ImageGallery, match mobile tab heights
- Show link preview cards for URLs that end a line, not just standalone
  URLs; only suppress previews for URLs followed by more text on the
  same line
- Show skeleton placeholders on notifications page until the query has
  completed at least once instead of flashing 'No notifications yet'
- Add skeleton loading for author rows in notification cards while
  profile data loads
- Replace inline image <a> tags with ImageGallery component so clicking
  images opens the lightbox with navigation
- Match notification tab height/weight to feed tabs on mobile while
  preserving original desktop styling
2026-02-19 16:39:13 -06:00
Chad Curtis a484c8b95c Delay stats invalidation after publish to preserve optimistic updates
The relay needs time to index newly published events. Immediate
invalidation caused a refetch that returned stale counts, overwriting
the optimistic +1 and making the count briefly appear then vanish.
2026-02-19 16:21:14 -06:00
Chad Curtis 35422ec6bb Fix optimistic updates, show user reaction emoji, compact embeds, and unify repost menu
- Add true optimistic updates for reactions and reposts via setQueryData
  instead of only invalidating queries after publish
- Track user's own reaction per event and display their emoji in place of
  the Heart icon across feed, post details, and notifications
- Strip whitespace around block embeds and skipped media URLs to eliminate
  blank lines caused by whitespace-pre-wrap
- Only render link preview cards for standalone URLs; inline URLs in
  sentences render as plain clickable links
- Remove border-b separators and use fixed-height object-cover on preview
  images to eliminate gaps
- Tighten padding on EmbeddedNote and EmbeddedNaddr cards
- Use fixed-height object-cover for ImageGallery grid images
- Unify RepostMenu to use Popover on all screen sizes instead of Drawer
  on mobile
2026-02-19 16:19:19 -06:00
Chad Curtis 7aad043734 Replace Repeat2 with custom RepostIcon, style repost/treasure action headers 2026-02-19 16:04:16 -06:00
Chad Curtis ec8e71cb70 Fix action header height — use w-11 instead of size-11 for icon container 2026-02-19 15:48:29 -06:00
Chad Curtis b0ac1180dd Align repost/treasure action text with username column, icon in avatar column 2026-02-19 15:46:57 -06:00
Chad Curtis 1bc069a7bd Fix sticky page titles on mobile for bookmarks and kind feed pages 2026-02-19 15:43:05 -06:00
Chad Curtis aa231797af Add NIP-05 domain feeds, profile hover cards, gallery lightbox, and NIP-05 profile URLs
- Domain feed page at /timeline/:domain fetches .well-known/nostr.json and queries events from domain users
- NIP-05 domains are clickable in usernames throughout the app (Nip05Badge, NoteCard, PostDetailPage, etc.)
- @_@domain.com renders as @domain.com (underscore prefix hidden)
- Profile hover cards on avatars, usernames, and mentions across all components
- Clicking avatar/banner on profile page opens image in gallery lightbox with safe-area support
- NIP-05 verified users get clean profile URLs (e.g. /user@domain.com) instead of /npub1...
- NIP19Page unified dispatcher handles NIP-19, NIP-05, and profile routing at /:param
- Removed /u/:npub and /d/:domain routes in favor of root-level routing
- CORS proxy fallback for NIP-05 resolution on non-CORS-compliant servers
- Mobile top bar logo links to home
- Safe area fixes for gallery lightbox, mobile drawer, and sheet close button
2026-02-19 15:37:53 -06:00
Chad Curtis e9331a4a6c Move notification polling to native Java with AlarmManager
Replace JS WebView-based polling with pure native implementation:
- NostrPoller: Java WebSocket client that queries Nostr relays directly via OkHttp
- PollAlarmReceiver: AlarmManager fires every 60s, acquires WakeLock, runs native poll
- NotificationService: foreground service keeps process alive, schedules alarms
- MewNotificationPlugin: Capacitor plugin passes pubkey/relays from JS to SharedPreferences
- Remove notificationService.ts (all polling logic now in Java)
- Simplify useNativeNotifications to only configure native service + handle permissions
2026-02-19 12:10:13 -06:00
Chad Curtis 64726d2cf7 Add local WebSocket notification polling and Mew splash/notification icons
- Implement Signal-like local-only notifications via direct WebSocket relay polling
- Poll every 60s foreground, 15min background, no external push server
- Resolve NIP-05 display names for notification body (e.g. 'alice@nostr.com reacted to your post')
- Add Capacitor LocalNotifications plugin with POST_NOTIFICATIONS permission
- Replace default Capacitor splash with Mew logo PNG on dark background using Android 12 Theme.SplashScreen
- Add ic_stat_mew vector drawable for notification small icon
- Regenerate splash PNGs with #14161f background
2026-02-19 10:40:38 -06:00
Chad Curtis 9d6cfdd4ef Fix Search and Settings page sticky behavior and transparency
SearchPage:
- Change tabs background from bg-background/95 to bg-background/80 (matches Feed/Notifications)
- Remove autoFocus from search inputs to prevent page jump on click
- Change z-index from z-20 to z-10 (consistent with other pages)

SettingsPage:
- Remove sticky from Settings header (title and description)
- Keep only tabs sticky
- Change tabs background from bg-background/95 to bg-background/80
- Header now scrolls out of view naturally, tabs remain sticky
2026-02-19 08:07:40 -06:00
Chad Curtis 780271f3c1 Fix sticky headers to use top-mobile-bar pattern
- Change STICKY_HEADER_CLASS to use 'top-mobile-bar sidebar:top-0'
- Matches the pattern used in Feed and NotificationsPage
- On mobile: sticky tabs position below the MobileTopBar (accounting for safe area)
- On desktop: sticky tabs position at top-0 (no top bar on desktop)
- Fixes issue where safe-area-top created unwanted space above tabs
2026-02-19 08:03:08 -06:00