Install @capacitor/haptics and add a centralized haptics utility
(src/lib/haptics.ts) that uses the native taptic engine on iOS/Android
and falls back to navigator.vibrate() on web.
Haptics added to:
- Switch component (covers 36+ toggle switches app-wide)
- PullToRefresh threshold (covers 15+ pages)
- MobileBottomNav tab taps
- ReactionButton (like/unlike, double-click heart)
- RepostMenu (repost/undo repost)
- ZapDialog button press + payment success (NWC and WebLN)
- FollowButton and ProfilePage follow toggle
- ComposeBox (post, voice message, and poll publish success)
- NoteMoreMenu (bookmark, pin, mute)
- VinesFeedPage reaction and repost buttons
- ProfileReactionButton and ExternalReactionButton
- NoteCard share button
- BlobbiRoomShell swipe navigation
Replaces raw navigator.vibrate() calls in GameControls and
SendAnimation with the new cross-platform haptics utility, fixing
haptic feedback on iOS where the Vibration API is not available.
NIP-09 deletion events for addressable events (kinds 30000-39999) now
include both an 'e' tag (event ID) and an 'a' tag (event coordinate)
to ensure deletion works on relays that only support one or the other.
- useDeleteEvent: accept optional pubkey/dTag params, auto-add 'a' tag
for addressable kinds
- NoteMoreMenu: pass event pubkey and d-tag to useDeleteEvent
- BadgesPage: add missing 'e' tag to badge definition deletion
- useUserLists: add missing 'e' tag to list deletion
- EnvelopeCard: add ... overflow menu trigger using NoteMoreMenu (no duplicated logic)
- NoteMoreMenu: detect NIP-44 ciphertext by content shape, show 'Encrypted content'
- LetterDetailSheet: reply button (InkPenIcon, primary colors); gift above card; letter centered in viewport; click outside closes
- LettersPage: reply pre-fills sender npub; default stationery falls back to parchment when no custom theme; 2-col mobile / 4-col desktop grid
- NotificationsPage: reply button next to 'View all letters' in letter notifications
- ComposeLetterSheet: auto-focus textarea on open; fix To field overflow on narrow screens
- InkPenIcon: new custom icon replacing PenLine on FAB and reply buttons
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.
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.
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.
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.
- 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 NIP-51 Follow Sets management (useUserLists, UserListsPage at /lists)
- Add Follow Packs support (useFollowPacks) for curated people lists
- Add FeedEditModal for creating/editing home feed tabs with author scope,
kind picker, and list/pack author population
- Add AddToListDialog accessible from the note more-menu
- Unify home feed tab resolution with profile tabs via useResolveTabFilter,
supporting $follows variable expansion
- Wire People filter in Search and FeedEditModal with list/pack picker
- Extract shared ScopeToggle, ListPackPicker, parseSelectedKinds primitives
into SavedFeedFiltersEditor to eliminate duplication across three call sites
- Cache savedFeeds in AppConfig for instant tab render on load
- Strip orphaned profile-destination entries from encrypted settings on read
- Copy Event ID now copies naddr1 for addressable events or nevent1 for
others, instead of raw hex
- Add ReportDialog component with NIP-56 kind 1984 reporting (7 report
types, optional details textarea, scrollable on small screens)
- Wire report dialog into both NoteMoreMenu (post reports) and
ProfileMoreMenu (profile reports)
- Mention action opens compose modal with nostr:npub pre-filled
- Fix dialog lifecycle: report/mention state lives in outer component to
survive menu unmount
Cap the dialog at 85dvh with overflow-y-auto so it scrolls when
content is tall. Also add a hard max-h on the post preview text
to prevent line-clamp-3 failures with nested block elements from
NoteContent.
- 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
- Defer bookmark/pin queries in NoteMoreMenu until menu is opened
- Move RightSidebar outside Suspense to prevent default sidebar queries on profile pages
- Split profile metadata: kind 0 piggybacked on feed query, kind 3+10001 fetched separately
- Share single feed query across posts/replies/media tabs (filter client-side)
- Reduce feed page size from 60 to 15 to match main feed
- Fix pagination using raw event count instead of filtered count
- Remove duplicate pinned events query from usePinnedNotes
- Add staleTime to useMuteList to prevent refetch on every navigation
- Add skeleton loading for banner, avatar, name, and pinned posts
- Stabilize streak calculation to use raw feed data across all tabs
Wire up the previously stubbed 'Mute @user' and 'Mute Conversation' menu
actions in NoteMoreMenu and ProfilePage to call useMuteList().addMute,
with toggle support for unmuting. Apply mute filtering (via isEventMuted
from muteHelpers) across all feed surfaces: main feed, profile feed,
notifications, post detail replies, search/explore stream, hashtag page,
domain feed, trending posts, and right sidebar.
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.
- Wrapped mute conversation, mention, mute user, and report options with !isOwnPost checks
- Only show these options when viewing someone else's post
- Pin to profile option remains available only on own posts
- Fixes issue where inappropriate moderation options were shown on user's own content
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Removed 'Show Post Details' option (redundant on detail page)
- Added 'Copy Event ID' to copy hex event ID
- Added 'Copy Event JSON' to copy full event as formatted JSON
- Replaced ArrowUpDown icon with FileJson for JSON copy option
- Created usePinnedNotes hook for NIP-51 kind 10001 pinned notes management
- Created useProfileFollowing hook to fetch any profile's follow list and count
- Added following count (with Users icon) to the left of the post streak on profiles
- Clicking following count opens a scrollable modal listing all followed users
- Pinned posts now display at the top of the Posts tab with a pin indicator
- Added "Pin on profile" / "Unpin from profile" option to the post "..." menu
(only visible for user's own posts)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Create PostDetailPage with expanded post view showing author info,
full content, images, stats (reposts, likes, zap amount), full date,
action buttons, and inline reply composer
- Create useEvent hook for fetching single events by hex ID
- Create useReplies hook for fetching kind:1 replies to an event
- Update NIP19Page to render PostDetailPage for note1/nevent1 identifiers
- Make NoteCard clickable to navigate to post detail via nevent1 URL
- Fix NoteMoreMenu to use React Router navigate instead of window.location.href
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- NoteMoreMenu now shows a compact post preview at the top (avatar,
author name, timestamp, and 3-line-clamped content) before menu items
- Dialog overlay updated globally: bg-black/60 + backdrop-blur-sm for a
frosted-glass effect behind all modals
- FloatingComposeButton modal reworked to match the same presentation
pattern: rounded-2xl, hidden default close button replaced with a
centered header (X / "New post" title), separator, compose area
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Created NoteMoreMenu component as a centered dialog with grouped actions:
- Show Post Details, Copy Link to Post, View on njump.me, Bookmark
- Mute Conversation, Mention @user
- Mute @user, Report @user (destructive)
- Close button
- Added the ⋯ More button back to NoteCard action bar alongside Bookmark
- Menu items show the author's display name dynamically
- Copy Link copies nevent-based URL to clipboard with toast feedback
- Bookmark option in the menu toggles bookmark state via useBookmarks hook
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>