mirror of
https://github.com/dergigi/boris.git
synced 2026-02-16 20:45:01 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9c46e602a | ||
|
|
4d980bf91c | ||
|
|
cb3b0e38e9 | ||
|
|
fbf5c455ca | ||
|
|
ed5decf3e9 | ||
|
|
44a7e6ae2c |
26
CHANGELOG.md
26
CHANGELOG.md
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.10.20] - 2025-10-23
|
||||
|
||||
### Added
|
||||
|
||||
- Web Bookmarks section now appears first when bookmarks are grouped by source
|
||||
- Provides quicker access to external URL bookmarks
|
||||
- Better organization for mixed bookmark collections
|
||||
|
||||
### Fixed
|
||||
|
||||
- Mobile scroll position preservation when toggling highlights panel
|
||||
- Opening/closing the highlights sidebar no longer resets scroll to top
|
||||
- Scroll position is saved before locking and restored after unlocking
|
||||
- Uses `requestAnimationFrame` to ensure DOM updates before restoring
|
||||
- Infinite loop in reading position tracking
|
||||
- Fixed "Maximum update depth exceeded" error in `useReadingPosition` hook
|
||||
- Callbacks now stored in refs to avoid dependency array issues
|
||||
- Prevents unnecessary re-renders during scroll tracking
|
||||
- Skeleton loading state for articles with zero highlights
|
||||
- Articles without highlights no longer show infinite loading skeletons
|
||||
- Properly transitions to empty state message
|
||||
- Navigation to bookmarked articles
|
||||
- Clicking bookmarked kind:30023 articles now navigates to `/a/:naddr` route
|
||||
- Fixes issue where clicking showed "Select a bookmark" message instead
|
||||
- Applies to both compact view and bookmark item interactions
|
||||
|
||||
## [0.10.19] - 2025-10-23
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "boris",
|
||||
"version": "0.10.20",
|
||||
"version": "0.10.21",
|
||||
"description": "A minimal nostr client for bookmark management",
|
||||
"homepage": "https://read.withboris.com/",
|
||||
"type": "module",
|
||||
|
||||
@@ -42,10 +42,11 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
const firstUrl = hasUrls ? extractedUrls[0] : null
|
||||
const firstUrlClassification = firstUrl ? classifyUrl(firstUrl) : null
|
||||
|
||||
// For kind:30023 articles, extract image and summary tags (per NIP-23)
|
||||
// For kind:30023 articles, extract title, image and summary tags (per NIP-23)
|
||||
// Note: We extract directly from tags here since we don't have the full event.
|
||||
// When we have full events, we use getArticleImage() helper (see articleService.ts)
|
||||
const isArticle = bookmark.kind === 30023
|
||||
const articleTitle = isArticle ? bookmark.tags.find(t => t[0] === 'title')?.[1] : undefined
|
||||
const articleImage = isArticle ? bookmark.tags.find(t => t[0] === 'image')?.[1] : undefined
|
||||
const articleSummary = isArticle ? bookmark.tags.find(t => t[0] === 'summary')?.[1] : undefined
|
||||
|
||||
@@ -156,10 +157,7 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
hasUrls,
|
||||
extractedUrls,
|
||||
onSelectUrl,
|
||||
authorNpub,
|
||||
getAuthorDisplayName,
|
||||
handleReadNow,
|
||||
articleSummary,
|
||||
articleTitle,
|
||||
contentTypeIcon: getContentTypeIcon(),
|
||||
readingProgress
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ interface CompactViewProps {
|
||||
hasUrls: boolean
|
||||
extractedUrls: string[]
|
||||
onSelectUrl?: (url: string, bookmark?: { id: string; kind: number; tags: string[][]; pubkey: string }) => void
|
||||
articleSummary?: string
|
||||
articleTitle?: string
|
||||
contentTypeIcon: IconDefinition
|
||||
readingProgress?: number
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export const CompactView: React.FC<CompactViewProps> = ({
|
||||
hasUrls,
|
||||
extractedUrls,
|
||||
onSelectUrl,
|
||||
articleSummary,
|
||||
articleTitle,
|
||||
contentTypeIcon,
|
||||
readingProgress
|
||||
}) => {
|
||||
@@ -34,7 +34,7 @@ export const CompactView: React.FC<CompactViewProps> = ({
|
||||
const isNote = bookmark.kind === 1
|
||||
const isClickable = hasUrls || isArticle || isWebBookmark || isNote
|
||||
|
||||
const displayText = isArticle && articleSummary ? articleSummary : bookmark.content
|
||||
const displayText = isArticle && articleTitle ? articleTitle : bookmark.content
|
||||
|
||||
// Calculate progress color
|
||||
let progressColor = '#6366f1' // Default blue (reading)
|
||||
|
||||
@@ -155,6 +155,8 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
|
||||
const isTextContent = useMemo(() => {
|
||||
if (loading) return false
|
||||
if (!markdown && !html) return false
|
||||
// Don't track internal sentinel URLs (nostr-event: is not a real Nostr URI per NIP-21)
|
||||
if (selectedUrl?.startsWith('nostr-event:')) return false
|
||||
if (selectedUrl?.includes('youtube') || selectedUrl?.includes('vimeo')) return false
|
||||
if (!shouldTrackReadingProgress(html, markdown)) return false
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import { faBooks } from '../icons/customIcons'
|
||||
import { usePullToRefresh } from 'use-pull-to-refresh'
|
||||
import RefreshIndicator from './RefreshIndicator'
|
||||
import { groupIndividualBookmarks, hasContent, hasCreationDate, sortIndividualBookmarks } from '../utils/bookmarkUtils'
|
||||
import { dedupeBookmarksById } from '../services/bookmarkHelpers'
|
||||
import BookmarkFilters, { BookmarkFilterType } from './BookmarkFilters'
|
||||
import { filterBookmarksByType } from '../utils/bookmarkTypeClassifier'
|
||||
import ReadingProgressFilters, { ReadingProgressFilterType } from './ReadingProgressFilters'
|
||||
@@ -394,8 +395,7 @@ const Me: React.FC<MeProps> = ({
|
||||
}
|
||||
|
||||
const getReadItemUrl = (item: ReadItem) => {
|
||||
if (item.type === 'article') {
|
||||
// ID is already in naddr format
|
||||
if (item.type === 'article' && item.id.startsWith('naddr1')) {
|
||||
return `/a/${item.id}`
|
||||
} else if (item.url) {
|
||||
return `/r/${encodeURIComponent(item.url)}`
|
||||
@@ -438,19 +438,16 @@ const Me: React.FC<MeProps> = ({
|
||||
|
||||
const handleSelectUrl = (url: string, bookmark?: { id: string; kind: number; tags: string[][]; pubkey: string }) => {
|
||||
if (bookmark && bookmark.kind === 30023) {
|
||||
// For kind:30023 articles, navigate to the article route
|
||||
const dTag = bookmark.tags.find(t => t[0] === 'd')?.[1] || ''
|
||||
if (dTag && bookmark.pubkey) {
|
||||
const pointer = {
|
||||
identifier: dTag,
|
||||
const naddr = nip19.naddrEncode({
|
||||
kind: 30023,
|
||||
pubkey: bookmark.pubkey,
|
||||
}
|
||||
const naddr = nip19.naddrEncode(pointer)
|
||||
identifier: dTag
|
||||
})
|
||||
navigate(`/a/${naddr}`)
|
||||
}
|
||||
} else if (url) {
|
||||
// For regular URLs, navigate to the reader route
|
||||
navigate(`/r/${encodeURIComponent(url)}`)
|
||||
}
|
||||
}
|
||||
@@ -491,8 +488,10 @@ const Me: React.FC<MeProps> = ({
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Merge and flatten all individual bookmarks
|
||||
const allIndividualBookmarks = bookmarks.flatMap(b => b.individualBookmarks || [])
|
||||
// Merge and flatten all individual bookmarks with deduplication
|
||||
const allIndividualBookmarks = dedupeBookmarksById(
|
||||
bookmarks.flatMap(b => b.individualBookmarks || [])
|
||||
)
|
||||
.filter(hasContent)
|
||||
.filter(b => !settings?.hideBookmarksWithoutCreationDate || hasCreationDate(b))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user