Zap receipts embedded via nostr:nevent1 references were falling through
to the generic EmbeddedNoteCard, which rendered the raw JSON content of
the zap request. Add a dedicated EmbeddedZapCard that extracts and
displays the sender, amount, and message using the existing zap utility
functions. Forwards disableHoverCards to prevent nested hover cards.
- Add disableMediaEmbeds prop to NoteContent that suppresses images,
galleries, and video/audio inside embedded quotes while preserving
link preview cards and lightning invoices
- Render inline fallback links for nevent/naddr references when
disableNoteEmbeds is true, instead of returning null and leaving
invisible gaps in quoted text
- Restore tag-based title/description fallback for events with empty
content (articles, custom addressable kinds) so they don't render
blank cards
- Migrate EmbeddedProfileBadgesCard to useProfileUrl for consistent
profile link routing
- Fix stateful global regex bug (IMETA_MEDIA_URL_REGEX) causing every
other URL to be misclassified when used with .test() in loops; add
non-global IMETA_MEDIA_URL_TEST_REGEX for safe .test() calls
- Rewrite EmbeddedNoteCard to render content via NoteContent (same as
NoteCard) with a 260px height cap instead of reimplementing URL
parsing and content truncation
- Pass disableEmbeds to NoteContent inside quotes to prevent recursive
nostr:nevent/note references from spawning nested EmbeddedNote
components
- Add overflow-aware 'Read more' toggle inline with attachment chips;
fade gradient only renders when content actually overflows
- Add BlobbiStateCard rendering for kind 31124 in both EmbeddedNote
and EmbeddedNaddr
- Extract EmbeddedCardShell with shared clickable card wrapper and
author row, deduplicating ~150 lines across EmbeddedNoteCard,
EmbeddedNaddrCard, and EmbeddedBlobbiCard
- Fix ComposeBox media URL detection using the same regex fix
- Fix EmbeddedNaddr profile links to use useProfileUrl instead of
hardcoded npub paths
Register kind 8211 across the event rendering pipeline so encrypted
letters render as 3D interactive envelopes instead of raw ciphertext.
Back shows a sealed envelope with sender/recipient names in script font
and a wax seal avatar. Click flips the envelope (CSS 3D transform),
click again opens it to reveal the ciphertext rendered as Nushu
characters -- a real historical secret women's script from China.
Kind 10008/30008 profile badges events now render a compact card with
author info, a row of up to 6 badge thumbnails, and a badge count
when embedded in quotes or reply context. Works in both EmbeddedNote
(nevent references) and EmbeddedNaddr (naddr references).
- Add isPhoto detection and PhotoDetailContent in PostDetailPage so kind 20
events render their image gallery when viewed directly via nevent links
- Add parsePhotoUrls helper and ImageGallery import to PostDetailPage
- Add 'Photo' shell title for kind 20 loading state
- Add KIND_HEADER_MAP entry for kind 20 ('shared a photo') in NoteCard
- Add Photo attachment indicator in EmbeddedNote for kind 20 events in
quote posts and reply context
Embedded/quoted posts (EmbeddedNote, EmbeddedNaddr) no longer display
full image thumbnails. Instead, images are shown as a small icon+label
indicator at the bottom, consistent with how videos and audio are
already represented. This keeps compact views lightweight and focused
on text content.
Remove gradient background and encryption footer from the full card, use
a clean bordered card with centered sender description. Add
EncryptedMessageCompact for quote posts, reply indicators, and the reply
composer — dispatched from EmbeddedNote like vanish events.
Add getKindLabel() to extraKinds.ts as the canonical resolver for
per-kind labels. Kinds in extraFeedKinds (like nsites 15128/35128)
now show 'nsite' instead of the parent category 'development'.
Embed cards for non-text kinds (nsites, follow packs, etc.) now show a kind
label line with icon below the title/description, giving context about what
the event is. Previously a quoted nsite just showed 'ditto' with no indication
it was an nsite deployment.
Quote posts and hover previews should always be compact (author + title/content).
Rendering a full NoteCard with action headers, buttons, and nested card components
inside a quote post or hover card is too much UI for an inline context.
- Remove NOTECARD_KINDS from EmbeddedNote.tsx and EmbeddedNaddr.tsx
- Remove NoteCard imports from both embed components
- Add tag-based metadata fallback (title/name/d, summary/description) to
EmbeddedNoteCard for non-text kinds with empty content
- Update AGENTS.md checklist to reflect that embeds no longer need per-kind registration
The same stripes + glitch icon + title + npub + reason layout was
duplicated across EmbeddedVanishCard, EmbeddedVanishPost,
VanishEventContent compact mode, and an inline version in NoteCard's
threaded branch. Extract a single VanishCardCompact component and
replace all four copies with it.
Net reduction of 76 lines.
When a Request to Vanish event is quoted/embedded inside another
post, it renders as a compact card with caution stripes, the glitch
icon, title, npub, and optional reason — matching the dramatic style
of the full vanish display.
When a quoted event fails to load, the 'this post could not be loaded'
indicator is now clickable, navigating to the event's page. Constructs
nevent1 for regular events and naddr1 for addressable events, including
relay hints and author pubkey when available from the parent event's tags.
Replace silent null returns in EmbeddedNote and EmbeddedNaddr with a
visible tombstone UI showing 'This post could not be loaded' with a
dashed border and icon, so users know a quote was referenced even when
the event can't be fetched from relays.
When a kind 30000 list is quoted, ComposeBox encodes it as a nevent
which routes through EmbeddedNote. EmbeddedNote had no kind-specific
handling, so lists appeared as generic text cards instead of the rich
card with title, member avatars, and description.
Add the same NOTECARD_KINDS check (kind 30000, 39089) that EmbeddedNaddr
already uses, delegating to NoteCard compact for these kinds.
- avatar.tsx: consolidate to single isEmojiShape boolean, fix AvatarFallback using same logic as Avatar
- avatarShape.ts: accept NostrMetadata directly in getAvatarShape (no cast needed)
- Remove 'as Record<string, unknown>' casts from all ~50 call sites
- Replace 'circle' magic string with empty string in form defaults and parseShape
- Use isValidAvatarShape instead of string comparison in save logic
- ProfileCard: extract IIFE overlay style into useMemo, use isEmojiShape throughout
- New 'shape' property on kind 0 profile metadata with 7 predefined shapes:
circle, triangle, inverted-triangle, hexagon, star, inverted-star, hexagram
- Avatar component updated with clip-path support for non-circle shapes
- Visual shape picker added to both EditProfileForm and ProfileSettings
- Shape applied across all 49 avatar render sites in the app
- New UserAvatar wrapper component for future simplified avatar rendering
- Unknown shape values gracefully fall back to circle (forward compatible)
- 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
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.
ProfileHoverCards on avatar, name, and @mentions inside EmbeddedNote
are now suppressed when rendered within the reply context hover card,
preventing nested hover card nesting.
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.
- 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
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.
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.
- 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
- 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
- Feed NoteCardSkeleton: restructured to match NoteCard's avatar + stacked
name/handle header with full-width content below (was incorrectly nested)
- VinesPage VineSkeleton: restructured to match vine card layout with
header, title, video placeholder, hashtags, and actions
- SearchPage PostSkeleton: aligned with Feed skeleton for consistency
- NoteCard: show skeleton for avatar and name while useAuthor is loading,
resolves to real data or fallback when relay responds/gives up
- RepostHeader: skeleton for reposter name while author loads
- ReplyContext: skeleton for reply-to name while author loads
- PostDetailPage: skeleton for author row in both main post and parent note
- EmbeddedNote: skeleton for author row in embedded note card
- EmbeddedNaddr: skeleton for author row in embedded naddr card
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
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>
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>
- 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>