- SavedFeed type with destination field ('feed' | 'profile'), stored in
EncryptedSettings and synced via NIP-78 across devices
- useSavedFeeds hook: add/remove/rename, accepts destination param
- Search page 'Add to…' popover with two tile options:
- 'Home feed' — saves as a tab on the home page feed (always available)
- 'Profile tab' — only shown for generic searches (no author filter set);
auto-locks authorPubkey to the current user's pubkey so the tab shows
your own posts matching that search; user-specific searches are
ineligible since they already have an author scope
- Home feed (Feed.tsx) renders saved feeds as extra scrollable tabs after
Follows/Community/Global, powered by useStreamPosts (live streaming)
- Profile page (ProfilePage.tsx) renders saved feeds where destination=profile
and authorPubkey matches the viewed profile as custom tabs after Wall;
tabs are scrollable, use shrink-0 layout to avoid stretching
- Both tab bars are horizontally scrollable to accommodate many tabs
- ProfileSavedFeedContent and SavedFeedContent share the same stream-based
rendering: skeleton loading, empty state, live NoteCard list
- Replace the raw text Input in the author filter with ProfileSearchDropdown
so users get the same typeahead + avatar dropdown as the main search bar
- Add hideCountry prop to ProfileSearchDropdown to suppress country suggestions
in contexts where they are irrelevant
- Author filter only writes to URL when a profile is explicitly selected from
the dropdown (immediate commit) — typing alone never updates the URL, so
slow per-keystroke relay queries no longer cause the filter to thrash
- Show a chip with the selected author's display name and an X to clear,
replacing the dropdown while an author is active
- Add commitAuthor / clearAuthor helpers that keep the URL param and the
display label in sync; resetFilters also clears the display label
- Persist all filters (replies, media, language, platform, kind, author) to URL params so they survive refresh and can be shared
- Add author scope filter: accepts npub or hex pubkey, filters both initial batch and live streaming
- Add reset all filters button in popover header + chip strip with clear link
- Show NIP-50 search string block below the input so users can see exactly what's sent to the relay
- Show active filter chips; empty state now lists active filters with a 'Clear all' shortcut
- Add kind + media type conflict warning when both are set simultaneously
- Fix Vines streaming: hardcoded 'return false' for kind 1 changed to only reject kind 1/1111, letting 22/34236 through
- Fix streaming language/protocol gap: protocol filter is now applied client-side to live streaming events via proxy tag detection
- Wire up useContentFilters: shouldFilterEvent() now applied in useStreamPosts useMemo so user-defined content rules affect search
- Add useDebounce hook (300ms) and apply to useSearchProfiles to stop hammering relays on every keystroke
Keep the $BTC format throughout — detection strips it internally for
matching, but the stored label and Select values all use the $ prefix
so the data round-trips correctly.
- Add leading spacer to Website and Lightning rows so they align with the
drag-handle column on custom fields
- Improve inferFieldType to detect Blossom-style URLs (SHA-256 hex paths)
as media, not just URLs with file extensions
- Replace 'Add Field' button with dropdown offering Text, Wallet Address, and Media options
- Wallet fields show a ticker dropdown (BTC, ETH, SOL, etc.) as the label
- Media fields include an upload button that fills the URL value via Blossom
- All custom fields are drag-and-drop reorderable using @dnd-kit
- Existing fields auto-detect their type when loaded from profile data
- Fix BlobbiBootCache type usage (companion singular, not companions plural)
- Add effectiveCompanionD to hook return value for BlobbiPage
- Add debug logging to track kind 31125 query execution
- Add refetchOnMount: 'always' with initialDataUpdatedAt for proper cache behavior
- Add homePage config field (default: 'feed') that determines which
sidebar item renders at the '/' route
- Any sidebar item can be set as the homepage via Feed settings
- The feed is always accessible at /feed when not configured as home
- Normalize sidebar item IDs: every item follows path === '/' + id
(feed path changed from '/' to '/feed', emoji-packs renamed to emojis)
- Remove BOTTOM_NAV_ITEMS filter from MobileDrawer so all sidebar
items are visible on mobile (feed, notifications, search included)
- Mobile bottom nav dynamically reflects the configured homepage icon
- Homepage setting syncs across devices via encrypted settings
- Add emoji-packs -> emojis migration for existing sidebar orders
Muted threads now display as clickable links (shortened event ID with
an external link icon) that navigate to the thread via its nevent
identifier, instead of showing a raw unclickable hex string.
Closes#50
SelectContent used z-50 while PopoverContent used z-[200]. Both are
portaled to the body, so when a Select inside a Popover is opened,
the Select dropdown rendered behind the Popover panel. Raised
SelectContent to z-[250] so it always appears above popovers.
Closes#55
All shortcode regexes used [a-zA-Z0-9_] which excluded hyphens,
causing custom emojis like :GM-Chachi: to fail at every stage:
publishing (no emoji tag added to event), rendering (shortcode not
resolved to image), and detection (not recognized as custom emoji).
Updated the character class to [a-zA-Z0-9_-] across all 8 locations
in NoteContent, CustomEmoji, ComposeBox, and customEmoji utility.
Also added viewer's custom emoji collection as a fallback in
NoteContent so shortcodes render even when events from other clients
omit the emoji tag.
Closes#62
Two bugs prevented NIP-30 custom emoji reactions from working on /i/
pages (e.g. country pages):
1. Publishing: QuickReactMenu's onReact callback discarded the emoji
tag, so kind 17 events were published without the ['emoji', name,
url] tag needed to resolve custom emojis. Now passes emojiTag
through to the callback.
2. Display: The reaction button rendered a plain <span> that showed
raw :shortcode: text. Now uses ReactionEmoji component which
resolves custom emoji images from the event's tags.
Also updated useExternalUserReaction to return the event's tags
alongside the emoji string so custom emojis can be rendered.
Closes#62
The divider item shared bg-background/85 with regular nav items,
causing a visible pill-shaped background around the thin line. Now
only applies the background when in edit mode where it needs to be
visually distinct for drag-and-drop.
Closes#63
The useLiveStreams hook only filtered by followed pubkeys, excluding the
logged-in user's own streams from the Follows tab. Now appends
user.pubkey to the authors filter, matching the behavior of the
useFeed hook used for videos and shorts.
Closes#52
Muted users in settings/content now show their avatar and display name
instead of raw hex pubkeys. Uses useAuthor to resolve profiles with a
skeleton loading state. Non-pubkey mute types (hashtags, words, threads)
retain the existing code display.
Closes#49
Use solid destructive background with proper foreground color on hover
instead of a semi-transparent red tint with red text, which had poor
contrast and made the button text unreadable.
Closes#44
The avatar in the top-left on mobile created a double profile picture
issue when the user was logged in. Now always shows a hamburger menu
icon regardless of login state.
Closes#20
- Display lud16/lud06 lightning address on profile pages below NIP-05
badge with a zap icon
- Add lightning address to profile fields sidebar (desktop) alongside
website and custom fields
- Add lud16 input field to EditProfileForm in the website/NIP-05 grid
- Add lud16 input field to ProfileSettings in the profile fields section
- Both forms initialize from and preserve existing lud16 values
Closes#48
- Show book preview (cover, title, author) above content when viewing a
book review (kind 31985) or a kind 1 post tagged with an ISBN
- Add star rating display on book review detail pages
- Set page title to 'Book Review' for kind 31985 events
- Add visual left border to review text in feed cards for better visibility
- Extract ISBN from events using extractISBNFromEvent for both review
d-tags and i-tags on regular posts
Closes#58
- Refactor FontPicker and BackgroundPicker to support controlled mode via
optional value/onChange props (backward-compatible — uncontrolled mode
unchanged when props are omitted)
- Add 'Edit Profile Theme' button to both palette dropdown menus on the
user's own profile (above Delete Profile Theme)
- New dialog with color pickers, font picker, and background picker that
edit the profile theme (kind 16767) independently from the app theme
- Local state is initialized from the current profile theme when the
dialog opens, and saved via setActiveTheme on submit
- Update button now says 'Update "Theme Name"' (left side)
- Publish button now says 'Publish New Theme' (right side)
- Delete moved into a collapsed 'Advanced' section below the buttons
- Uses Collapsible component with ChevronDown indicator
- Add horizontal margin (1rem each side) so dialog doesn't touch screen edges
- Add rounded-lg for consistent border radius on mobile
- Shorten button labels ('Update' / 'Publish') and allow footer to flex-wrap
to prevent overflow with multiple buttons
- Remove onEdit prop from ThemeButton and all related plumbing (onEditTheme
in ThemeGrid, handleEditTheme in ThemeSelector, Pencil icon overlay)
- Add Delete button in the builder dialog footer (visible only when editing
an existing theme), using the existing deleteTheme from usePublishTheme
- Delete resets theme to system and closes the builder dialog
Add fabIcon prop to LayoutOptions and FloatingComposeButton so pages can
override the default Plus icon. The Themes page now shows a Pencil icon
on its FAB to indicate editing/customizing rather than composing.
Active Theme card sits first in the grid, followed by My Themes cards
in the same grid with separate section labels using col-span-full.
The active theme is filtered out of both My Themes and Presets sections
so it only appears once.
- Remove the Edit button from the ThemesPage header (FAB + grid edit icons
are sufficient for accessing the builder)
- Split the flat theme grid into three labeled sections:
1. Active Theme — shows the currently active theme as a single card
2. My Themes — user's published themes with edit icons (only shown when
themes exist)
3. Presets — builtin themes (System/Light/Dark) and preset themes
- ThemeGrid component is unchanged (still used by onboarding carousel)
- ThemeSelector's customize card (color pickers, font, background, publish)
and auto-share toggle now live inside a Dialog instead of inline
- FAB (compose button) on the My Themes tab opens the builder in 'new' mode
- Header 'Edit' button opens the builder for the current theme
- User theme cards in the grid show a Pencil edit icon on hover that opens
the builder in edit mode for that specific theme
- Builder dialog shows 'New Theme' or 'Edit Theme' title based on mode
Move the ThemeSelector (formerly on the Vibe/settings/theme page) into the
Themes page as the first 'My Themes' tab, alongside new 'Follows' and
'Global' feed tabs for browsing published themes.
- Delete ThemeSettingsPage and ThemeBuilderPage (builder lives inline in ThemeSelector)
- Remove Vibe sidebar entry and settings section
- Add useThemeFeed hook for follows/global theme event filtering
- Rename 'Vibe' to 'Theme' in account popover dropdown
- Update all links from /settings/theme to /themes
Install Cinzel, Nunito, Quicksand, Courier Prime, and Comic Neue as
bundled fonts and register them in the font registry. Add Unsplash
background images to every new preset (Gothic, Cottage, Candy Heart,
Midnight, Hologram, Floret, Win 95, Plush).
Wire up the non-functional X button so clicking it dismisses accounts
from the list. Dismissed pubkeys are persisted to localStorage so they
stay hidden across page reloads.
Implements the initial Blobbi ecosystem (egg stage only) per the spec:
- Kind 31125 (Blobbonaut Profile) with canonical d-tag and legacy support
- Kind 31124 (Blobbi Current State) with canonical d-tag and seed derivation
- localStorage boot cache for instant UI on page load
- Profile initialization, egg creation, rest action, visibility toggle
- Preserves unknown tags when republishing for forward compatibility