Commit Graph

4447 Commits

Author SHA1 Message Date
shakespeare.diy 41cdf72bab Remove all theme transitions - apply instantly
- 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>
2026-02-18 03:38:49 -06:00
shakespeare.diy e862331f38 Debounce theme sync to only save after user stops changing
- 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>
2026-02-18 03:37:53 -06:00
shakespeare.diy 62d5625adb Use View Transitions API and double RAF for smooth theme changes
- 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>
2026-02-18 03:37:18 -06:00
shakespeare.diy faef42481d Add smooth CSS transition for theme changes
- 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>
2026-02-18 03:36:35 -06:00
shakespeare.diy e4cb3fd10e Increase theme sync delay to 2 seconds
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:35:25 -06:00
shakespeare.diy 1079799eb7 Increase theme sync delay to 500ms to prevent glitch
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:34:24 -06:00
shakespeare.diy c4f65a3dde Add 100ms delay before syncing theme to prevent glitch
- 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>
2026-02-18 03:33:14 -06:00
shakespeare.diy fa36aa9d94 Fix theme change glitch - make setTheme synchronous
- Remove async from setTheme to prevent UI glitches
- Fire-and-forget encrypted settings update
- Theme changes apply instantly without waiting for signer

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:32:44 -06:00
shakespeare.diy c0f6bd6bbb Sync theme changes to encrypted settings
- 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>
2026-02-18 03:31:51 -06:00
shakespeare.diy f46e7facf1 Change encrypted settings stale time to 30 minutes
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:30:15 -06:00
shakespeare.diy 93e6848622 Add encrypted settings sync on login with stale-while-revalidate
- 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>
2026-02-18 03:29:21 -06:00
shakespeare.diy 9c79578d7a Sync feed and relay settings to encrypted Nostr storage
- 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>
2026-02-18 03:23:42 -06:00
shakespeare.diy 9400b0392a Refactor mute settings to always use encryption
- 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>
2026-02-18 03:22:05 -06:00
shakespeare.diy 149a1cf6e5 Add comprehensive mute settings with NIP-51 and encrypted content filters
- Implement useMuteList hook for NIP-51 mute lists (kind 10000)
  - Support for muting users, hashtags, words, and threads
  - Public and encrypted private mute items using NIP-44
  - Automatic normalization of npub/note identifiers
  
- Implement useContentFilters hook for encrypted client-side filters (NIP-78)
  - Advanced filtering with custom rules (kind, content, tags)
  - Multiple operators (equals, contains, regex, etc.)
  - Stored as encrypted kind 30078 events
  
- Add MuteSettingsPage with full UI
  - Tabbed interface for mute lists and content filters
  - Add/remove mutes with public/private toggle
  - Create custom filters with multiple rules
  - Collapsible sections for organized viewing
  
- Add utility functions for applying mutes
  - isEventMuted() checks if event should be filtered
  - filterMutedEvents() applies mutes to event arrays
  - getMuteSummary() provides mute statistics
  
- Add /mutes route to AppRouter

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:16:53 -06:00
shakespeare.diy 3310c25e7f Move Mutes into Settings page as a tab
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>
2026-02-18 03:12:03 -06:00
shakespeare.diy 8a28742f11 Remove Vines from mobile bottom nav
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>
2026-02-18 03:09:50 -06:00
shakespeare.diy 1e19ca255f Reorder mobile drawer to match sidebar; remove Mutes link
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>
2026-02-18 03:09:11 -06:00
shakespeare.diy 416de22ff5 Add custom kind pages to mobile drawer navigation
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>
2026-02-18 03:07:25 -06:00
shakespeare.diy 9918ca4dfe Simplify image blend to mix-blend-difference, remove custom CSS
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 03:02:54 -06:00
shakespeare.diy 01bdb9322d Replace intro art with custom mew_boy illustration, update blend logic
- 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>
2026-02-18 03:01:19 -06:00
shakespeare.diy c60768215d Theme-aware blend for intro art: darken on light/pink, lighten on dark/black
- 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>
2026-02-18 02:58:25 -06:00
shakespeare.diy 31da678784 Update intro image: w-40, 80% opacity, lighten blend mode
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:54:56 -06:00
shakespeare.diy cdd0d49a7c Enlarge intro image and place text to its right
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:45:46 -06:00
shakespeare.diy ed51116758 Size up intro image to 96px, tighten vertical spacing
- 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>
2026-02-18 02:45:19 -06:00
shakespeare.diy ac3badd0a0 Compact feed settings intro into single horizontal row
- Image, text, and column headers now share one row
- Eliminates vertical negative space before toggles
- Image shrunk to 64px inline icon
- Shortened copy slightly

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:44:42 -06:00
shakespeare.diy 06d78922ae Blend intro image into UI with mix-blend-difference
- 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>
2026-02-18 02:44:04 -06:00
shakespeare.diy ecb2a53ad1 Update intro illustration and remove box wrapper
- 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>
2026-02-18 02:43:00 -06:00
shakespeare.diy c66e5aad0b Move kind badges to descriptions, add fun intro with illustration
- 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>
2026-02-18 02:40:30 -06:00
shakespeare.diy 9322d947c2 Add kind badges, intro text, and clean up Feed settings descriptions
- 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>
2026-02-18 02:36:19 -06:00
shakespeare.diy 4f35253401 Add clear text labels to Feed settings column headers
- Replaced icon-only column headers with "Sidebar" and "Feed" text labels
- Aligned toggle columns consistently with fixed widths
- Removed tooltip-only discoverability in favor of always-visible labels

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:34:58 -06:00
shakespeare.diy c7cbb4a0e4 Clean up Feed settings: consolidate into single list with dual toggles
- 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>
2026-02-18 02:34:03 -06:00
shakespeare.diy ddafaaf1bd Move Wallet from sidebar to Settings tab, reorder Bookmarks above Settings
- 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>
2026-02-18 02:32:39 -06:00
shakespeare.diy b21909b312 Increase search page top tab padding to py-5 on desktop
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:28:00 -06:00
shakespeare.diy 985fe5e6d8 Add more spacing between trending hashtag pills and sort tabs
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:22:35 -06:00
shakespeare.diy 1f016477f6 Replace stacked hot/rising/controversial sections with sub-tabs
- 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>
2026-02-18 02:21:25 -06:00
shakespeare.diy bd12d2a873 Display trending hashtags as horizontal pill chips on trends tab
- 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>
2026-02-18 02:19:28 -06:00
shakespeare.diy 1975fd73d9 Compact trend items on trends tab to match sidebar style
- 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>
2026-02-18 02:18:48 -06:00
shakespeare.diy 4d19c6664a Remove redundant "Trending" label, add sparkline to trends tab
- 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>
2026-02-18 02:17:36 -06:00
shakespeare.diy 6272e673ae Show post counts on trending hashtags in sidebar and trends page
- Sidebar: shows "X posts · Trending" under each hashtag
- Trends page: shows "X posts" right-aligned on each hashtag row

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 02:16:22 -06:00
shakespeare.diy ac220f7391 Compact trending hashtags on trends page: limit to 5, single-line rows
- 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>
2026-02-18 02:15:22 -06:00
shakespeare.diy 4ad9df3771 Remove hot icon from sidebar, use accent color for trend page icons
- 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>
2026-02-18 02:13:37 -06:00
shakespeare.diy 5ac5f4896a Remove feed-wait gate on right sidebar, bump trend query timeouts to 10s
- 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>
2026-02-18 02:12:31 -06:00
shakespeare.diy e8ed34363c Use relay.ditto.pub as sole source for trend data
- 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>
2026-02-18 02:09:57 -06:00
shakespeare.diy 9bb489d452 Revert to 0fa3e58: Drastically reduce concurrent relay queries to prevent rate limiting
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>
2026-02-18 01:53:51 -06:00
shakespeare.diy 25b2e274be Prevent individual queries from racing with batch queries
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>
2026-02-18 01:53:12 -06:00
shakespeare.diy 0fa3e58a83 Drastically reduce concurrent relay queries to prevent rate limiting
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>
2026-02-18 01:48:27 -06:00
shakespeare.diy b2ab738d17 Remove cache2.primal.net from default relays
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>
2026-02-18 01:40:59 -06:00
shakespeare.diy 7b7f8f4811 Revert to bec0982: perf: fix gcTime Infinity → 5min, reduce useAuthor retry 3 → 1
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>
2026-02-18 01:29:56 -06:00
shakespeare.diy 1b3a1806b3 perf: batch engagement stats into 2 queries instead of 2×N per card
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>
2026-02-18 01:29:17 -06:00
shakespeare.diy b74430e655 perf: batch engagement counts with NIP-45 COUNT at feed level
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>
2026-02-18 01:26:30 -06:00