Commit Graph

184 Commits

Author SHA1 Message Date
Gigi
51c0f7d923 fix(highlights): scroll to highlight when clicked from /me/highlights
Pass highlightId and openHighlights in navigation state when clicking
highlights from the highlights list. This triggers the scroll behavior
in Bookmarks.tsx that was already implemented but not being used.

The useHighlightInteractions hook automatically scrolls to the selected
highlight once the article loads and the highlight mark is found in the DOM.
2025-10-23 00:27:35 +02:00
Gigi
829ec4bf6e fix(reading-position): fix infinite loop causing spam saves
The root cause was scheduleSave being in the scroll effect's dependency array.
Even though scheduleSave had an empty dependency array, React still saw it as
a dependency and re-ran the effect constantly, causing unmount/remount loops
and triggering flush-on-unmount repeatedly.

Solution: Store scheduleSave in a ref (scheduleSaveRef) and call it via the ref
in the scroll handler. This removes scheduleSave from the effect dependencies
while still allowing the scroll handler to access the latest version.

This fixes the "Maximum update depth exceeded" error and stops the spam saves.
2025-10-23 00:20:55 +02:00
Gigi
30ae0d9dfb fix(reading-position): prevent spam saves during scroll animation
The issue was that scheduleSave and saveNow had syncEnabled/onSave in their
dependency arrays, causing them to be recreated when those props changed.
This triggered the scroll effect to unmount/remount repeatedly during smooth
scroll animations, flushing saves on each unmount.

Solution: Use refs (syncEnabledRef, onSaveRef) for all callback dependencies,
making scheduleSave and saveNow stable with empty dependency arrays. This
prevents effect re-runs and stops the save spam.

Now the scroll effect only runs once per article load, not on every render.
2025-10-23 00:19:04 +02:00
Gigi
8924f1b307 fix(reading-position): flush pending saves on unmount
Previously, if user navigated away within the 3-second debounce window,
the pending save would be canceled and reading progress would be lost.

Now flushes any pending save on unmount if:
- There's a pending save timer active
- Position has changed by at least 5% since last save
- Not currently in suppression window (e.g., during restore)

This ensures reading progress is always saved even when navigating away
quickly, while still avoiding the 0% save issue from back navigation
(which doesn't trigger scroll events that would set up a pending save).

Uses refs to stabilize cleanup function and avoid effect re-runs.
2025-10-23 00:16:51 +02:00
Gigi
ae76d6e4ea chore(reading): remove noisy debounce log messages
Removed 'Debouncing save for 3000ms' logs that spam console on every scroll event. Keep only the actual save execution logs.
2025-10-22 23:55:59 +02:00
Gigi
7bc4522be4 fix(reading): prevent false 100% detection during page transitions
Add guards to prevent detecting 100% completion when:
- Document height is < 100px (likely during transition)
- scrollTop is < 100px (not actually scrolled)

Prevents accidentally saving 100% when navigating away at 50%.
2025-10-22 23:35:55 +02:00
Gigi
048e0d802b fix(reading): make saveNow respect suppression flag
saveNow() was bypassing suppression, causing 0% to overwrite saved positions during restore. Now checks suppressUntilRef before saving, just like the debounced auto-save.
2025-10-22 23:33:31 +02:00
Gigi
90f25420b2 debug(reading): add ISO timestamps to all position logs
Makes it easy to see exact timing of saves and identify if debouncing is working correctly.
2025-10-22 23:21:11 +02:00
Gigi
9167134a89 refactor(reading): increase debounce to 3 seconds 2025-10-22 23:18:40 +02:00
Gigi
0c8eaaf220 refactor(reading): simplify save debouncing to 2s max
Replace complex interval logic with simple 2-second debounce. Every scroll event resets the timer, so saves only happen after 2s of no scrolling (or when reaching 100%). Much less aggressive than the previous 15s minimum interval.
2025-10-22 23:17:34 +02:00
Gigi
ea69740fc8 debug(reading): add comprehensive logging for position restore and save
Add detailed console logs to trace:
- Position collection and stabilization
- Save scheduling, suppression, and execution
- Restore calculations and decisions
- Scroll deltas and thresholds

Logs use [reading-position] prefix with emoji indicators for easy filtering and visual scanning.
2025-10-22 23:14:29 +02:00
Gigi
9aa914a704 feat(reading): add save suppression to useReadingPosition
Add suppressSavesFor(ms) API to temporarily block auto-saves after programmatic scrolls, preventing feedback loops where restore triggers save which triggers restore.
2025-10-22 23:05:11 +02:00
Gigi
ba263acdff fix: stop highlights loading spinner when article has no highlights 2025-10-22 15:40:18 +02:00
Gigi
3ff57c4b67 fix(lint): add previewData to useArticleLoader effect dependencies 2025-10-22 15:36:03 +02:00
Gigi
51c364ea53 feat(article): instant preview from blog cards - show title, image, summary, date immediately via navigation state while content loads 2025-10-22 15:33:37 +02:00
Gigi
48b5aa3a30 feat(article): instant load from eventStore when clicking bookmark cards - check store by coordinate before relay query 2025-10-22 15:29:08 +02:00
Gigi
d4483a2f91 fix(lint): resolve eslint warnings in useArticleLoader - add comment for empty catch, use settingsRef consistently 2025-10-22 15:26:16 +02:00
Gigi
3f7d726ae6 feat(article): local-first streaming loader using eventStore + queryEvents in useArticleLoader; emit immediately on first store/relay hit; finalize on EOSE 2025-10-22 15:22:39 +02:00
Gigi
774e2ba67c fix(reader): clear markdown render on change and add request guards to external URL loader to prevent stale content 2025-10-22 13:45:41 +02:00
Gigi
6f1c31058f fix(reader): guard against stale article fetches overwriting current content/highlights via requestId in useArticleLoader 2025-10-22 13:41:46 +02:00
Gigi
7551a05aee fix(article): prevent re-fetch on settings change by memoizing via ref in useArticleLoader 2025-10-22 13:38:24 +02:00
Gigi
89273e2a03 refactor(settings): use startSettingsStream in useSettings hook 2025-10-22 08:54:45 +02:00
Gigi
c9208cfff2 chore: remove all debug console logs
- Remove console.log from bookmark hydration
- Remove console.log from relay initialization
- Remove all console.debug calls from TTS hook and controls
- Remove debug logging from RouteDebug component
- Fix useCallback dependency warning in speak function
2025-10-22 01:26:42 +02:00
Gigi
366e10b23a feat(/e/): check eventStore first for author profile
- Try to load author profile from eventStore cache first
- Only fetch from relays if not found in cache
- Instant title update if profile already loaded
2025-10-22 01:19:09 +02:00
Gigi
f09973c858 feat(/e/): display publication date in top-right like articles
- Remove inline metadata HTML from note content
- Pass event.created_at as published timestamp via ReadableContent
- ReaderHeader now displays date in top-right corner
2025-10-22 01:18:14 +02:00
Gigi
d03726801d feat(/e/): title 'Note by @author' with background profile fetch
- Immediate fallback title using short pubkey
- Fetch kind:0 profile in background; update title when available
- Keeps UI responsive while improving attribution
2025-10-22 01:16:30 +02:00
Gigi
1929b50892 fix: properly implement eventManager with promise-based API
- Fix eventManager to handle async fetching with proper promise resolution
- Track pending requests and deduplicate concurrent requests for same event
- Auto-retry when relay pool becomes available
- Resolve all pending callbacks when event arrives
- Update useEventLoader to use eventManager.fetchEvent
- Simplify useEventLoader with just one effect for fetching
- Handles both instant cache hits and deferred relay fetching
2025-10-22 00:55:20 +02:00
Gigi
160dca628d fix: simplify eventManager and restore working event fetching
- Revert eventManager to simpler role: initialization and service coordination
- Restore original working fetching logic in useEventLoader
- eventManager now provides: getCachedEvent, getEventLoader, setServices
- Fixes broken bookmark hydration and direct event loading
- Uses eventManager for cache checking but direct subscription for fetching
2025-10-22 00:54:33 +02:00
Gigi
c04ba0c787 feat: add centralized eventManager for event fetching
- Create eventManager singleton for fetching and caching events
- Handles deduplication of concurrent requests for same event
- Waits for relay pool to become available before fetching
- Provides both async/await and callback-based APIs
- Update useEventLoader to use eventManager instead of direct loader
- Simplifies event fetching logic and enables better reuse across app
2025-10-22 00:52:15 +02:00
Gigi
479d9314bd fix: make event loading non-blocking and wait for relay pool
- Don't show error if relayPool isn't available yet
- Instead, keep loading state and wait for relayPool to become available
- Effect will re-run automatically when relayPool is set
- Enables smooth loading when navigating directly to /e/ URLs on page load
- Fetching happens in background without blocking user
2025-10-22 00:50:14 +02:00
Gigi
b9d5e501f4 improve: better error messages when direct event loading fails
- Show error if relayPool is not available when loading direct URL
- Improved error message wording to be clearer
- These messages will help diagnose direct /e/ path loading issues
2025-10-22 00:49:50 +02:00
Gigi
43e0dd76c4 fix: don't show user highlights when viewing events on /e/ path
- Set selectedUrl and ReadableContent url to empty string for events
- This prevents ThreePaneLayout from displaying user highlights for event views
- Events should only show event-specific content, not global user highlights
- Fixes issue where 422 highlights were always shown for all notes
2025-10-22 00:48:43 +02:00
Gigi
dc9a49e895 chore: remove debug logging from event loader and compact view
- Remove debug logs from useEventLoader hook
- Remove debug logs from Bookmarks component
- Remove empty kind:1 bookmark debug logging from CompactView
- Clean console output now that features are working correctly
2025-10-22 00:46:44 +02:00
Gigi
3200bdf378 fix: add hydrated bookmark events to global eventStore
- bookmarkController now accepts eventStore in start() options
- All hydrated events (both by ID and by coordinates) are added to the external eventStore
- This makes hydrated bookmark events available to useEventLoader and other hooks
- Fixes issue where /e/ path couldn't find events because they weren't in the global eventStore
- Now instant loading works for all bookmarked events
2025-10-22 00:42:25 +02:00
Gigi
2254586960 perf: check eventStore before setting loading state for instant cached event display
- Synchronously check eventStore first before setting loading state
- If event is cached, display it immediately without loading spinner
- Only set loading state if event not found in cache
- Provides instant display of events that are already hydrated
- Improves perceived performance when navigating to bookmarked events
2025-10-22 00:38:42 +02:00
Gigi
18c78c19be fix: render events as plain text html instead of markdown
- kind:1 notes are plain text, not markdown
- Changed from markdown to html rendering
- HTML-escape content to prevent injection
- Preserve whitespace and newlines for plain text display
- Display event metadata in styled HTML header
2025-10-22 00:36:55 +02:00
Gigi
167d5f2041 fix: clear reader content when loading event and set proper selectedUrl
- Clear readerContent at start of loading to ensure old content doesn't persist
- Set selectedUrl to nostr:eventId to match pattern used in other loaders
- This ensures consistent behavior across all content loaders
2025-10-22 00:35:33 +02:00
Gigi
cce7507e50 fix: properly extract eventId from route params
- Add eventId to useParams instead of manually parsing pathname
- useParams automatically extracts eventId from /e/:eventId route
- Add debug logging to track event loading
- This fixes the issue where eventId wasn't being passed to useEventLoader
2025-10-22 00:30:54 +02:00
Gigi
e83d4dbcdb feat: render notes like articles with markdown processing
- Change useEventLoader to set markdown instead of html
- Notes now get proper markdown processing and rendering similar to articles
- Use markdown comments for event metadata instead of HTML
- This enables proper styling and markdown features for note display
2025-10-22 00:28:29 +02:00
Gigi
a5bdde68fc fix: resolve all linter and type check errors
- Fix mergeMap concurrency syntax (pass as second parameter, not object)
- Fix type casting in CompactView debug logging
- Update useEventLoader to use ReadableContent type
- Fix eventStore type compatibility in useEventLoader
- All linter and TypeScript checks now pass
2025-10-22 00:27:45 +02:00
Gigi
145ff138b0 feat: integrate event viewer into three-pane layout for /e/:eventId
- Create useEventLoader hook to fetch and display individual events
- Events display in middle pane with metadata (ID, timestamp, kind)
- Integrates with existing Bookmarks three-pane layout
- Remove standalone EventViewer component
- Route /e/:eventId now uses Bookmarks component
- Metadata displayed above event content for context
2025-10-22 00:22:04 +02:00
Gigi
f39b926e7b fix(tts): remove self-assignment in rate-change handler; keep current lang without no-op 2025-10-21 22:48:01 +02:00
Gigi
4b9de7cd07 feat(tts): make Web TTS reliable by chunking long text and resuming by chunks 2025-10-21 22:26:51 +02:00
Gigi
cadf4dcb48 perf(reading): debounce reading position saves (>=5% delta, 15s min interval, instant on completion) 2025-10-21 21:19:45 +02:00
Gigi
8c0b73ad0c fix: resolve all linting and type checking issues 2025-10-21 08:21:36 +02:00
Gigi
a5d2ed8b07 feat: hide articles from bot accounts by name; add setting (default on) 2025-10-21 07:36:00 +02:00
Gigi
66c4bfc449 refactor: remove all eslint-disable comments; fix types and deps; clean unused imports 2025-10-21 07:26:00 +02:00
Gigi
29918f78f9 refactor: remove eslint-disable comments by typing publish, fixing unused-vars, and updating effect deps 2025-10-21 07:21:01 +02:00
Gigi
fc138f3ceb feat(tts): select voice by detected/system language per utterance 2025-10-20 22:55:15 +02:00
Gigi
b14842c6fe fix(lint): wrap createUtterance in useCallback and correct deps for hooks 2025-10-20 22:29:45 +02:00