Prevent the compose modal from being accidentally dismissed when the user
taps the emoji/GIF picker overlay to close it. On mobile this was very
easy to trigger, causing the draft to be lost.
Add onInteractOutside and onEscapeKeyDown handlers to the compose modal's
DialogContent that detect when a nested dialog (emoji picker) is open and
prevent the dismiss event from propagating to the parent modal.
Notifications now say 'reacted to your badge', 'reposted your theme',
'commented on your nsite', etc. instead of always saying 'your post'
or 'your note'. Uses the referenced event's kind to look up a
human-readable noun from a comprehensive kind-to-label map.
The BadgeDetailContent action bar had reactions, reposts, and comments
but was missing the zap button that NoteCard renders for the same
events in the feed.
Extract shared useInsertText hook to DRY up the duplicated text
insertion logic across ComposeBox, DMChatArea, and ZapDialog.
Add EmojiPicker (GUI) and EmojiShortcodeAutocomplete (:shortcode
typing) to the zap comment textarea, and also add shortcode
autocomplete to the DM chat input which was previously missing it.
Closes#176
On mobile, toasts enter from the top but previously could only be swiped
right to dismiss. Now swipe direction is responsive: swipe up on mobile
(top-positioned), swipe right on desktop (bottom-right positioned). Exit
animations also match the swipe direction at each breakpoint.
Kind 16767 events previously hardcoded description to undefined, so the
theme description never appeared on 'updated their theme' posts in the
feed or detail view.
Three changes:
- buildActiveThemeTags now accepts and includes a description tag, so
future kind 16767 events carry the description directly
- setActiveTheme accepts description to thread it through publishing
- ThemeContent extracts the description tag from kind 16767 events, and
for older events without one, falls back to querying the source theme
definition via the a-tag reference
On the feed, theme descriptions are truncated to a single line. On the
post detail page, the full description is now displayed so users can
read long descriptions that don't fit in the thumbnail card.
Closes#124
The <a download> and <a target="_blank"> patterns don't work in
WKWebView. Add downloadTextFile() and openUrl() utilities in
src/lib/downloadFile.ts that use @capacitor/filesystem and
@capacitor/share on native platforms, falling back to standard
browser behavior on web.
Update all call sites: onboarding key download (InitialSyncGate,
SignupDialog), image lightbox buttons (ImageGallery, ProfilePage).
Document Capacitor compatibility constraints in AGENTS.md.
Closes#186. Badge award notifications now display a visual preview
card with the badge image, name, and description for both single and
grouped badge notifications.
Show the sender's profile pic via the EnvelopeCard component (the same
Wii-Mail-inspired envelope tile used in the letters inbox). The card
auto-decrypts to display stationery colors and the sender's avatar as a
wax seal. Clicking the envelope navigates to /letters.
Letters were completely absent from the notification pipeline — users had
to visit the Letters page to discover incoming letters. This integrates
kind 8211 into every layer of the notification system:
- useNotifications: query, grouping, and referenced-event exclusion
- useHasUnreadNotifications: unread dot indicator
- NotificationsPage: LetterNotification component with link to /letters
- NotificationSettings: toggleable Letters row
- notificationTemplates: web push template
- Android NotificationRelayService + NostrPoller: native push support
- EncryptedSettings + schema: letters preference field
Closes#188
The useBadgeFeed hook required a logged-in user before enabling the query,
causing the follows tab to show loading skeletons forever when logged out.
Now fetches the Team Soapbox follow pack (kind 39089) and uses its members
as the authors filter, giving logged-out users a curated badge feed.
- MobileTopBar: changed from sticky to fixed positioning with scroll-hide
transform animation (mirrors bottom nav behavior via useScrollDirection)
- MainLayout: replaced -mt-mobile-bar overlap trick with pt-mobile-bar
padding since the top bar is now fixed; added data-nav-hidden attribute
to drive CSS transitions on sticky sub-headers
- SubHeaderBar/top-mobile-bar: sticky top offset transitions to 0 when
the top bar hides, keeping sub-headers flush with the viewport top
- NotificationsPage, ProfilePage: added arc overhang spacer after
SubHeaderBar to match Feed's spacing
Expose COMMIT_SHA and COMMIT_TAG via import.meta.env at build time.
In CI, these come from GitLab env vars; locally they fall back to git.
The changelog page now shows:
- A pre-release banner when the build is untagged, with a link to
the GitLab diff between the latest release and main
- An external link icon on each version card header linking to the
GitLab release page for that version
- Switch from CalVer (date+SHA) to semantic versioning starting at v2.0.0
- Create release skill (.agents/skills/release/) with full AI-guided release workflow
- Add CHANGELOG.md with initial 2.0.0 entry
- Update CI tag regex to match semver tags (v2.0.0 instead of v2026.03.24-sha)
- Extract changelog content into GitLab release descriptions
- Update Android versionName to 2.0.0 in build.gradle
- Update iOS MARKETING_VERSION to 2.0.0 in pbxproj
- Expose VERSION (semver) and BUILD_DATE (ISO 8601) as build-time constants
- Display version and build date in Settings page footer
- Remove npm release script (releases are now done via the AI skill)
- LetterEditor: replace stickyHeader/headerLeft with renderToolbar render prop;
callers decide where to place the tool buttons
- Both ComposeLetterSheet and LetterPreferencesSection: use SubHeaderBar noArc
+ useLayoutOptions({ hasSubHeader: true }) so tools sit in the sticky sub-header
matching every other tabbed/sub-header page in the app
- Extract FabButton from FloatingComposeButton (avatar shape mask + primary bg)
- FloatingComposeButton now delegates to FabButton
- ComposeLetterSheet: replace inline send button with FabButton FAB,
fixed bottom-right on mobile, sticky in column on desktop
- Remove separate page-level send button from compose header
- useLetterPreferences: simplify to just expose raw saved prefs + isThemeDefault flag,
no longer conflates theme stationery with saved stationery
- LetterPreferencesSection: always pull from useThemeStationery directly when
isThemeDefault, persist only on explicit user picks (handleSetStationery),
sync preview live when theme changes
- ComposeLetterSheet: same pattern — init from themeStationery, switch to saved
pref once settings load, track explicit user picks to avoid theme override
- LetterEditor drawer: remove bg-background / rounded-b-3xl / border-b card shape