- Replace @typescript-eslint/no-explicit-any with proper Filter type from nostr-tools/filter in dataFetch.ts and helpers.ts
- Replace @typescript-eslint/no-explicit-any with IAccount and AccountManager types from applesauce-accounts in hooks
- Replace @typescript-eslint/no-explicit-any with unknown type casts in App.tsx for keep-alive subscription
- Fix react-hooks/exhaustive-deps warnings by including all dependencies in useEffect hooks
- Remove unused _settings parameters in useImageCache.ts that were causing no-unused-vars warnings
- Update default from paper-white to sepia for warmer reading
- Midnight remains default for dark mode
- Sepia provides warm, eye-friendly tones for light mode
- Add darkColorTheme: black, midnight (default), charcoal
- Add lightColorTheme: paper-white (default), sepia, ivory
- Extend UserSettings with color theme fields
- Update ThemeSettings UI to show color options
- Add CSS variables for all color theme variants
- Sepia and Ivory have warm, reading-friendly palettes
- Black offers true black for OLED screens
- All color themes sync via Nostr (NIP-78)
- Remove localStorage.setItem/getItem from theme.ts
- Simplify early boot script to just default to system theme
- Theme now loads purely from NIP-78 settings
- Prevents race conditions between localStorage and Nostr settings
- Define semantic color tokens (--color-bg, --color-text, etc.)
- Add .theme-dark, .theme-light, .theme-system CSS classes
- Create theme.ts utility for theme application
- Add early boot theme script to prevent FOUC
- Support system preference with live updates
- Update nostrUriResolver to return internal /p/:npub links for npub/nprofile
- Replace external profile links with React Router Link components
- Update ResolvedMention, LargeView, and CardView components
- Convert nprofile to npub before routing
- Keep note/nevent links as external (no internal viewer yet)
- Walk original text across node boundaries while tracking normalized positions
- Identify exact start/end nodes and offsets for the match
- Compute combined indices from node spans to create accurate DOM Range
- Eliminates artifacts like 'We b' by preventing whitespace from splitting words
- Keeps strict bounds checks and graceful failures
- Strip all existing mark elements from HTML before re-highlighting
- Prevents old broken highlights from persisting in the DOM
- Ensures clean text is used as the base for new highlight application
- Fixes 'We b' spacing issue caused by corrupted marks from previous buggy renders
- Remove debug logging now that position mapping is working correctly
- Log search text, match indices, and extracted text during position mapping
- Show sample of combined text around the extracted range
- Help identify where position mapping is going wrong for 'We b' issue
- Build explicit position map array from normalized to original text indices
- Properly handle whitespace sequences in position mapping
- Ensure each normalized character position maps to correct original position
- Validate mapped positions are within bounds before using
- Fixes spacing issues like 'We b' appearing instead of 'Web' in highlights
- Validate extracted range text matches search text before highlighting
- Check single-node matches are not empty or whitespace-only
- Compare both exact and normalized text to handle whitespace variations
- Prevent broken/corrupted highlights from being applied to DOM
- Add detailed logging for validation failures to aid debugging
- Implement proper normalized-to-original text position mapping
- Add comprehensive validation for range indices and node offsets
- Verify range is not collapsed before extracting content
- Add try-catch block to handle DOM manipulation errors gracefully
- Add detailed warning logs for debugging failed highlight matches
- Prevent invalid ranges from corrupting the DOM structure
- Fix broken text nodes and visual artifacts in highlighted content
- Use DOM Range API to extract and wrap content in a single mark element
- Preserves internal DOM structure (links, formatting) within the highlight
- Eliminates visual breaks between multiple mark elements
- Ensures highlight appears as one continuous selection even across inline elements
- Add tryMultiNodeMatch function to find text spanning multiple DOM nodes
- Build combined text from all text nodes for comprehensive matching
- Handle highlighting across node boundaries with proper offsets
- Falls back to multi-node matching when single-node match fails
- Fixes issue where selections with inline formatting couldn't be matched
- Create nostrGateways.ts config file with PRIMARY (njump.me) and SEARCH (search.dergigi.com) gateways
- Add helper functions: getProfileUrl, getEventUrl, getNostrUrl
- Update all hardcoded gateway URLs across the codebase to use the config
- Updated files: HighlightItem, nostrUriResolver, BookmarkViews (Card/Large), ResolvedMention
- Remove unused React import from nostrUriResolver
- Add block scoping to switch case statements
- Add react-hooks plugin to eslint config
- Fix exhaustive-deps warnings in components
- Fix DecodeResult type to use ReturnType<typeof decode>
- Update dependency arrays to include all used values
- Add eslint-disable comment for intentional dependency omission
All linting warnings resolved. TypeScript type checking passes.
- Add articleTitleResolver service to fetch article titles from relays
- Extract naddr identifiers from markdown content
- Fetch article titles in parallel using relay pool
- Replace naddr references with actual article titles
- Fallback to identifier if title fetch fails
- Update markdown processing to be async for title resolution
- Pass relayPool through component tree to enable resolution
Example: nostr:naddr1... now shows as "My Article Title" instead of "article:identifier"
Improves readability by showing human-friendly article titles in cross-references
- Articles (naddr) now link to /a/{naddr} route (internal)
- Other nostr identifiers still link to njump.me (external)
- Improved article labels to show identifier instead of generic text
- Better UX: clicking article references opens them in-app
- Add nostrUriResolver utility to detect and replace nostr: URIs
- Support npub, note, nprofile, nevent, and naddr identifiers
- Convert nostr: URIs to clickable njump.me links
- Process markdown before rendering to handle nostr mentions
- Add CSS styling for nostr-uri-link class
- Implements NIP-19 and NIP-27 (nostr: URI scheme)
Nostr-native articles can now contain references like:
- nostr:npub1... → @npub1abc...
- nostr:note1... → note:note1abc...
- nostr:naddr1... → article:identifier
All identifiers become clickable links to njump.me
- Add relay tracking to Highlight type (publishedRelays, isLocalOnly fields)
- Create utility functions to identify local relays (localhost/127.0.0.1)
- Update highlight creation service to track which relays received the event
- Detect when highlights are only on local relays and mark accordingly
- Add visual indicator in UI for local-only highlights with amber badge
- Enable immediate display of highlights created offline
- Ensure highlights work even when only local relay is available
- Add summary field when converting ArticleContent to ReadableContent
- Fix contentLoader.ts to include article.summary
- Fix useArticleLoader.ts to include article.summary
- Article summaries now properly display in reader header
- Resolves missing summary display for kind:30023 articles
- Create textMatching module for text search utilities
- Create domUtils module for DOM manipulation helpers
- Create htmlMatching module for HTML highlight application
- Reduce highlightMatching.tsx from 217 lines to 59 lines
- All files now under 210 lines
- Extract URL from 'd' tag for kind:39701 web bookmarks
- Add protocol prefix (https://) if missing from web bookmark URLs
- Make classifyUrl handle undefined input gracefully
- Prevent crash when web bookmarks have no content
- Convert loadFont to async function that returns a Promise
- Use Font Loading API to wait for fonts to be actually ready
- Add comprehensive logging for font loading stages
- Wait for font loading in useSettings before applying CSS variables
- Update Settings component to handle async font loading
- Prevents FOUT (Flash of Unstyled Text) by ensuring fonts are ready
- Fixes timing issue where custom fonts weren't being applied consistently
This ensures custom fonts are fully loaded and ready before being applied,
eliminating the race condition where content would render with system fonts
before custom fonts were available.
- Add extensive logging to track highlight rendering through entire pipeline
- Fix markdown rendering to wait for HTML conversion before displaying
- Prevent fallback to non-highlighted markdown during initial render
- Add debugging to URL filtering to identify matching issues
- Add logging to highlight application to track matching success/failures
- Ensure highlights are always applied when content is ready
- Show mini loading spinner while markdown is being converted
This will help diagnose and fix cases where highlights aren't showing up.
- Add three highlight levels: nostrverse (all), friends (followed), and mine (user's own)
- Create contactService to fetch user's follow list from kind 3 events
- Add three configurable colors in settings (purple, orange, yellow defaults)
- Replace mode switcher with independent toggle buttons for each level
- Update highlight rendering to apply level-specific colors using CSS custom properties
- Add CSS styles for three-level highlights in both marker and underline modes
- Classify highlights dynamically based on user's context and follow list
- All three levels can be shown/hidden independently via toggle buttons
Fixes:
- Fixed highlight filtering for Nostr articles in urlHelpers.ts
Now returns all highlights for nostr: URLs since they're pre-filtered
- This fixes highlights not appearing in article content
Features:
- Added highlight mode toggle: 'my highlights' vs 'other highlights'
- Icons: faUser (mine) and faUserGroup (others)
- Mode toggle only shows when user is logged in
- Filters highlights by user pubkey based on selected mode
- Default mode is 'others' to show community highlights
- Added CSS styling for mode toggle buttons
Result: Highlights now show both in the panel AND underlined in
the article text. Users can switch between viewing their own
highlights vs highlights from others.
Extracted large functions into separate modules to follow DRY principles
and keep files manageable:
- Created useArticleLoader.ts hook (92 lines)
- Handles article loading from naddr
- Fetches article content and highlights
- Sets up article coordinate for refresh
- Created contentLoader.ts utility (44 lines)
- Handles both Nostr articles and web URLs
- Unified content loading logic
- Reusable across components
Result: Bookmarks.tsx reduced from 282 to 208 lines ✅
All files now under 210 line limit while maintaining functionality.
- Extract URL normalization to urlHelpers utility (DRY)
- Condense Settings.tsx from 212 to 190 lines
- Inline IconButton props on single lines
- Shorten preview text
- Condense ContentPanel.tsx from 223 to 190 lines
- Extract filterHighlightsByUrl function
- Remove unnecessary logic
- All files now under 210 line limit
- All lint and type checks pass
- Store original HTML in ref to prevent re-highlighting already highlighted content
- Separate highlight application from click handler attachment effects
- Remove onHighlightClick from highlight application dependencies
- Remove verbose console logging for cleaner code
- Highlights now apply correctly without stacking on top of each other
- Add readingFont setting to UserSettings interface
- Create fontLoader utility to load fonts from Bunny Fonts
- Add font selector dropdown in settings with popular reading fonts
- Use CSS variable --reading-font to apply font to reader content
- Support fonts: Inter, Lora, Merriweather, Open Sans, Roboto, Source Serif 4, Crimson Text, Libre Baskerville, PT Serif
- Fonts loaded from https://fonts.bunny.net/ (GDPR-friendly)
- Remove unused applyHighlightsToText import from ContentPanel
- Replace while(true) with proper condition in findHighlightMatches
- Remove unused match parameter from replaceTextWithMark function
All ESLint and TypeScript checks now pass with no errors.
- Use proper URL parsing to normalize URLs (remove www, query params, fragments)
- Add detailed logging for URL comparison to debug matching issues
- Implement two-pass text matching: exact match first, then normalized whitespace
- Handle whitespace variations in highlighted text more flexibly
- Add context to debug logs showing surrounding text
This should make highlights appear more reliably even with URL variations
and whitespace differences between the highlight and the actual content.
- Replace simple string replacement with proper DOM tree walking
- Find text nodes and split them to insert mark elements
- Add extensive debugging to track highlight matching
- Handle text that spans across HTML elements correctly
This should fix the issue where highlights weren't showing up in
article content due to HTML tags breaking up the text.
- Create highlightMatching utility to find and apply highlights to text/HTML
- Update ContentPanel to accept highlights and match them to current URL
- Add visual highlighting with yellow background and blue underline
- Show highlight count indicator when content has highlights
- Add hover effects and tooltips showing highlight date
- Support both HTML and markdown content highlighting
Highlighted text now appears underlined in the main content panel when
viewing URLs that have associated NIP-84 highlights.
- Add Open Graph image extraction from article HTML
- Use allorigins.win as free CORS proxy (no auth required)
- Implement HTML parsing to extract og:image meta tags
- Add in-memory caching to avoid repeated fetches
- Async loading with React useEffect for non-YouTube URLs
- 5 second timeout for fetch requests
- Graceful fallback to icon placeholder on errors
- Extract YouTube video thumbnails from URLs
- Display thumbnail images as background in large preview cards
- Add gradient overlay for better text contrast
- Fallback to icon placeholder for non-YouTube URLs
- Handle multiple YouTube URL formats (watch, youtu.be, shorts)
- Gracefully handle missing images with icon fallback