Pass post.likeCount to ExternalReactionButton via new count prop so like
counts display from the Bluesky API. Comment button now opens the
ReplyComposeModal with the post URL instead of navigating away.
The Bluesky page had a broken inline reaction that just published '+' with
no emoji picker. The /i/ page had the full implementation with Popover,
QuickReactMenu, hover-to-open, and custom emoji support. Extracted the
reaction logic into a reusable ExternalReactionButton component and wired
it into both pages, removing ~230 lines of duplicated/inferior code.
Integrate useWikipediaSearch and useArchiveSearch into both the desktop
sidebar dropdown (ProfileSearchDropdown) and mobile bottom-nav sheet
(MobileSearchSheet). At most 1 result from each source is shown, always
positioned after Nostr profiles to preserve profile precedence. Keyboard
navigation indices updated to include the new items.
Detect Wikipedia URLs and render a custom WikipediaArticleHeader with hero
image, article title, Wikidata description, expandable extract, and a
Read on Wikipedia footer link. Also uses the Wikipedia API for accurate
page titles in the header bar and SEO metadata, and navigates back to
/wikipedia on the back button.
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.
Starter pack pages now have two tabs: Feed (default) shows posts from all
pack members using useStreamPosts, and Members shows the existing member
list with follow/unfollow buttons.
Adds a Compressed/Original toggle button in the ComposeBox toolbar.
When set to Original, images are uploaded as-is without resizing or
re-encoding. Defaults to Compressed.
ExternalContentSidebarItem now fetches the book title from OpenLibrary
via useBookInfo for ISBN entries instead of showing the generic 'Books'
label. The icon uses BookOpen instead of the Globe fallback.
ExternalContentPage (country, URL, ISBN pages) gains a 3-dots menu on
the right side of the action bar with Add/Remove from sidebar.
NoteMoreMenu gets an Add/Remove from sidebar item after 'Add to list',
so any post can be pinned to the sidebar from its options menu.
Both locations toggle between add (PanelLeft icon) and remove (Trash2
icon) based on whether the item is already in the sidebar.
Remove all non-standard NIP-58 extensions:
- Delete BadgeTierPill component and badge tier system (bronze/silver/gold/diamond)
- Delete isShopBadge, isAchievementBadge, getBadgeTier, BadgeTier type
- Delete publish-achievement-badges.sh script
- Remove kind 30009 section from NIP.md
- Clean up badge category pills from detail page and tier pills from badge rows
Badges now use pure standard NIP-58 with no custom tags.
External i-tag identifiers like https:// URLs, iso3166:US country
codes, and isbn: values can now be added as sidebar menu items.
URLs show their favicon and hostname. Country codes show their
flag emoji and name. ISBN shows the book label. Clicking navigates
to /i/<encoded-value>.
The 'Add link' input (renamed from 'Add Nostr link') now accepts
all identifier types: Nostr URIs, URLs, iso3166 codes, and ISBNs.
The badge detail page now has three tabs: Awarded To, Feed, and
Comments. The Feed tab shows an infinite-scroll feed of kind 1 posts
authored by users who hold the badge, giving a community-feed view
centered around each badge.
Kind 30000 (NIP-51 lists) now shows the Scroll icon instead of the
generic FileText fallback. Added a KNOWN_KIND_ICONS map in
NostrEventSidebarItem for kinds not covered by EXTRA_KINDS.
ListDetailPage gains an 'Add to sidebar' dropdown action that
creates a nostr:naddr sidebar entry for the current list. The
option is hidden once the list is already pinned.
useEventStats now accepts an optional event object. For addressable
events (kinds 30000-39999), it queries kind 30384 stats by the a-tag
coordinate instead of kind 30383 by event ID, so reply/reaction counts
display correctly for badge collections, badge definitions, articles,
and other addressable event types.
All 8 call sites updated to pass the event object.
Support nostr: URIs (npub, nprofile, note, nevent, naddr) as
sidebar menu items. Profiles show their avatar and display name;
other events show a kind-based icon and label fetched from relays.
Users can add Nostr links via the 'Add Nostr link' button in
sidebar edit mode. Clicking navigates to /:nip19.
Kind 30009 badge definition embeds now show a smaller version of the
badge showcase (centered image with rotating light rays, name, and
description) instead of the generic link-preview card with cover image.
- Add action bar with ReactionButton (kind 7), RepostMenu (kind 16),
and comment count button below the badge info section
- Replace flat awardees list with tabbed interface: 'Awarded To' and
'Comments'
- Comments tab uses useComments (NIP-22 kind 1111 on addressable event),
ComposeBox for inline composition, and ThreadedReplyList for display
- Add rotating light rays spotlight effect to the badge detail hero
- Replace full-width image with centered badge showcase (size-36)
Replace the link-preview-style layout (full-width image + text below) with
a centered badge showcase: the image is displayed at badge size (112px)
with name and description centered beneath it, and a slow-rotating conic
gradient spotlight behind it for a grand presentation feel.
- Replace three separate pages (/badges/create, /badges/created,
/badges/manage) with a single /badges page
- Two tabs: 'My Badges' (accepted + pending + created sections)
and 'Follows' (badge feed from followed users)
- Convert badge creation form into a CreateBadgeDialog opened via FAB
- Remove Global tab
- Delete BadgeCreatePage, BadgeCreatedPage, BadgeManagePage
- Update BadgeShowcaseGrid editPath to /badges
- Simplify useBadgeFeed to only support follows tab
- Fix incorrect npub in publish-achievement-badges.sh (was wrong bech32 encoding)
- Show actual badge names in award notifications by fetching kind 30009 definitions,
with fallback to un-slugified d-tag identifier
- Strip price/supply UI from shop page and badge detail (no purchase flow exists)
- Document custom badge tag extensions and DVM claim-achievement flow in NIP.md
- Remove unused badge-glow CSS animation (duplicate of pending-glow in Tailwind)
- Make badge award notifications respect user preferences instead of force-enabled
- Add badges toggle to notification settings page
- Enhanced DiscussBar below embeds (YouTube, Archive.org, Spotify, etc.)
to show title, author, provider name, and an external link, matching
the style of generic LinkPreview cards
- Always show the info bar (title, domain, external link) below embeds,
even on /i/ pages where showActions=false; only hide the Discuss button
- Added native OEmbed fetching for YouTube, Spotify, and Reddit directly
from their provider endpoints, since the generic link preview proxy
fails for these sites
- For Archive.org, fetch title/creator from the metadata API and
transform into OEmbed-compatible shape
- Removed the !title guard in useLinkPreview that discarded OEmbed
responses without a title field
- Falls back to the generic link preview proxy for unknown providers
When users click the play overlay, the iframe now loads with autoplay=1
so the content plays immediately, matching the YouTube embed behavior.
Also adds allow='autoplay' to the iframe attribute so browsers permit
the autoplay request from the embedded frame.
The archive.org embed page has a responsive player for videos/audio
but renders software/games at fixed native pixel dimensions. Fetch the
item's mediatype from the metadata API and branch accordingly.
The archive.org embed renders content at native pixel dimensions and
doesn't scale to fill the iframe like YouTube does. On mobile the
550px-wide content overflowed the ~370px container.
Fix: give the iframe its native dimensions and use transform: scale()
with a ResizeObserver to shrink it to fit the container width. Also
reverts the unnecessary overflow-x-hidden on ExternalContentPage.
The CSS aspect-ratio property can cause overflow on narrow viewports.
The padding-bottom percentage trick is always relative to the parent
width, so it scales correctly on mobile.
Enter/submit now always performs a text search instead of redirecting
when the query looks like a NIP-05, npub, nevent, etc.
Identifiers are detected in real-time and shown as autocomplete items:
- NIP-05 (user@domain.com, domain.com): resolves to profile via .well-known
- npub/nprofile: shows profile with avatar and metadata
- note/nevent: shows event content preview with author
- naddr: shows addressable event with title/content preview
- hex: shows navigable link to the identifier
Resolved profiles are deduplicated from regular search results.
Works in both desktop sidebar and mobile bottom sheet search.
Replace the confusing externalLink/hideActions/showDiscuss props with
a clearer model:
- navigateToComments: opt-in to /i/ navigation (default: card opens
the URL externally, which is the natural expectation)
- showActions: single prop controlling the action button across both
LinkPreview and DiscussBar (default: true)
The action button always offers the opposite of what clicking the card
does: 'Discuss' when the card opens externally, 'Open' when the card
navigates to /i/.
Link previews now show the correct action button based on context:
- In posts (externalLink): card opens externally, shows 'Discuss' button
- In hover cards (!externalLink): card navigates to /i/, shows 'Open' button
- On /i/ page (hideActions): no action button since both would be redundant
LinkEmbed now defaults externalLink to true so link previews embedded
in post content open the URL externally as expected. Only standalone
uses of LinkPreview (like the CommentContext hover card) navigate to
the /i/ comment page.