Remove the Messages tab and add a Feed tab (using PlanetIcon) as the
leftmost item in the mobile bottom navigation. Feed highlights when
on /feed or /.
Allow users to upload their own .woff2/.woff/.ttf/.otf font files via
Blossom, which are immediately applied and stored with the theme. The
uploaded font URL is preserved when publishing themes to Nostr (via the
existing f tag in the theme event schema).
Add the attribute to the file input in ComposeBox and update
the onChange handler to iterate over all selected files, uploading each
one via handleFileUpload, enabling users to select and attach multiple
files at once.
- Fix color moments rendering long text as emoji overlay; only render
single emoji (≤2 code points) as palette overlay
- Replace MapPin with ChestIcon on geocache name
- Add geohash pill badge to geocache type/size row, linking to /g/ route
- Truncate geohash display to 5 characters
- Add /g/:geohash route with GeotagPage backed by shared TagFeedPage
- DRY up HashtagPage and GeotagPage into shared TagFeedPage component
- Extend useInterests to support g tags for geohash following
- Add geotag feed tabs to home feed with MapPin icon
Break the dialog into 3 focused steps (Scope, Details, Confirm)
with animated progress indicators, dramatic destructive color
treatment, custom scope selection cards, and a centered final
confirmation with type-to-confirm input.
Implement kind 62 event publishing to allow users to request
permanent deletion of their data from relays. Includes global
(ALL_RELAYS) and targeted (specific relays) modes with a
multi-step confirmation dialog in Advanced Settings.
The wrapRef div had no dimensions, so max-w-full/max-h-full on the img
resolved against the image's own natural size rather than the available
space. Give wrapRef full width/height so percentage constraints work
correctly against the padded slot area.
Browsers (especially Safari/Firefox) require pushManager.subscribe() to be
synchronously reachable from a user gesture. The previous code awaited a
getVapidKey() network call inside enable(), which broke the activation chain
and threw 'DOMException: The operation is insecure'.
Fix: fetch and cache the VAPID key during SW registration on mount so it is
ready in vapidKeyRef before the user ever clicks Enable, making
pushManager.subscribe() the first async call after the user gesture.
The nullish coalescing operator (??) treats null as nullish, so
`null ?? <RightSidebar />` was falling through to the default.
Use an explicit null check so pages can hide the sidebar by
passing rightSidebar: null.
- Remove redundant Notification.requestPermission() from enable() since
the caller (NotificationSettings) already handles it from the user gesture.
On iOS this second call could behave unexpectedly.
- Add console.debug logging throughout the enable flow and RPC send for
diagnosing push registration issues in production.
- NotificationSettings: on web, drive the push toggle from the hook's
enabled state (actual browser subscription) instead of the NIP-78
notificationsEnabled setting which can be stale across devices.
NIP-78 is still used for the Capacitor/Android path.
- useNativeNotifications: remove the web push auto-disable effect that
raced against encrypted settings loading, causing disablePush() on
every page load before settings resolved.
- usePushNotifications: remove REGISTERED_KEY localStorage check from
the mount restore logic; derive enabled purely from
pushManager.getSubscription() like the working Ghastly reference.
Remove dead REGISTERED_KEY code entirely.
Implement NIP-53 staleness heuristic (24h threshold) to mark abandoned
status=live streams as ended. Fetch all streams globally and filter
follows client-side (including p-tag participants for streaming services).
Add Live/Planned/Past pill tabs to the streams strip on /videos.
Also fix pre-existing bug where the volume icon showed unmuted while the
video was actually muted (autoplay requires muted), by syncing the
initial muted state from the media element in usePlayerControls.
Closes#88
Conditionally render the Media section and footer only when mediaEvents
is explicitly passed, so the fields-only mobile preview shows just the
profile fields without an empty Media box or the Shakespeare link.
Only pass fields to the mobile ProfileRightSidebar preview, omitting
mediaEvents and mediaLoading so the media collage section doesn't
render in the inline mobile preview.