Commit Graph

54 Commits

Author SHA1 Message Date
Alex Gleason 24a645277e Fix custom emoji stretching by adding object-contain to all emoji images
Custom emoji images with non-1:1 aspect ratios were being stretched
into a square. Added object-contain to preserve natural aspect ratio
within the bounding box. Moved text sizing classes to parent containers
for reaction emoji bubbles so unicode emojis still size correctly.
2026-04-02 03:50:50 -05:00
Chad Curtis 71f8ee0e16 fix: support accented and Unicode characters in hashtags
Replace /#\w+/g with /#[\p{L}\p{N}_]+/gu across all hashtag regexes
so that hashtags like #Bíblia and #verdade parse correctly. Affects
NoteContent, BioContent, ComposeBox, and PhotoComposeModal.
2026-03-31 06:48:36 -05:00
Alex Gleason a9449bd009 Fix jumpy home feed: layout shifts, background refetches, and pre-filtering
- Add min-height placeholder to InlineImage to prevent layout shifts when
  images load from 0px to natural height
- Remove 60s refetchInterval from useFeed that caused all pages to re-sort
  in the background, triggering full feed re-renders
- Pre-filter deprecated/hidden events at Feed level (shouldHideFeedEvent)
  instead of returning null inside NoteCard after hooks have already run
- Stabilize author info skeleton/loaded height with consistent min-h-[42px]
  to prevent cascading layout recalculations
2026-03-20 13:56:26 -05:00
Chad Curtis d955473c3c Fix long tag/bech32 string overflow in feed tabs, empty states, and note content 2026-03-17 09:29:50 -05:00
Alex Gleason f92f50d5e0 Fix quote posts not loading: include relay hints in nevent URIs and q tags 2026-03-15 04:19:02 -05:00
Alex Gleason 08e02190b4 URL-encode relay links in NoteContent to preserve slashes 2026-03-06 21:37:33 -06:00
Alex Gleason fa484dc03d Use /r/* wildcard route for relay pages, supporting bare URLs with slashes 2026-03-06 21:32:35 -06:00
Alex Gleason 24e940ae63 Linkify wss:// URLs in post content to internal relay pages 2026-03-06 21:27:09 -06:00
Mary Kate Fain eba4121d63 Support hyphens in custom emoji shortcodes
All shortcode regexes used [a-zA-Z0-9_] which excluded hyphens,
causing custom emojis like :GM-Chachi: to fail at every stage:
publishing (no emoji tag added to event), rendering (shortcode not
resolved to image), and detection (not recognized as custom emoji).

Updated the character class to [a-zA-Z0-9_-] across all 8 locations
in NoteContent, CustomEmoji, ComposeBox, and customEmoji utility.

Also added viewer's custom emoji collection as a fallback in
NoteContent so shortcodes render even when events from other clients
omit the emoji tag.

Closes #62
2026-03-04 23:51:19 -06:00
Chad Curtis bcbb89163a render consecutive inline images as gallery grid in kind 1 notes 2026-03-02 23:44:53 -06: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
Mary Kate Fain 7647aa8f28 Fix duplicate images in calendar events by hiding link preview thumbnails when cover image is shown 2026-03-01 22:29:20 -06:00
Alex Gleason fad790be16 Extract non-component exports to separate modules to fix react-refresh warnings
Move helper functions, types, and constants out of component files into
dedicated lib/hooks modules so each component file only exports components:

- getContentWarning -> src/lib/contentWarning.ts
- isCustomEmoji, getCustomEmojiUrl, buildEmojiMap, ResolvedEmoji, resolveReactionEmoji -> src/lib/customEmoji.ts
- ExternalContent, parseExternalUri, formatIsbn, headerLabel, seoTitle -> src/lib/externalContent.ts
- extractYouTubeId, extractTweetId, and other URL helpers -> src/lib/linkEmbed.ts
- isSingleImagePost -> src/lib/noteContent.ts
- useOnboarding, OnboardingContext -> src/hooks/useOnboarding.ts

Also un-exported module-private symbols in VinesFeedPage and SettingsPage.
2026-03-01 22:15:47 -06:00
Alex Gleason d147a25590 Fix all ESLint errors and warnings across 15 files 2026-03-01 21:59:19 -06:00
Chad Curtis e1e5bbe696 Render audio uploads as video-style visualizer with avatar and sinewave
- Add AudioVisualizer component: mirrors VideoPlayer chrome exactly (same overlay controls, progress bar, hide-on-idle, scroll-pause) with a canvas sinewave and author avatar in the centre
- Wire audio into NoteCard (kind 1 notes), FileMetadataContent (kind 1063), and ComposeBox preview
- Extract shared utilities: formatTime, usePlayerControls hook, and mediaUrls (regexes + mimeFromExt) to eliminate duplication across VideoPlayer, AudioVisualizer, NoteCard, NoteContent, ComposeBox, and EmbeddedNote
- Fix ComposeBox: audio URLs now get correct imeta MIME tags and are excluded from link-embed detection
2026-02-28 23:35:17 -06:00
Chad Curtis 44cc217de9 Treat single image with short caption as a single image post 2026-02-28 23:01:21 -06:00
Alex Gleason 21b465ff3e Add unified LinkEmbed component, consolidate URL detection and embed rendering
- Create LinkEmbed that dispatches to YouTubeEmbed, TweetEmbed, or LinkPreview based on URL
- Centralize extractYouTubeId and extractTweetId in LinkEmbed module
- Simplify NoteContent: merge link-preview and youtube-embed token types into link-embed
- Tweet URLs in posts now render as embedded tweets automatically
- Remove duplicate extractYouTubeId from NoteContent and ExternalContentHeader
2026-02-28 19:01:47 -06:00
Alex Gleason 2cd4124d65 Enlarge emoji-only posts with robust detection for ZWJ, flags, keycaps, skin tones, and NIP-30 custom emojis 2026-02-28 17:17:40 -06:00
Chad Curtis fc5dbc3e80 Pass relay and author hints from nevent1 to EmbeddedNote
When a nostr:nevent1 URI is decoded in NoteContent, the relay hints and
author pubkey embedded in the identifier were being discarded. This meant
EmbeddedNote would only query the user's configured relays and skip the
relay hints, causing quoted events hosted on other relays to silently fail
to load. Now the hints are stored in the nevent-embed token and forwarded
to EmbeddedNote → useEvent.
2026-02-28 16:19:38 -06:00
Alex Gleason 874c374434 Make flag emojis in post content clickable, linking to /i/iso3166:<CODE> pages 2026-02-28 00:19:36 -06:00
Chad Curtis 761bbb0526 Fix image rendering in note content: full width, preserve aspect ratio, re-measure after image load
- Images now render at full width with natural aspect ratio (no cropping)
- Single-image posts skip the 'Read more' truncation
- Re-measure scrollHeight after images load to correctly detect overflow on multi-image posts
2026-02-27 21:41:01 -06:00
Chad Curtis 79c143fab1 fix: replace image URLs with newline in disableEmbeds preview mode 2026-02-26 05:37:01 -06:00
Chad Curtis 0576775a57 fix: suppress image URLs in triple-dot menu post preview
When disableEmbeds is true, image-embed tokens now return null instead of
rendering the raw URL as a link. This fixes the triple-dot (more menu)
preview showing bare blossom/image URLs instead of clean post text.
2026-02-26 05:36:27 -06:00
Chad Curtis 6f5a07c0a9 Render images inline at their position in post content
- Images now render inline via NoteContent at the position of their URL
  rather than collected into a gallery block below the text
- Clicking an inline image opens a full lightbox with navigation across
  all images in the post; lightbox index is tracked by position so
  duplicate URLs open at the correct index
- Removed separate ImageGallery/extractImages from NoteCard,
  PostDetailPage, and ComposeBox to prevent double-rendering
- Added disableEmbeds to NoteMoreMenu clamped preview to avoid block
  embeds inside a line-clamp-3 container
- Fixed hasPreviewableContent in ComposeBox to detect image-only posts
  so the Preview tab appears correctly
- Removed mp3/ogg/wav/pdf from MEDIA_URL_REGEX suppression list; those
  URLs now render as clickable links instead of being silently dropped
- Added avif to IMAGE_URL_REGEX; added cursor-pointer to InlineImage
2026-02-26 04:35:03 -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 64cf10f381 Fix useProfileUrl to call useNip05Verify directly instead of peeking cache
The cache-peek approach always returned npub because the cache was empty
at render time. Replace it with a proper hook that calls useNip05Verify,
relying on TanStack Query's deduplication to avoid redundant requests.

Also fix the dot separator in NoteCard to hide when NIP-05 is unverified,
and refactor ProfileSearchDropdown to pass the verified URL through
onClick rather than recomputing it in an event handler.
2026-02-23 19:39:13 -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 580b5ae46e Fix whitespace stripped around URLs containing naddr1 identifiers
URLs like https://following.party/naddr1... were having all surrounding
whitespace removed because naddr-embed tokens from URLs were treated as
block-level elements. Only bare naddr1 identifiers (without a URL) should
strip surrounding whitespace; URL-sourced ones are inline and need their
spacing preserved.
2026-02-22 01:49:38 -06:00
Chad Curtis bba57e83e4 Fix compose preview to match real note rendering
Mentions now trigger the Edit/Preview toggle. Compose preview uses
NoteContent directly for link previews and embeds instead of rendering
them separately, matching how real notes display. LinkPreview falls back
to a domain+favicon card when OEmbed data is unavailable. Added
disableEmbeds prop to NoteContent for future use.
2026-02-21 17:27:08 -06:00
Alex Gleason 13f05936dd Add webxdc support: attach .xdc files as stateful mini apps with kind 4079 state sync
- Create useWebxdc hook bridging the Webxdc API with Nostr kind 4079 state updates
- Create WebxdcEmbed component with launch-on-click UX for sandboxed iframe rendering
- Update ComposeBox to accept .xdc files and generate imeta tags with webxdc UUID
- Update NoteCard and PostDetailPage to detect and render webxdc attachments
- Skip .xdc URLs in NoteContent to avoid rendering them as raw links
2026-02-21 04:57:05 -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
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 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 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
shakespeare.diy 510e7a76f2 Add multiple reply authors and emoji-only enlargement
- Show multiple reply authors like "Replying to @chad and @alex"
- Display up to 2 authors, with "and X others" for more
- Enlarge emojis when they're the only content (text-5xl)
- Detect emoji-only content (max 12 emoji chars)
- Update ReplyContext to accept array of pubkeys
- Extract all non-mention p tags for reply context
- Matches Ditto's reply author display behavior

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 20:40:54 -06:00
shakespeare.diy 3c4c84d255 Fix URL parsing with trailing punctuation and preserve whitespace formatting
- Strip trailing punctuation from URLs (.,;:!?)])  that are likely not part of the URL
- Fixes issue where (https://example.com) was parsed incorrectly
- Preserve newlines and formatting after embedded content
- Only collapse excessive whitespace (3+ newlines) instead of removing all whitespace
- Maintains proper text flow after link previews and embedded events

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 04:27:33 -06:00
shakespeare.diy 973064af99 Fix whitespace handling for naddr URLs with embedded events
- Preserve one newline after naddr-embed tokens when present
- Prevents text from flowing directly after URL without spacing
- Embedded event now properly displays with preserved formatting

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 04:25:38 -06:00
shakespeare.diy 724663f7dd Support mentions in all contexts including inside quotes and parentheses
- Removed lookahead that was preventing matches in certain contexts
- NIP-19 identifiers now render as mentions regardless of surrounding characters
- Maintains single @ display by consuming optional @ prefix

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 04:23:08 -06:00
shakespeare.diy d3d98a00bf Fix double @@ rendering for mentions and support mentions inside quotes
- Updated regex to optionally match @ before NIP-19 identifiers
- Removed word boundary requirement to allow mentions in quotes
- Mentions now render correctly with single @ symbol in all contexts

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 04:22:04 -06:00
shakespeare.diy 7ff554f8b6 Fix hashtag clicks navigating to post detail instead of hashtag page
Add e.stopPropagation() to hashtag, nostr-link, and mention Links
inside NoteContent so clicks don't bubble up to the parent card's
onClick handler that navigates to the post detail page.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 19:47:34 -06:00
shakespeare.diy 476e9bf177 fix: match bare NIP-19 identifiers (without nostr: prefix) in note content
The content parser regex only matched nostr:-prefixed identifiers like
`nostr:naddr1...`. Bare identifiers like `naddr1...` were rendered as
plain text. Added a \b word-boundary alternation to also match bare
npub1, note1, nprofile1, nevent1, and naddr1 identifiers, so they
render as proper embeds/mentions/links.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 19:16:24 -06:00
shakespeare.diy 9e71aea931 Fix raw image URL rendering in post details and improve skeleton
- Fix NoteContent fallback that incorrectly rendered raw media URLs as
  plain text when the entire content was a media URL. The parser would
  skip media URLs (handled by parent as embeds), but when all tokens
  were skipped, the empty-result fallback re-added the full content
  as text. Now tracks whether any regex matches occurred to distinguish
  "no matches at all" from "all matches were skipped media URLs".

- Restructure PostDetailSkeleton to match the actual PostDetailContent
  layout: proper article/replies separation (fixes double padding on
  reply skeletons), image placeholder, rounded action button circles,
  and -mx-4 action bar matching the real component.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 04:21:57 -06:00
shakespeare.diy 49917ec1a0 Preserve newlines between text and naddr URL in note content
The whitespace collapsing logic was stripping newlines before naddr-embed
tokens that have a URL, causing text and the URL to smash together.
Now only pure block embeds (no URL) trim preceding whitespace.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 02:34:50 -06:00
shakespeare.diy 7ca3587e1d Preserve original URL for naddr embeds and implement naddr detail page
- NoteContent now shows the original URL as a clickable link above the
  embedded naddr card when the naddr was extracted from a regular URL
- Replaced "Addressable event view coming soon" placeholder in NIP19Page
  with a full AddrDetailPage that shows hero image, author, title,
  description, image gallery, metadata fields, and tags
- AddrDetailPage extracts metadata from both event tags and JSON content

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 02:33:06 -06:00
shakespeare.diy b81aa6f2c8 Render naddr1 URLs as embedded Nostr events instead of broken link previews
- Added useAddrEvent hook for fetching addressable events by kind+pubkey+d-tag
- Created EmbeddedNaddr component that displays title, description, image, and author
  from addressable events (extracting metadata from tags and JSON content)
- Updated NoteContent to detect naddr1 identifiers in regular URLs (e.g.
  bitpopart.com/art/naddr1...) and render them as Nostr embeds
- Added naddr1 to the nostr: URI regex so nostr:naddr1... is also handled
- Added naddr-embed token type with proper whitespace collapsing

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-17 02:30:17 -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