Commit Graph

88 Commits

Author SHA1 Message Date
shakespeare.diy 9d95b10a48 Clean up debug logs from stream hook
The debug logs confirmed the stream IS working correctly:
- req() subscription opens successfully
- EOSE is received and subscription stays open
- New events arrive after EOSE
- Cleanup only happens when the preview environment reloads (replaceDocument)

Removed eoseTimeout from NPool in previous commit which was the
main fix for subscription lifecycle issues.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 01:02:21 -06:00
shakespeare.diy 67d523b260 Match bitmap/clawchat streaming pattern exactly, remove eoseTimeout
- Rewrote useStreamPosts to exactly mirror bitmap's useChatSession pattern
- Removed eoseTimeout: 200 from NPool config (not a valid NPoolOpts field,
  was potentially causing issues with subscription lifecycle)
- Uses AbortController directly (not useRef)
- fetchInitialMessages + subscribeToMessages run in parallel
- 30s timeout on initial fetch (matching bitmap)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 01:00:01 -06:00
shakespeare.diy d9d6e19ca0 Fix streaming: pass relays option directly to req() like clawchat does
- Pass `relays` array directly to nostr.req() and nostr.query()
  to bypass pool's reqRouter/eoseTimeout that was killing streams
- This is the pattern clawchat uses successfully for live subscriptions
- Default stream uses multiple relays, NIP-50 search uses relay.ditto.pub only
- Filter out future-dated events (created_at > now)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:57:41 -06:00
shakespeare.diy 99f922ea15 Fix streaming: use single relay instead of pool, filter future events
- Always use relay.ditto.pub directly for req() streaming
  (NPool's eoseTimeout: 200 was killing subscriptions prematurely)
- Filter out events with created_at in the future
- Matches clawchat pattern: fetchInitial + streamNew in parallel
- Both query() and req() go to same single relay

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:55:48 -06:00
shakespeare.diy 738b29f075 Fix streaming: run fetch + stream in parallel, use limit: 100 for req
- Match clawchat's proven streaming pattern
- fetchInitial() and streamNew() run in parallel, not sequentially
- req() uses limit: 100 (not limit: 0 which was wrong)
- Added isSubscribed guard for safe state updates
- Proper AbortError handling on both fetch and stream paths

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:53:27 -06:00
shakespeare.diy 87e1580c5a Fix streaming: query initial batch then req for live updates
- Step 1: query() with limit: 40 to fetch initial posts immediately
- Step 2: req() with limit: 0 + since: now to stream new posts live
- Fixes blank page issue (limit: 0 alone returns no stored events)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:52:09 -06:00
shakespeare.diy dcf0650eeb Fix streaming: use AsyncIterable API with AbortController, stream by default
- Rewrote useStreamPosts to use Nostrify's correct req() API which
  returns AsyncIterable, not a subscription object with .close()
- Uses AbortController to cancel streams on cleanup (fixes sub.close error)
- Streams posts by default with no search query (global kind:1 feed)
- When search query is provided, uses NIP-50 search on relay.ditto.pub
- Properly handles EOSE, CLOSED, and EVENT messages from the stream

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:51:12 -06:00
shakespeare.diy 9d3d62f7e6 Set stream subscription limit to 0 for proper real-time streaming
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:49:27 -06:00
shakespeare.diy c838a5337a Rewrite search page to match Ditto's exact layout
- Tabs (Posts/Trends/Accounts) at the very top, sticky
- Search input below tabs inside content area (icon on right)
- Search filters open by default with circled chevron toggle
- "Including replies" label + switch inline on same row
- Radio buttons laid out horizontally with flex-wrap
- "In the language:" label inline with dropdown
- Filter labels are bold (matching Ditto's white/bold style)
- Removed back arrow from header (Ditto doesn't have one)
- Accounts tab gets its own search input
- Posts stream live below filters

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:48:26 -06:00
shakespeare.diy 9bd46e93a8 Fix search page layout - move filters to collapsible section above content
- Removed broken sidebar-inside-main-column layout that squished content
- Filters now collapse/expand above the post results (matching Ditto's pattern)
- Smooth animated expand/collapse with chevron indicator
- Simplified empty states (plain text, no cards)
- Cleaned up unused useSearchPosts.ts (replaced by useStreamPosts)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:46:37 -06:00
shakespeare.diy 151746e7b2 Implement Ditto-style search page with live streaming posts
- Added Posts, Trends, and Accounts tabs
- Implemented sidebar search filters for Posts tab (replies, media type, language)
- Created useStreamPosts hook for real-time streaming subscriptions
- Search uses relay.ditto.pub for NIP-50 search functionality
- Posts stream in real-time with REQ subscription instead of static queries
- Layout matches Ditto design with filters in left sidebar on desktop
- All tabs functional with proper empty states

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:44:37 -06:00
shakespeare.diy e36bcad066 Fix profile header height to exactly match post composer (75px)
- Changed min-h from 84px to 75px to match actual ComposeBox height
- Both headers now have identical 75px height

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:37:32 -06:00
shakespeare.diy d899777776 Set profile header minimum height to match post composition
- Added min-h-[84px] to profile header
- Now matches ComposeBox total height (py-3 + textarea min-h-[44px] + py-2)
- Ensures consistent header heights across all pages

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:36:34 -06:00
shakespeare.diy b3aca61384 Match profile header height to post composition area
- Changed profile header padding from py-2 to py-3
- Now both headers have consistent 12px vertical padding
- Provides better visual alignment across pages

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:35:36 -06:00
shakespeare.diy f9635f9e29 Fix search autocomplete to show NIP-05 or npub, not both
- Show NIP-05 username if available
- Otherwise show npub with monospace font
- Removed the previous behavior of showing both username and NIP-05 separated by a dot
- Made npub slightly smaller (11px) with monospace font for better readability

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:33:29 -06:00
shakespeare.diy 0fe4ce47f1 Add "on Mew" to CTA copy for branding
- Updated CTA text to "Follow accounts you care about on Mew"
- Reinforces brand identity in the call-to-action

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:31:12 -06:00
shakespeare.diy 57df552a3f Make CTA more compact with better copy
- Reduced padding from py-6 to py-3 for more compact design
- Horizontal layout instead of vertical stacking
- Better CTA copy: "Follow accounts you care about"
- Smaller button size (sm) and simpler "Join" text
- Keeps gradient background but with better proportions
- More balanced and less overwhelming

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:30:21 -06:00
shakespeare.diy 8408bdbb9f Redesign CTA with centered, more prominent layout
- Center-aligned design for better visual balance
- Gradient background (primary/5 to primary/10) for subtle depth
- Larger, more prominent "Join Mew" button with shadow effects
- Engaging copy: "Join to unlock your personalized feed "
- Increased padding and spacing for breathing room
- More visually appealing and less boring design

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:29:31 -06:00
shakespeare.diy d879f3b363 Improve CTA styling with emphasis and better copy
- Change to "Join Mew to follow accounts & personalize your feed"
- Add emphasis with bold "Join Mew" in foreground color
- Use medium font weight for better visual hierarchy
- Make Join button smaller (sm size) for better balance
- More engaging and visually distinct CTA

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:28:30 -06:00
shakespeare.diy 46cea34669 Shorten CTA statement to be more concise
- Changed "Join Mew to personalize your feed and connect with others" to "Join to personalize your feed"
- More concise and direct call-to-action

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:27:59 -06:00
shakespeare.diy bb0161df47 Replace tabs with call-to-action for logged-out users
- Show Follow/Global tabs only when user is logged in
- Display CTA banner with Join button when logged out
- CTA message: "Join Mew to personalize your feed and connect with others"
- Join button triggers login dialog in Feed component
- Added LoginDialog and SignupDialog to Feed component
- Improves UX with clear call-to-action instead of empty tab bar

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:27:26 -06:00
shakespeare.diy 403e1a8d6b Hide Follow/Global tabs when user is logged out
- Import useCurrentUser hook to check login status
- Conditionally render tabs only when user is logged in
- Change default tab to 'global' for logged-out users
- Improves UX by showing only relevant UI elements based on auth state

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:25:54 -06:00
shakespeare.diy 3d3ac7fa19 Update LoginDialog to match borkstr format with signup link
- Added onSignupClick prop to LoginDialog interface
- Added "New here? Create account" link in LoginDialog
- Link appears after extension login button (if available) or with other options
- Matches borkstr's login dialog pattern for better UX
- Users can easily switch between login and signup flows

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:25:13 -06:00
shakespeare.diy 97afc671fd Update Join button to trigger login modal instead of signup dialog
- Changed Join button onClick handler to open LoginDialog instead of SignupDialog
- Follows the same pattern as borkstr project where Join opens the login modal
- Users can still access signup through the login modal's "More Options" section

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:24:23 -06:00
shakespeare.diy b5fd5ecd24 Fix React hooks violation in ComposeBox causing error #300 on logout
- Moved early return to after all hooks to comply with Rules of Hooks
- Changed handleLogout to async/await pattern for better error handling
- Prevents "Rendered more hooks than during the previous render" error

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:22:51 -06:00
shakespeare.diy 6bab1e4113 Simplify logo filters and add pink theme filter
- Simplified code to inline filters in className
- Light theme: dark grey filter
- Pink theme: dark pink filter with medium brightness
- Dark/Black themes: no filter (original logo)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:19:42 -06:00
shakespeare.diy 106e5df46e Update logo filters: dark grey for light theme, dark pink for pink theme
- Light theme: neutral dark grey filter (no color tint)
- Pink theme: vibrant dark pink filter with high saturation
- Improved contrast and readability on light backgrounds

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:16:56 -06:00
shakespeare.diy 3aa5c6383c Fix logo readability in light and pink themes with CSS filters
- Apply dark blue-purple filter for light theme to make logo readable
- Apply dark pink filter for pink theme to match theme and improve visibility
- Replace opacity with color filters for better contrast
- Logo remains unfiltered in dark and black themes

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:16:01 -06:00
shakespeare.diy 1004f86415 Fix theme selector and logo display issues
- Show current theme name and icon in dropdown trigger button
- Fix light theme not working (update class removal from 'mew' to 'dark')
- Remove opacity from logo in pink theme (keep full visibility)
- Logo now only uses opacity in light theme (70%)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:14:55 -06:00
shakespeare.diy 92e2aca8e8 Update logo opacity and theme selector to dropdown menu
- Use opacity (60% pink, 70% light) for MewLogo instead of color filters
- Change Mew theme icon to Cat, Black theme icon to Moon
- Convert theme selector to proper dropdown menu with chevron indicator
- Add DropdownMenuLabel and separator for better UX
- Maintain theme icons: Cat (Mew), Sun (Light), Moon (Black), Heart (Pink)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:13:08 -06:00
shakespeare.diy 16d9c3ef1a Update theme system: Mew→dark, enhance pink theme, add theme icons and logo filters
- Rename "mew" theme to "dark" (Mew=dark, Light=light remain)
- Make pink theme more vibrant with increased saturation and adjusted hues
- Convert theme selector to dropdown menu with icons (Moon, Sun, Zap, Heart)
- Add CSS filters to MewLogo for pink and light themes with smooth transitions
- Keep Black and Pink themes as requested

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 00:10:34 -06:00
shakespeare.diy c743c7d458 Remove ... icon, add theme toggle, fix logout error
- Removed MoreHorizontal icon from account switcher trigger
- Fixed logout minified React error by properly closing popover before navigation
- Added theme toggle to account popover with Mew, Light, Black, Pink options
- Added Pink (pastel pink) theme CSS variables
- Updated Theme type to support 'light', 'dark', 'black', 'pink', 'system'

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:39:29 -06:00
shakespeare.diy e0b8785d7b Show Join button when logged out, Ditto-style account popover, hide account area when logged out
- LeftSidebar: Compose button becomes "Join" when logged out, opens signup dialog
- LeftSidebar: Account area in lower-left hidden when logged out
- LeftSidebar: Clicking account area opens Ditto-style popover with profile card, account switching, add account, and logout
- FloatingComposeButton: Shows join icon (UserPlus) when logged out, opens signup dialog

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:33:32 -06:00
shakespeare.diy 25d91f7adb Only show reaction emojis on post detail page, not in the feed
Add showEmojis prop to ReactionButton (default false). The emoji
indicators next to the count now only render when showEmojis is
true, which is only passed from PostDetailPage.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:25:50 -06:00
shakespeare.diy ca759ab243 Fix double-counting reaction: reset optimistic delta on publish success
The optimistic +1 delta was stacking on top of the refetched stats
(which already included the new reaction), causing the count to
jump by 2. Now we reset the delta to 0 on success so only the
real server count is displayed.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:23:55 -06:00
shakespeare.diy beeff37dc6 Add emoji picker for reactions with optimistic count updates
- Create ReactionButton component with Popover-based emoji picker
- Clicking the reaction button opens the full emoji picker (EmojiPicker)
- Selecting an emoji publishes a NIP-25 kind 7 reaction event with proper e/p/k tags
- Optimistically increments the reaction count and shows the user's chosen emoji
- Reverts optimistic update on publish failure
- Invalidates event-stats and event-interactions queries on success
- Replace static heart/like buttons in NoteCard and PostDetailPage with ReactionButton

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:23:03 -06:00
shakespeare.diy 9964d02775 Render npub/nprofile as @username mentions in embedded note previews
Parse nostr:npub1… and nostr:nprofile1… references within embedded note
card text and render them as clickable @username mentions (resolving the
display name via useAuthor), matching the style used in NoteContent.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:18:38 -06:00
shakespeare.diy fa32b45ee8 Strip nested nevent/note references from embedded note previews
Embedded note cards now strip out nostr:nevent1... and nostr:note1...
references from the content preview text, preventing recursive embedding
and keeping the preview clean.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:17:35 -06:00
shakespeare.diy d48d4dc8b6 Render nevent/note references as inline embedded post cards
- Create EmbeddedNote component with avatar, author name, timestamp,
  truncated content preview, and optional image thumbnail
- Update NoteContent tokenizer to detect note1 and nevent1 references
  and render them as embedded cards instead of plain text links
- Collapse whitespace around embedded note cards like link previews
- Clicking an embedded card navigates to the full post detail page

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:16:17 -06:00
shakespeare.diy 722202eede Increase link preview and YouTube embed spacing to my-2.5
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:05:45 -06:00
shakespeare.diy 9b2d26b6a0 Fix link preview spacing, bot headers, and add YouTube embeds
Spacing:
- Reduce link preview margins from my-2 to mt-1.5 mb-0.5
- Collapse whitespace on text tokens adjacent to block-level tokens
  (link-preview, youtube-embed) so newlines from the original content
  don't stack with the card's own spacing
- Filter out empty text tokens after trimming

Bot headers:
- Send proper User-Agent header ("Mew/1.0 Link Preview Bot") when
  fetching OG data so dynamic sites (SPAs, Twitter, etc.) return
  server-rendered HTML with OG meta tags instead of a JS shell
- Accept application/xhtml+xml in addition to text/html

YouTube embeds:
- Detect YouTube URLs (youtube.com/watch, youtu.be, /embed/, /shorts/)
  and extract video ID
- New YouTubeEmbed component renders a privacy-enhanced iframe player
  (youtube-nocookie.com) with proper 16:9 aspect ratio
- YouTube links render as playable inline embeds instead of OG cards

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:03:09 -06:00
shakespeare.diy dd02f2ff27 Render link previews inline where URLs appear in post content
Move LinkPreview rendering from a fixed position below the post into
NoteContent itself, so previews appear exactly where the URL was in
the original text.

- Rewrite NoteContent to use a token-based architecture: useMemo
  produces typed tokens (text, link-preview, mention, nostr-link,
  hashtag), then the render phase maps tokens to components
- Non-media URLs produce a `link-preview` token that renders an
  inline <LinkPreview> card at that position in the content flow
- Remove separate LinkPreview blocks from NoteCard and PostDetailPage
  since previews are now handled by NoteContent
- Remove unused extractPreviewUrl helper from useLinkPreview hook

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 23:00:58 -06:00
shakespeare.diy 00d5024218 Replace non-media link URLs with rich preview cards
- Add useLinkPreview hook that fetches Open Graph metadata (title,
  description, image, favicon, site name) via CORS proxy with 1hr
  stale time caching
- Add extractPreviewUrl helper to find the first non-media URL in
  note content
- Add LinkPreview component with a polished card UI showing OG image,
  title, description, domain favicon, and external link indicator
- Strip all URLs (both media and non-media) from NoteContent inline
  text — media URLs are rendered as image embeds, non-media URLs are
  rendered as LinkPreview cards
- Integrate LinkPreview into NoteCard and PostDetailPage between
  image attachments and action buttons

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:58:19 -06:00
shakespeare.diy ce90ded614 Strip embedded image URLs from NoteContent text display
Image URLs (jpg, jpeg, png, gif, webp, svg) are already rendered as
embedded image previews by NoteCard and PostDetailPage. This change
removes them from the inline text content to avoid duplication.

Also trims leading/trailing whitespace left behind after stripping
image URLs from the edges of content.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:55:11 -06:00
shakespeare.diy 8b46ce9692 Fix NIP-05 and display name truncation in NoteCard header
- Cap display name to max 40% width so it doesn't get crushed by long NIP-05 addresses
- Make NIP-05 span properly truncate with min-w-0 instead of pushing the layout
- Timestamp and separator remain fixed (shrink-0) so they're always visible

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:53:36 -06:00
shakespeare.diy 627b19a810 Remove post count from profile header
Unreliable metric since it only reflects the limited number of posts fetched, not the user's actual total.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:52:30 -06:00
shakespeare.diy 168cc28b39 Remove "Joined Nostr" calendar item from profile page, fix long strings breaking container
- Removed the Calendar icon and "Joined Nostr" text from profile info
- Added truncate to NIP-05 address to prevent overflow
- Added min-w-0 and truncate to website URL to prevent container breakout
- Made link icon shrink-0 to prevent it from being squished by long URLs

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:51:51 -06:00
shakespeare.diy 5270a5b7e8 Add subtle scrollbars that only appear on hover
- Scrollbars are hidden by default (transparent thumb and track)
- Thin 6px scrollbar appears with 25% opacity on container hover
- Thumb brightens to 40% on direct hover for feedback
- Works across both webkit and Firefox (scrollbar-width/scrollbar-color)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:49:19 -06:00
shakespeare.diy 38bfb91624 Fix search icon vertical alignment and remove focus ring
- Use flex items-center on the input wrapper instead of absolute
  top-1/2 -translate-y-1/2 hacks for proper icon centering
- Remove focus-visible ring and ring-offset on search input

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:48:44 -06:00
shakespeare.diy b88b75a90b Fix search spinner animation and remove debounce delay
- Replace Loader2 icon with inline SVG spinner using explicit @keyframes
  spin to avoid tailwindcss-animate conflicts
- Remove 250ms debounce so search fires immediately on input
- Add @keyframes spin to index.css for reliable rotation animation

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-16 22:47:30 -06:00