mirror of
https://github.com/dergigi/boris.git
synced 2026-02-19 14:04:38 +01:00
feat: add support for bookmark sets (kind 30003)
- Add setName, setTitle, setDescription, and setImage fields to IndividualBookmark type - Extract d tag and metadata from kind 30003 events in bookmark processing - Create helper functions to group bookmarks by set and extract set metadata - Display bookmark sets as separate sections in BookmarkList UI - Maintain existing content-type categorization alongside bookmark sets
This commit is contained in:
@@ -12,7 +12,7 @@ import { ViewMode } from './Bookmarks'
|
||||
import { usePullToRefresh } from 'use-pull-to-refresh'
|
||||
import RefreshIndicator from './RefreshIndicator'
|
||||
import { BookmarkSkeleton } from './Skeletons'
|
||||
import { groupIndividualBookmarks, hasContent } from '../utils/bookmarkUtils'
|
||||
import { groupIndividualBookmarks, hasContent, getBookmarkSets, getBookmarksWithoutSet } from '../utils/bookmarkUtils'
|
||||
import { UserSettings } from '../services/settingsService'
|
||||
|
||||
interface BookmarkListProps {
|
||||
@@ -71,7 +71,13 @@ export const BookmarkList: React.FC<BookmarkListProps> = ({
|
||||
// Merge and flatten all individual bookmarks from all lists
|
||||
const allIndividualBookmarks = bookmarks.flatMap(b => b.individualBookmarks || [])
|
||||
.filter(hasContent)
|
||||
const groups = groupIndividualBookmarks(allIndividualBookmarks)
|
||||
|
||||
// Separate bookmarks with setName (kind 30003) from regular bookmarks
|
||||
const bookmarksWithoutSet = getBookmarksWithoutSet(allIndividualBookmarks)
|
||||
const bookmarkSets = getBookmarkSets(allIndividualBookmarks)
|
||||
|
||||
// Group non-set bookmarks as before
|
||||
const groups = groupIndividualBookmarks(bookmarksWithoutSet)
|
||||
const sections: Array<{ key: string; title: string; items: IndividualBookmark[] }> = [
|
||||
{ key: 'private', title: 'Private bookmarks', items: groups.privateItems },
|
||||
{ key: 'public', title: 'Public bookmarks', items: groups.publicItems },
|
||||
@@ -79,6 +85,15 @@ export const BookmarkList: React.FC<BookmarkListProps> = ({
|
||||
{ key: 'amethyst', title: 'Amethyst-style bookmarks', items: groups.amethyst }
|
||||
]
|
||||
|
||||
// Add bookmark sets as additional sections
|
||||
bookmarkSets.forEach(set => {
|
||||
sections.push({
|
||||
key: `set-${set.name}`,
|
||||
title: set.title || set.name,
|
||||
items: set.bookmarks
|
||||
})
|
||||
})
|
||||
|
||||
if (isCollapsed) {
|
||||
// Check if the selected URL is in bookmarks
|
||||
const isBookmarked = selectedUrl && bookmarks.some(bookmark => {
|
||||
|
||||
@@ -33,6 +33,12 @@ export async function collectBookmarksFromEvents(
|
||||
if (!latestContent && evt.content && !Helpers.hasHiddenContent(evt)) latestContent = evt.content
|
||||
if (Array.isArray(evt.tags)) allTags = allTags.concat(evt.tags)
|
||||
|
||||
// Extract the 'd' tag and metadata for bookmark sets (kind 30003)
|
||||
const dTag = evt.kind === 30003 ? evt.tags?.find((t: string[]) => t[0] === 'd')?.[1] : undefined
|
||||
const setTitle = evt.kind === 30003 ? evt.tags?.find((t: string[]) => t[0] === 'title')?.[1] : undefined
|
||||
const setDescription = evt.kind === 30003 ? evt.tags?.find((t: string[]) => t[0] === 'description')?.[1] : undefined
|
||||
const setImage = evt.kind === 30003 ? evt.tags?.find((t: string[]) => t[0] === 'image')?.[1] : undefined
|
||||
|
||||
// Handle web bookmarks (kind:39701) as individual bookmarks
|
||||
if (evt.kind === 39701) {
|
||||
publicItemsAll.push({
|
||||
@@ -46,7 +52,11 @@ export async function collectBookmarksFromEvents(
|
||||
type: 'web' as const,
|
||||
isPrivate: false,
|
||||
added_at: evt.created_at || Math.floor(Date.now() / 1000),
|
||||
sourceKind: 39701
|
||||
sourceKind: 39701,
|
||||
setName: dTag,
|
||||
setTitle,
|
||||
setDescription,
|
||||
setImage
|
||||
})
|
||||
continue
|
||||
}
|
||||
@@ -55,7 +65,11 @@ export async function collectBookmarksFromEvents(
|
||||
publicItemsAll.push(
|
||||
...processApplesauceBookmarks(pub, activeAccount, false).map(i => ({
|
||||
...i,
|
||||
sourceKind: evt.kind
|
||||
sourceKind: evt.kind,
|
||||
setName: dTag,
|
||||
setTitle,
|
||||
setDescription,
|
||||
setImage
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -103,7 +117,11 @@ export async function collectBookmarksFromEvents(
|
||||
privateItemsAll.push(
|
||||
...processApplesauceBookmarks(manualPrivate, activeAccount, true).map(i => ({
|
||||
...i,
|
||||
sourceKind: evt.kind
|
||||
sourceKind: evt.kind,
|
||||
setName: dTag,
|
||||
setTitle,
|
||||
setDescription,
|
||||
setImage
|
||||
}))
|
||||
)
|
||||
Reflect.set(evt, BookmarkHiddenSymbol, manualPrivate)
|
||||
@@ -120,7 +138,11 @@ export async function collectBookmarksFromEvents(
|
||||
privateItemsAll.push(
|
||||
...processApplesauceBookmarks(priv, activeAccount, true).map(i => ({
|
||||
...i,
|
||||
sourceKind: evt.kind
|
||||
sourceKind: evt.kind,
|
||||
setName: dTag,
|
||||
setTitle,
|
||||
setDescription,
|
||||
setImage
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ export interface IndividualBookmark {
|
||||
added_at?: number
|
||||
// The kind of the source list/set that produced this bookmark (e.g., 10003, 30003, 30001, or 39701 for web)
|
||||
sourceKind?: number
|
||||
// The 'd' tag value from kind 30003 bookmark sets
|
||||
setName?: string
|
||||
// Metadata from the bookmark set event (kind 30003)
|
||||
setTitle?: string
|
||||
setDescription?: string
|
||||
setImage?: string
|
||||
}
|
||||
|
||||
export interface ActiveAccount {
|
||||
|
||||
@@ -104,3 +104,49 @@ export function groupIndividualBookmarks(items: IndividualBookmark[]) {
|
||||
export function hasContent(bookmark: IndividualBookmark): boolean {
|
||||
return !!(bookmark.content && bookmark.content.trim().length > 0)
|
||||
}
|
||||
|
||||
// Bookmark sets helpers (kind 30003)
|
||||
export interface BookmarkSet {
|
||||
name: string
|
||||
title?: string
|
||||
description?: string
|
||||
image?: string
|
||||
bookmarks: IndividualBookmark[]
|
||||
}
|
||||
|
||||
export function getBookmarkSets(items: IndividualBookmark[]): BookmarkSet[] {
|
||||
// Group bookmarks by setName
|
||||
const setMap = new Map<string, IndividualBookmark[]>()
|
||||
|
||||
items.forEach(bookmark => {
|
||||
if (bookmark.setName) {
|
||||
const existing = setMap.get(bookmark.setName) || []
|
||||
existing.push(bookmark)
|
||||
setMap.set(bookmark.setName, existing)
|
||||
}
|
||||
})
|
||||
|
||||
// Convert to array and extract metadata from the bookmarks
|
||||
const sets: BookmarkSet[] = []
|
||||
setMap.forEach((bookmarks, name) => {
|
||||
// Get metadata from the first bookmark (all bookmarks in a set share the same metadata)
|
||||
const firstBookmark = bookmarks[0]
|
||||
const title = firstBookmark?.setTitle
|
||||
const description = firstBookmark?.setDescription
|
||||
const image = firstBookmark?.setImage
|
||||
|
||||
sets.push({
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
image,
|
||||
bookmarks: sortIndividualBookmarks(bookmarks)
|
||||
})
|
||||
})
|
||||
|
||||
return sets.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
export function getBookmarksWithoutSet(items: IndividualBookmark[]): IndividualBookmark[] {
|
||||
return sortIndividualBookmarks(items.filter(b => !b.setName))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user