- Add three-dot menu button at end of articles (before Mark as Read)
- Right-aligned menu with two options:
- Open on Nostr (using nostr gateway/portal)
- Open with Native App (using nostr: URI scheme)
- Add 'Open with Native App' option to highlight card menus
- Menu only appears for nostr-native articles (kind:30023)
- Styled consistently with highlight card menus
- Click outside to close menu functionality
- Install prismjs and rehype-prism-plus packages
- Integrate rehype-prism plugin into ReactMarkdown
- Use prism-tomorrow dark theme for syntax highlighting
- Enhanced code block styling with better padding and borders
- Inline code now has distinct styling from code blocks
- Monospace font for all code (Monaco, Menlo, Consolas)
- Improved readability with proper line-height and spacing
- Remove inline styles from custom image component
- Let CSS inheritance handle font and styling properly
- Images now respect user's reading font and size settings
- Install rehype-raw plugin for HTML support in ReactMarkdown
- Configure ReactMarkdown to parse and render HTML img tags
- Add responsive image styling with max-width and auto height
- Images now render inline in nostr-native blog posts with proper styling
- Add functions to check if article/URL was already marked as read via NIP-25 reactions
- Make mark-as-read action instant with fire-and-forget publishing
- Add checkmark icon animation when marking as read
- Display read status on load by querying kind:7 (nostr events) and kind:17 (websites) reactions
- Add green styling for already-read state
- Button shows checkmark and is disabled when article is already marked as read
- Update ReaderHeader to receive highlights and highlightVisibility props
- Calculate dominant color based on visible highlight groups
- Apply color priority: nostrverse > friends > mine
- Highlight count indicator now reflects the active group colors
- Create AuthorCard component showing profile picture and bio
- Display author card after mark as read button
- Only shown for nostr-native articles (not external URLs)
- Fetch author profile data using applesauce ProfileModel
- Card displays author name, avatar, and bio (truncated to 3 lines)
- Responsive design with smaller avatar on mobile
- Elegant card styling matching app design system
Author information helps readers learn more about article authors
directly within the reading experience.
- Create reactionService for handling kind:7 and kind:17 reactions
- Add mark as read button at the end of articles (📚 emoji)
- Use kind:7 reaction for nostr-native articles (/a/ paths)
- Use kind:17 reaction for external websites (/r/ paths)
- Pass activeAccount and currentArticle props through component tree
- Add responsive styling for mark as read button
- Button shows loading state while creating reaction
- Only visible when user is logged in
Implements NIP-25 (kind:7 reactions) and NIP-25 (kind:17 website reactions).
Users can now mark articles as read, creating a permanent record on nostr.
- 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
- 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 imageCacheService with localStorage-based image caching and LRU eviction
- Create useImageCache hook for React components to fetch and cache images
- Integrate image caching with article service to cache cover images on load
- Add image cache settings (enable/disable, size limit) to user settings
- Update ReaderHeader to use cached images for article covers
- Update BookmarkViews (CardView, LargeView) to use cached images
- Add image cache configuration UI in OfflineModeSettings with:
- Toggle to enable/disable image caching
- Slider to set cache size limit (10-200 MB)
- Display current cache stats (size and image count)
- Clear cache button
Images are cached in localStorage for offline viewing, with a configurable
size limit (default 50MB). LRU eviction ensures cache stays within limits.
- Add published field to ReadableContent interface
- Pass published date from article loader through component chain
- Display formatted publication date in ReaderHeader with calendar icon
- Format date as 'MMMM d, yyyy' using date-fns
- Add summary field to ReadableContent interface
- Pass summary through ContentPanel to ReaderHeader
- Display summary below title in both overlay and standard layouts
- Style summary with reading font for consistency
- Summary appears in white with shadow in image overlays
- Summary appears in gray (#aaa) in standard headers
- Enhances article preview and reading experience
- Update useMarkdownToHTML to return {renderedHtml, previewRef}
- Use returned previewRef in ContentPanel hidden markdown preview
- Resolves article markdown not rendering instantly
- 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.
Move HighlightButton outside .pane.main container by rendering it in Bookmarks component. This bypasses the CSS contain property that was preventing position:fixed from working properly. FAB now floats correctly in bottom-right corner.
- Replace floating popup button with persistent FAB in bottom-right corner
- Button always visible but disabled when no text is selected
- Uses user's highlight color from settings
- Visual feedback: scales up and becomes opaque when text is selected
- Follows Google apps design pattern for floating action buttons
- Create HighlightButton component that appears on text selection
- Add highlightCreationService using EventFactory and HighlightBlueprint
- Integrate highlight button into ContentPanel with text selection detection
- Update Bookmarks to pass required props and refresh highlights after creation
- Publish highlights to NIP-84 relays automatically
- Only show button when user is logged in
- Add logic to wait for HTML conversion when highlights need to be applied
- Prevent rendering plain markdown when highlights are pending
- Show ReactMarkdown fallback only when no highlights need to be applied
- Fixes default article highlights not showing
- Remove 'Highlights' text and count number to save space in panel
- Fix markdown rendering fallback to always show content when finalHtml is not ready
- Simplify render logic by removing highlight count condition that prevented content display
- Only show raw ReactMarkdown when there are no highlights
- Wait for finalHtml (with highlights) when highlights are present
- Prevents highlights from being bypassed during markdown conversion
- Render markdown directly with ReactMarkdown when finalHtml is not ready yet
- Prevents empty content display while markdown is being converted to HTML
- Fixes issue where default article text doesn't show
- Check for markdown/html existence before checking finalHtml
- Show empty container while markdown is being converted to HTML
- Fixes issue where nostr blog posts briefly showed error message
- Convert markdown to HTML before applying highlights
- Use hidden ReactMarkdown preview to render markdown
- Apply highlights to rendered HTML for both HTML and markdown content
- Fix scroll-to-highlight functionality for nostr blog posts (kind:30023)
- Ensure highlight marks are properly injected into markdown-rendered content
- 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
- 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
- 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
- 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')
- 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 500ms delay before starting pulse animation
- Prevents pulse from starting while element is still scrolling
- Creates better visual flow: scroll → pause → pulse
- Makes the highlight easier to track with your eyes
The pulse now starts after the smooth scroll completes,
making it much clearer which highlight you jumped to.
- Replace brightness change with subtle pulse animation
- Pulse twice over 1.5 seconds with scale and glow effects
- Scale slightly (1.02x) and increase shadow glow
- More elegant visual feedback than color change
- Easier to spot without being jarring
The highlight now pulses twice when clicked from the
sidebar, making it easy to see where you've jumped to.
- Add selectedHighlightId prop to ContentPanel
- Add useEffect to watch for selectedHighlightId changes
- Find and scroll to the corresponding mark element
- Temporarily brighten the highlight for visual feedback
- Pass selectedHighlightId from Bookmarks to ContentPanel
Now clicking a highlight in the sidebar properly scrolls
to and highlights the text in the article view.
- Clicking a highlight in the main text scrolls to it in the sidebar
- Selected highlight is visually highlighted with border and shadow
- Add selectedHighlightId state management in Bookmarks component
- Add click handlers to mark elements in ContentPanel
- Add isSelected prop to HighlightItem with scroll-into-view
- Add CSS styles for selected highlight state
- Set cursor to pointer on clickable highlights
Users can now click on highlighted text to jump to the corresponding
highlight in the right sidebar for easy navigation.
- 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.