- Strip out View Transitions API and RAF complexity
- Just apply theme class change synchronously
- Debounce still prevents signer spam
- Let browser handle the paint naturally
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Use debounced timer with 1 second delay
- Only triggers signer prompt after user settles on a theme
- Prevents repeated prompts when clicking through themes
- Reduces glitching by avoiding prompt during active theme switching
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Use native View Transitions API when available for smooth theme switch
- Fall back to manual transitions with double requestAnimationFrame
- Double RAF ensures theme change happens after browser paint cycle
- Prevents glitching even when React re-renders from signer prompt
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Apply 300ms transition to background and text colors during theme switch
- Prevents jarring flash when signer prompt appears
- Transition removed after completion to avoid affecting other animations
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Delay encrypted settings update to let theme apply to DOM first
- Prevents visual glitch when signer prompt appears
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Update useTheme to save theme to encrypted storage when changed
- Theme now syncs across devices like other settings
- Prompts signer when changing theme while logged in
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- NostrSync now loads encrypted settings from Nostr on login
- Settings sync to local AppContext (theme, feedSettings, useAppRelays)
- Use 5-minute staleTime for fresh page loads to pick up changes
- Settings refetch automatically after 5 minutes on new page load
- No expensive real-time subscriptions - just periodic refresh
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Update FeedSettingsForm to save to encrypted settings when toggling
- Update RelayListManager to sync app relay toggle to encrypted storage
- Feed preferences and relay toggle now prompt for signer when changed
- Settings sync across devices via NIP-78 encrypted events
- Local storage still used for immediate UI updates (dual-write pattern)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Remove silly public/private toggle - all mutes are now encrypted by default
- Update useMuteList to store everything in encrypted content field
- Remove isPrivate field from MuteListItem interface
- Simplify MuteSettings UI by removing encryption toggle
- Update muteHelpers to remove hasPrivate from summary
- Add useEncryptedSettings hook for unified app settings storage
- Integrate MuteSettings component into SettingsPage /settings/mutes tab
- Refactor useContentFilters to use unified encrypted settings
- All sensitive user preferences now encrypted with NIP-44
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Mutes is now a tab in the Settings page (Settings > Mutes) instead of a
standalone route. Removed the /mutes route and PlaceholderPage import
from the router. The mutes tab shows a placeholder state for now until
the full mute list management UI is built.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Vines is now accessible through the mobile drawer alongside the other
custom kinds, so it no longer needs a dedicated bottom nav tab. Bottom
nav is now just Home, Notifications, Search.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Drawer now shows extra kinds first, then Profile, Bookmarks, Settings —
matching the desktop sidebar order (minus Home/Notifications/Search
which live in the bottom nav). Mutes link removed from the drawer since
it belongs in Settings.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Show enabled extra kinds (Vines, Polls, Treasures, Colors, Follow Packs)
in the mobile slide-out drawer under an "Other Stuff" section, matching
the desktop sidebar behavior. Items are driven by the same feedSettings
config so toggling them in settings updates both desktop and mobile nav.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Swapped to provided gray-on-white line art
- Light/pink: darken blend (gray lines show naturally)
- Dark/black: lighten + invert (lines become light on dark bg)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added .blend-art CSS utility that inverts + darkens on light backgrounds
and lightens on dark backgrounds
- Works across all four themes (light, dark, black, pink)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Image back to centered above text at w-24 (96px)
- Minimal vertical gaps between image, heading, and description
- Column headers separated into their own tight row
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Uses mix-blend-difference so black background disappears and
white lines adapt to any theme color automatically
- Lowered opacity for a subtle, integrated feel
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- New whimsical stick figure head with floating doodle icons
- Removed rounded box/card wrapper, image sits openly in the layout
- Sized down illustration for subtlety
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Kind badges now appear as [xxxxx] prefix on description lines, not titles
- Added Nintendo-style instruction illustration explaining "Other Stuff"
- Rewrote intro copy to be friendlier and more fun
- Removed old webp illustration file
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added "Content Types" heading with beginner-friendly explanation of what
Nostr content types are and why you'd toggle them
- Added kind number badges inline before each label (replacing parenthetical
kind references in descriptions)
- Cleaned up descriptions to be concise without redundant kind numbers
- Sub-kind rows now also show kind badges for consistency
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Merged "Sidebar Links" and "Feed Content" sections into one unified list
- Each content type now shows both sidebar and feed toggles side by side
- Removed redundant kind number badges for cleaner appearance
- Added column header icons (sidebar/feed) with tooltips for clarity
- Sub-kind rows fade out when parent is disabled
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Created WalletSettings component with wallet management UI
- Added "Wallet" tab to SettingsPage
- Removed Wallet nav item from LeftSidebar and MobileDrawer
- Moved Bookmarks above Settings in both LeftSidebar and MobileDrawer
- Removed /wallet route from AppRouter
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added Hot/Rising/Controversial as tabbed sub-navigation on trends tab
- Only one sort mode fetched at a time instead of all three
- Removed SortedPostsSection component (no longer needed)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Hashtags now render as inline pill-shaped chips in a flex-wrap row
- Each chip shows #tag + count, compact and horizontal
- Removed sparkline from trend items (not needed in chip layout)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Single-row layout: tag name + count inline, sparkline on right
- Removed dividers between trend items
- Tighter vertical padding for less wasted space
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Sidebar: shows only "X posts" under each hashtag, no "Trending"
- Trends tab: each hashtag row now includes the sparkline graphic
- Exported TrendSparkline for reuse across components
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Capped trending hashtags to top 5 on the trends tab
- Collapsed TrendItem to a single compact row with tag name left
and "Trending" label right, reducing vertical space
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Removed Flame icon from "Hot Posts" heading in the right sidebar
- Changed Hot/Rising/Controversial icons on the search trends tab
from hardcoded orange/green/red to text-primary (accent color)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Sidebar data now loads immediately when the xl breakpoint is met,
instead of waiting for the feed to finish fetching first
- Increased AbortSignal timeout from 5s to 10s on all Ditto relay
trend queries (trending tags, trending posts, sorted posts)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Rewrote useTrendingTags to query kind 1985 label events from
relay.ditto.pub (L: pub.ditto.trends, l: #t) instead of counting
hashtags from recent notes
- Added useTrendingPosts hook for trending events via kind 1985 #e labels
- Added useSortedPosts hook using NIP-50 search extensions (sort:hot,
sort:rising, sort:controversial) against relay.ditto.pub
- Updated RightSidebar: trending hashtags → hot posts → new accounts
- Updated SearchPage Trends tab with trending hashtags section plus
top 5 hot, rising, and controversial post sections
- Added URL param support for tab=trends on search page
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This reverts the codebase back to the state at commit 0fa3e58.
Reverted 1 commit(s):
- 25b2e27: Prevent individual queries from racing with batch queries
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
useAuthor and useEventStats were firing individual queries simultaneously
with the batch hooks (useAuthors, useBatchEventStats), causing a flood of
concurrent relay subscriptions. Each NoteCard's useAuthor created its own
kind:0 query even though useAuthors in Feed.tsx was about to fetch the
same data in a single batched query.
Fix: Use useIsFetching to detect when a batch query is in-flight and
disable individual queries until the batch completes. The batch seeds
individual cache entries, so useAuthor/useEventStats resolve instantly
from cache without ever firing their own relay queries.
On pages without batch queries (PostDetailPage, NotificationsPage, etc.),
batchFetching === 0 immediately, so individual hooks fire normally.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The app was firing an excessive number of concurrent REQs, causing relays
to return "too many concurrent REQs" errors. Root causes and fixes:
1. **Batch event stats** (biggest win): Created `useBatchEventStats` hook
that fetches interaction stats for ALL visible feed items in a single
relay query instead of 2 queries per NoteCard. For a 15-item feed this
reduces ~30 concurrent REQs to just 1. Results are seeded into the
individual `['event-stats', id]` cache for instant resolution.
2. **Merged dual queries**: Both `useEventStats` and `useEventInteractions`
were firing 2 parallel queries (e-tag + q-tag). Merged each into a
single query using multiple filter objects (relay handles as OR).
3. **Reduced limits across the board**:
- useEventStats: limit 200+50 → 50+20 (single query)
- useEventInteractions: limit 500+100 → 50+20 (single query)
- useTrendingTags: limit 200 → 50
- useReplies: limit 100 → 50
- useProfileFeed PAGE_SIZE: 30 → 20
- useStreamPosts/useStreamKind subscription limit: 100 → 0
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Primal's cache relay uses a proprietary protocol that doesn't support
standard Nostr filters (kinds, authors). It was returning NOTICE errors
("kinds or authors filter is not supported") for every query, causing
unnecessary noise and potential issues.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This reverts the codebase back to the state at commit bec0982.
Reverted 2 commit(s):
- 1b3a180: perf: batch engagement stats into 2 queries instead of 2×N per card
- b74430e: perf: batch engagement counts with NIP-45 COUNT at feed level
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Replace per-card useEventStats (2 queries per NoteCard = 30 queries for
15 posts) with useBatchedEventStats at the feed level. Fires 2 combined
queries for ALL event IDs at once, processes results, and seeds the
individual ['event-stats', eventId] cache entries. Each NoteCard's
useEventStats() then resolves instantly from cache — same data, same
pattern as useAuthors, no prop changes needed.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Replace per-card useEventStats queries (2 heavy queries × N posts) with
a single useEngagementCounts hook that fires lightweight NIP-45 COUNT
requests in parallel via relay.ditto.pub. Feed passes counts as props;
NoteCard only falls back to per-card queries when rendered outside a
feed (e.g. PostDetailPage).
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>