- Add localStorage caching for kind:30023 articles (same as web articles)
- Cache TTL: 7 days
- Cache key prefix: article_cache_
- Add bypassCache parameter to fetchArticleByNaddr()
- Log cache hits and misses for debugging
- Gracefully handle storage errors
Articles are now cached locally after first fetch, making subsequent
loads instant and reducing relay queries.
- Add fetchHighlightsForArticle() to query highlights by article coordinate
- Use #a tag filter to find highlights that reference the article
- Query well-known relays for highlights even without authentication
- Extract article's d-tag and construct coordinate (kind:pubkey:identifier)
- Keep original fetchHighlights() for fetching user's own highlights
- Add detailed logging for debugging highlight fetching
This fixes the issue where no highlights were shown because we were
querying for highlights created BY the article author rather than
highlights created ABOUT the article.
- Add VITE_DEFAULT_ARTICLE_NADDR env variable support
- Create .env with default article naddr
- Create .env.example for documentation
- Add vite-env.d.ts for TypeScript type support
- Fallback to hardcoded value if env var not set
- Using Vite's built-in env variable support (no dotenv needed)
- Redirect root path to default article (naddr)
- Start with both sidebars (bookmarks and highlights) collapsed
- Auto-fetch and show highlights for the article author
- No authentication required to view articles
- Highlights panel auto-expands when article loads
- Login page moved to /login route
Add comment explaining that we extract the image tag directly from
bookmark.tags since we don't have the full NostrEvent here. When we
do have full events (like in articleService), we use getArticleImage()
helper from applesauce-core as intended.
- Add image prop to ContentPanel to display hero images
- Extract image tag from kind:30023 bookmark tags
- Display article images in Card, Large, and Compact views
- Show hero image at top of article reader view
- Add CSS styling for article-hero-image and reader-hero-image
- Article images clickable to open article in reader
- Per NIP-23: image tag contains header/preview image URL
- Pass pubkey along with bookmark data to handleSelectUrl
- Use bookmark.pubkey directly when constructing naddr
- More reliable article loading with correct author attribution
- Update type signatures across all components
- Update handleSelectUrl to detect kind:30023 bookmarks
- Construct naddr from article event data (pubkey, d tag)
- Fetch and render articles using article service
- Update all bookmark views (Compact, Card, Large) to handle articles
- Show 'Read Article' button for kind:30023 bookmarks
- Articles load in the existing ContentPanel with full reader features
- Update hydrateItems to detect long-form articles (kind:30023)
- Extract and display article title using getArticleTitle helper
- Article titles now appear as bookmark content in lists
- Provides better context for bookmarked articles
- Create articleService to fetch articles by naddr
- Update Bookmarks component to detect naddr in URL params
- Articles now render in the existing ContentPanel with highlight support
- Remove standalone Article component
- Articles work seamlessly within the existing three-pane layout
- Support for article metadata (title, image, published date, summary)
- Install react-router-dom for routing support
- Create Article component to decode naddr and fetch/render articles
- Add /a/:naddr route to App.tsx for article viewing
- Use applesauce relay pool patterns for event fetching
- Render articles with markdown using ReactMarkdown
- Support article metadata (title, image, published date, summary)
- Add highlightColor setting with 6 preset colors (yellow, orange, pink, green, blue, purple)
- Implement color picker UI with square color swatches
- Use CSS variables to dynamically apply highlight colors
- Add hex to RGB conversion for color transparency support
- Update both marker and underline styles to use selected color
- 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
- Create useSettings hook to handle settings loading, saving, and watching
- Move settings-related logic out of Bookmarks component
- Move font loading logic into the hook
- Reduce Bookmarks.tsx from 221 to 167 lines (under 210 limit)
- Keep code DRY by centralizing settings management
- All lint and type checks pass
- Remove unused FontAwesomeIcon import from Settings component
- Remove invalid eslint-disable comment for non-configured rule
- Add onSave back to useEffect dependencies to satisfy linter
- All lint checks and type checks now pass
- Wrap handleSaveSettings in useCallback to prevent recreation
- Only trigger save effect when localSettings object changes
- Remove onSave from dependency array with eslint-disable comment
- Settings now only save when user actually changes a setting
- Create Toast component for user feedback
- Add toast notification styles with slide-in animation
- Remove Save Settings button from Settings component
- Implement auto-save with 500ms debounce on setting changes
- Show success/error toast messages when settings are saved
- Settings now save automatically as user makes changes
- Improves UX by eliminating manual save step
- Increase bottom padding in .settings-content from 1rem to 2rem
- Ensures Save Settings button is fully visible and not cut off
- Improves scrollable area spacing
- Merge settings load and subscription setup into single useEffect
- Ensure settings are loaded immediately upon successful login
- Set up watchSettings subscription at the same time as initial load
- Add eventStore as dependency to ensure proper initialization
- Improves timing and prevents race conditions
- Import and use watchSettings from settingsService
- Subscribe to settings changes in eventStore
- Automatically update app state when settings change from Nostr
- Properly cleanup subscription on component unmount
- Fixes settings resetting on browser refresh
- Remove faulty conditional that prevented HTML ref from updating
- Now properly stores fresh content when switching articles
- Fixes issue where articles weren't switching properly
- Fixes React Hooks order violation
- All hooks must be called unconditionally in the same order
- Moved readingStats useMemo before the conditional returns
- Resolves 'Rendered more hooks than during the previous render' error
- Remove custom readingTime.ts implementation
- Install reading-time-estimator package (browser-compatible)
- Update ContentPanel to use named import from reading-time-estimator
- Fixes browser compatibility issues with reading-time package
- All linting and type checks pass
- Add padding-bottom to settings-content for breathing room
- Add bottom padding to settings-footer
- Add flex-shrink: 0 to footer to prevent it from being compressed
- Ensures Save Settings button is always fully visible
- Install reading-time package
- Calculate reading time from article content (html or markdown)
- Display reading time with clock icon in article header
- Strip HTML tags for accurate word count
- Style reading-time indicator similar to highlights
- Shows estimated reading time (e.g., '5 min read')
- Set max-width of 900px for the main content pane
- Center content with margin: 0 auto
- Add horizontal padding for breathing room
- Improves reading experience by preventing overly wide lines
- Fix checkbox alignment with flex display override
- Reduce checkbox size from 20px to 18px
- Add accent-color to match theme
- Improve text color and spacing
- All checkboxes now properly aligned
- Replace dropdown with visual 'A' buttons at different sizes
- Buttons show the actual size they represent
- Active state highlights selected size
- Consistent with view mode button pattern
- More intuitive and visual UX
- Change h3 font-size from 1.5rem to 1.5em to scale with parent
- Remove hardcoded font-size from preview paragraphs
- Now font size changes are properly reflected in the preview
- Remove loading state variable from Bookmarks component
- Remove 'Loading bookmarks...' screen
- Start with empty list and populate bookmarks in background
- Remove timeout and loading callbacks from fetchBookmarks
- Better UX: show UI immediately, bookmarks appear when ready
- Bookmarks.tsx now at 197 lines
- Add fontSize to UserSettings interface
- Add font size dropdown in Settings with options from 12px to 22px
- Apply font size to preview content instantly
- Set --reading-font-size CSS variable in Bookmarks when settings change
- Apply font-size variable to .reader-html and .reader-markdown
- Condense code in Bookmarks.tsx to stay under 210 lines (now at 207)
- 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 handleHighlightClick that opens panel if collapsed
- Sets selected highlight ID to scroll to it in the panel
- Add console logging for debugging
- When user clicks highlight in article with panel closed, panel opens automatically
- Create handleHighlightClick handler that sets highlight ID and opens panel
- Automatically expand highlights sidebar if collapsed when highlight clicked
- Improves UX by ensuring highlights panel is visible when interacting with highlights
- Applied to both ContentPanel and HighlightsPanel click handlers
- Preview highlight dynamically shows/hides based on showUnderlines setting
- Users can see highlight appearance changes instantly
- Conditional className applied to preview highlight
- Add highlighted text in preview using content-highlight class
- Shows how highlights appear with different fonts
- Helps users see complete reading experience before saving