Commit Graph

2792 Commits

Author SHA1 Message Date
Chad Curtis 4643830512 Sync letter improvements from lief
- Make LetterContent.body optional; a letter requires a non-empty body
  or at least one sticker
- Replace colors:[]/flatMode with event-stripping: flat color moment =
  event field stripped from Stationery, removing the colors? field
- Remove edgeScale: stickers render at their stored scale value with no
  edge-proximity size reduction, matching lief and the NIP
- Fix sticker shrinking near card edges: add max-width:none to override
  Tailwind preflight max-width:100% on img/svg elements
2026-03-30 04:30:00 -05:00
Chad Curtis ef04de67c0 Improve notification rendering for badges and letters
- Add hideKindHeader prop to NoteCard, used by ReferencedNoteCard to
  suppress redundant action headers in repost/reaction/zap notifications
- Redesign badge award notification: show full BadgeContent showcase card
  with prominent rounded-pill Accept Badge button below
- Redesign letter notification: larger centered envelope (minimal mode
  hides name/timestamp), click opens LetterDetailSheet inline, View All
  Letters button below
2026-03-30 00:13:01 -05:00
Chad Curtis 5847cceba6 Auto-shrink stickers near card edges and clip overflow at rounded boundary
Stickers now scale down proportionally as their center approaches any
edge of the letter card, preventing them from overflowing the rounded
corners. A 5% drag buffer keeps sticker centers away from the very
edge. The sticker overlay uses pointer-events-none so the textarea
remains clickable underneath.
2026-03-29 23:53:20 -05:00
Chad Curtis f62b86027c Remove unused eslint-disable directive in LayoutContext 2026-03-29 22:59:41 -05:00
Chad Curtis 8e5018d3b2 Fix 3 letter bugs: allow drawing-only sends, fix sticker drag bounds, preserve theme events
- Allow sending letters with only stickers/drawings (no body text required)
- Fix sticker drag positioning by using cardRef instead of page container
  ref, so percentage coordinates map correctly to the card boundaries
- Preserve stationery source events (color moments/themes) in preferences
  so they embed as gift attachments in sent letters
- Accept sticker-only letters during decryption validation
2026-03-29 22:41:03 -05:00
Chad Curtis 8df17f5ae7 Fix top bar arc flash by deferring layout cleanup past Suspense boundary 2026-03-29 22:23:23 -05:00
Alex Gleason dd31ce681f Add Blobbi to default sidebar order after Badges 2026-03-29 22:05:31 -05:00
Alex Gleason 74345fdb2f Fix feed gaps when replies are disabled by over-fetching from relay
When followsFeedShowReplies is false, the relay limit was PAGE_SIZE (15)
but client-side reply filtering could discard most events, leaving only
a few visible posts per page with large time gaps between them.

Apply the same over-fetch pattern already used by useProfileFeed:
- Request PAGE_SIZE * 3 events when reply filtering is active
- Use rawCount (pre-filter) for pagination termination so pages where
  all items are replies don't prematurely stop pagination
2026-03-29 18:51:20 -05:00
Alex Gleason 02231ea1f9 Fix avatar shape flash by computing mask URL synchronously
The Avatar component was initializing maskUrl as '' and loading it in a
useEffect. Since hasCustomShape was true immediately, rounded-full was
removed on the first render, but the mask wasn't applied until after the
effect fired — causing a visible square flash for one frame.

getAvatarMaskUrl is already synchronous (renders emoji to canvas, caches
the data-URL), so compute it inline during render instead of deferring
to an effect. The mask is now applied on the very first paint.
2026-03-29 17:47:57 -05:00
Alex Gleason effc704613 Fix 'Cannot update component while rendering' warning in useLayoutOptions
useLayoutOptions was calling store.setOptions() synchronously during
render, which triggered useSyncExternalStore listeners in MobileBottomNav
(and MainLayout) while Index was still rendering.

Move the store update into useLayoutEffect, which fires synchronously
after commit but before browser paint — same visual result without
violating React's setState-during-render rule.
2026-03-29 17:43:55 -05:00
Alex Gleason 51fb1fd1cb Give comments (kind 1111) and generic reposts (kind 16) independent feed toggles
Previously comments shared feedKey 'feedIncludePosts' with kind 1, and
generic reposts shared 'feedIncludeReposts' with kind 6. This made it
impossible to toggle them independently in settings.

Add feedIncludeComments and feedIncludeGenericReposts to FeedSettings
and wire them to their respective EXTRA_KINDS entries.
2026-03-29 17:33:56 -05:00
Alex Gleason 1988e1b849 Fix duplicate React keys in content settings
Multiple ExtraKindDef entries share the same feedKey (e.g. posts/comments
both use feedIncludePosts) and multiple subKinds share the same showKey
(e.g. both video sub-kinds use showVideos). Using these as React keys
caused 'duplicate key' warnings.

Use def.id (always unique) for ContentTypeRow keys and sub.feedKey
(unique per sub-kind) for SubKindRow keys.
2026-03-29 17:29:45 -05:00
Alex Gleason 1b782f65d1 Display QR code in terminal for NIP-46 auth script 2026-03-29 16:58:22 -05:00
Alex Gleason 6c4eddece7 Add NIP-46 client-initiated auth script for Zapstore CI signing 2026-03-29 16:47:36 -05:00
Alex Gleason a796f279a5 release: v2.2.2 v2.2.2 2026-03-29 15:48:26 -05:00
Alex Gleason efc491bad4 Add release notes to Zapstore publishing 2026-03-29 15:45:52 -05:00
Alex Gleason f6c08f8afa Add badge list recovery dialog for kind 10008 events
Allow users to browse and restore previous versions of their accepted
badges (profile badges) from relay history, matching the existing
mute list recovery pattern in /settings/content.
2026-03-29 15:22:51 -05:00
Alex Gleason 3197c53fcc Fix PageSkeleton to match actual page layout structure
The lazy-loading skeleton was missing center column borders
(sidebar:border-l/r) and the right sidebar widget backgrounds
(bg-background/85 rounded-xl). Updated to mirror the real Outlet
wrapper classes and RightSidebar widget card styling with three
distinct skeleton sections (Trends, Hot Posts, New Accounts).
2026-03-29 15:14:09 -05:00
Alex Gleason 7b793149b3 Reserve grid cell for +N overflow indicator in badge lists
When a badge list overflows PREVIEW_LIMIT, show one fewer badge to
make room for the +N button on the same row instead of widowing it.
The loading skeleton now also includes a placeholder for the overflow
cell when applicable.
2026-03-29 15:08:48 -05:00
Alex Gleason 24c938728a Replace spinner with skeleton grid for badge list loading state
Shows placeholder skeletons matching the badge grid layout (48px
rounded squares + name bars) instead of a centered spinner while
badge definitions are being fetched.
2026-03-29 15:06:33 -05:00
Alex Gleason 1c358a3c79 Add compact badge row preview for embedded profile badges events
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).
2026-03-29 15:04:58 -05:00
Alex Gleason 3bbed8875c Remove inline compose box from profile badges detail view
The badge collection detail page (kind 10008/30008) no longer shows
a ComposeBox between the badge grid and the comments section.
2026-03-29 15:02:12 -05:00
Alex Gleason 0f7fc673eb Make +N overflow indicator clickable to expand full badge grid
Clicking the '+2' (or similar) button at the end of a truncated badge
grid now reveals all badges instead of being a static indicator.
2026-03-29 15:01:17 -05:00
Alex Gleason 646c95a86f Show kind action header on threaded ancestor NoteCards
The KIND_HEADER_MAP action header (e.g. 'updated their badges',
'created a badge', 'shared a photo') was only rendered in the normal
NoteCard layout. Now it also appears in the threaded layout, so parent
events shown as ancestors in reply threads display their kind context.
2026-03-29 14:56:55 -05:00
Alex Gleason 87a8974c8c Show parent event as threaded NoteCard for kind 1111 comments
When viewing a NIP-22 comment (kind 1111) that references its parent
via an 'a' tag (addr coordinates) rather than an 'e' tag (event ID),
the parent event is now rendered as a full threaded NoteCard with a
connector line — matching how kind 1 reply threads display ancestors.

Previously these showed a compact AddressableEventPreview banner.
Now the parent badges list (or any other addr-referenced event) renders
inline in the thread, giving proper visual context for the comment.
2026-03-29 14:55:48 -05:00
Alex Gleason 9b5df28b93 Fix naddr routing for replaceable events (kind 10000-19999)
Replaceable events have no d-tag, so useAddrEvent must omit the #d
filter for kinds in the 10000-19999 range. Without this, querying
for a kind 10008 profile badges event via naddr would include
'#d': [''] in the filter, which fails to match events without a d-tag.
2026-03-29 14:47:52 -05:00
Alex Gleason e876e290da Encode replaceable events (kind 10000-19999) as naddr URLs
Replaceable events should use naddr encoding (kind + pubkey + empty
identifier) rather than nevent (event ID), since they are identified by
their coordinates. This fixes kind 10008 profile badge events linking
to /nevent1... instead of /naddr1... from the feed.
2026-03-29 14:45:45 -05:00
Alex Gleason f26f033b14 Support viewing kind 10008/30008 profile badges via nevent URLs
PostDetailPage (used for nevent1 identifiers) was missing the kind
10008/30008 branch, so profile badge events fell through to the generic
PostDetailContent. AddrPostDetailPage already had this handling via
ProfileBadgesDetailView — now PostDetailPage shares the same code path
for both badge definitions (30009) and profile badges (10008/30008).
2026-03-29 14:41:24 -05:00
Alex Gleason 565f323179 Add mouse-only 3D tilt to BadgeThumbnail with visible effect
Build the tilt directly into BadgeThumbnail instead of a separate
wrapper. Use aggressive parameters (35deg max tilt, 1.15x scale,
perspective = size*3) so the effect is clearly visible on small
28-48px thumbnails. Add a perspective parameter to useCardTilt.

Remove old group-hover:scale-110 from all badge grid call sites
(BadgeShowcaseGrid, ProfileBadgesContent, ProfilePage,
ProfileHoverCard) since the tilt+scale is now built into the
thumbnail itself.
2026-03-29 14:37:46 -05:00
Alex Gleason 6b59658f00 Add mouse-only 3D tilt effect to badge images in feed cards
Reuse useCardTilt for the badge image in BadgeContent feed cards, but
only respond to mouse/pen pointer events. Touch events are explicitly
ignored and touch-action is set back to auto so tapping through to the
badge detail view and normal scrolling are unaffected. Includes the
specular glare overlay masked to the badge image shape.
2026-03-29 14:28:33 -05:00
Alex Gleason 2e1e4416b3 Add touch support to badge 3D tilt effect
Update useCardTilt to handle touch inputs via PointerEvent. Touch
interactions use a press-and-drag gesture: the tilt follows the finger
while down, then holds for 600ms after release before smoothly
resetting. touch-action: none prevents the browser from intercepting
the gesture for scrolling. Mouse behavior is unchanged.

Update BadgeHero glare overlay to match: glare follows touch position
during the drag and fades after the same linger delay on release.
2026-03-29 14:26:02 -05:00
Alex Gleason e92a2c571c Remove 'Badge' pill from badge detail issuer row
Remove the secondary Badge UI element showing '<Award icon> Badge' next to
the issuer name on the badge detail page. The context is already clear from
the page layout and hero image.
2026-03-29 14:20:52 -05:00
Alex Gleason d3a418b5ee Remove redundant header from profile badges feed card
Remove the 'Name's Badges (N badges)' header line from ProfileBadgesContent
to reduce visual clutter. The badge grid and NoteCard's KIND_HEADER_MAP
already provide sufficient context.
2026-03-29 14:18:37 -05:00
Alex Gleason c9945107e9 Replace Photos and Videos with Badges in default sidebar order 2026-03-29 14:14:55 -05:00
Alex Gleason 4c70133ca9 Clarify EmbeddedNote vs NoteCard compact prop in AGENTS.md
Rename the checklist item from 'Inline embeds / quote posts' to
'Embedded note cards' with explicit file paths, explain that kinds
with tag-based media may need attachment indicator updates, and add
a note distinguishing EmbeddedNote components from the NoteCard
compact prop to prevent confusion.
2026-03-29 14:11:51 -05:00
Alex Gleason 0df942cb9d Display kind 20 photo events in detail view and add Photo indicator
- 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
2026-03-29 14:09:39 -05:00
Alex Gleason 37a63f068b Make version tag and date clickable links, remove external link icon 2026-03-29 13:48:07 -05:00
Alex Gleason cc8638e8b2 Show build date instead of commit hash in pre-release banner, compare to current commit 2026-03-29 13:46:26 -05:00
Alex Gleason cf9d409166 Migrate profile badges from kind 30008 to kind 10008
Profile badges should be a replaceable event (kind 10008), not an
addressable event (kind 30008) with a fixed d-tag. This follows the
same deprecation pattern used by NIP-51 lists.

All writes now publish kind 10008. All reads query both 10008 and
legacy 30008, picking whichever is newest, for backwards compatibility
during the transition period.
2026-03-29 13:10:22 -05:00
Chad Curtis 7d8ac49fe2 Document fetchFreshEvent pattern in AGENTS.md 2026-03-29 10:08:44 -05:00
Chad Curtis dc3be6564b Fix stale-cache overwrites in replaceable event mutations
Extract shared fetchFreshEvent() utility that fetches the freshest
version of a replaceable/addressable event directly from relays before
every mutation. This prevents data loss when the TanStack Query cache
is stale (cross-device edits, rapid sequential operations).

Previously only useFollowActions and useMuteList had this safety
pattern. Now all list-type hooks use the same shared primitive:
useAcceptBadge, useRemoveBadge, useBookmarks, usePinnedNotes,
useInterests, and useUserLists.
2026-03-29 10:05:58 -05:00
Chad Curtis 337e27f2b5 Add multi-select badge awarding with already-sent indicators 2026-03-29 09:47:05 -05:00
Chad Curtis c400437662 Add kinds 10015, 10030, 10063 to NostrBatcher REPLACEABLE_KINDS
Interests, custom emojis, and Blossom server list queries now batch
with profile/follow/mute queries instead of firing separate REQs,
reducing ~3 REQs on feed load.
2026-03-29 08:51:41 -05:00
Chad Curtis e8941e8ef6 Fix search page 'N new posts' pill showing unfiltered count
The stream buffer count was reported raw without applying client-side
filters (search query, media type, replies, protocol, mute list, etc.),
so the pill would show e.g. '10 new posts' when only 3 matched the
active search criteria. Extract the filtering predicate into a shared
matchesFilters callback and derive the pill count from filtered buffer
contents instead of the raw streamBufferCount.
2026-03-29 08:00:29 -05:00
Chad Curtis 169823980f Add arc overhang spacer to Photos and Videos pages
Both pages have a SubHeaderBar but were missing the ARC_OVERHANG_PX
spacer div that prevents content from sitting behind the arc background.
Every other page with tabs already includes this spacer.
2026-03-29 07:58:26 -05:00
Chad Curtis aa7376b357 Add pull-to-refresh to all feed pages via usePageRefresh hook
Missing pull-to-refresh on Photos, Videos, Trends, Search, Bookmarks,
TagFeed (#t/#g), DomainFeed pages meant Android users had no way to
refresh content without navigating away.

- Create usePageRefresh hook that wraps queryClient.invalidateQueries
  with a referentially-stable callback (ref-based) for PullToRefresh
- Wrap scrollable content in PullToRefresh on all affected pages
- Fix Feed.tsx: HashtagFeedContent, GeotagFeedContent, and
  SavedFeedContent tabs now include PullToRefresh (were outside wrapper)
- Refactor Events, Books, Themes pages to use usePageRefresh for
  consistency and reduced boilerplate
2026-03-29 06:54:58 -05:00
Chad Curtis 6a0e88cbf1 Fix gap between arc and top nav on relay feed page mobile 2026-03-29 06:36:14 -05:00
Chad Curtis 01b7e1cea2 Stop click propagation on delete confirmation AlertDialog content
Clicks inside the portaled AlertDialog bubble through React's synthetic
event tree to the NoteCard article, triggering post detail navigation.
Adding stopPropagation on AlertDialogContent prevents any click inside
the delete confirmation from reaching the card handler.
2026-03-29 06:23:01 -05:00
Chad Curtis 910f43e0a5 Stop click propagation in NoteMoreMenu items to prevent click-through
MenuItem button clicks inside the Radix Dialog portal bubble through
React's synthetic event system to the parent article's handleCardClick,
causing navigation to post details when selecting menu actions like
delete. Adding stopPropagation prevents this.
2026-03-29 06:21:15 -05:00
Chad Curtis 6bf630bb40 Fix delete post dialog freezing feed on desktop
Move the delete confirmation AlertDialog out of NoteMoreMenuContent
(where it was nested inside the more-menu Dialog) and into the parent
NoteMoreMenu component. The nested Radix dialogs caused overlapping
overlays and focus traps that left the page uninteractable after
confirming deletion. Now follows the same close-then-open pattern used
by Report, Mention, AddToList, and EventJson dialogs.
2026-03-29 06:16:23 -05:00