mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 14:44:26 +01:00
fix: properly parse NIP-51 bookmark lists (kind 10003) according to specification
- Parse bookmark lists correctly according to NIP-51 specification - Handle 'e' tags for event references (the actual bookmarks) - Handle 'a' tags for article references - Handle 'r' tags for URL references - Display bookmark count and organize references by type - Show event IDs in a readable format with truncation - Add proper CSS styling for bookmark list display - Update Bookmark interface to include metadata fields This fixes the issue where kind:10003 bookmark lists weren't being displayed properly. Now follows the NIP-51 specification exactly as shown in the example event structure.
This commit is contained in:
@@ -11,6 +11,10 @@ interface Bookmark {
|
||||
content: string
|
||||
created_at: number
|
||||
tags: string[][]
|
||||
bookmarkCount?: number
|
||||
eventReferences?: string[]
|
||||
articleReferences?: string[]
|
||||
urlReferences?: string[]
|
||||
}
|
||||
|
||||
interface BookmarksProps {
|
||||
@@ -87,37 +91,31 @@ const Bookmarks: React.FC<BookmarksProps> = ({ addressLoader, onLogout }) => {
|
||||
|
||||
const parseBookmarkEvent = (event: NostrEvent): Bookmark | null => {
|
||||
try {
|
||||
// Parse the event content as JSON (bookmark list)
|
||||
const content = JSON.parse(event.content || '{}')
|
||||
// According to NIP-51, bookmark lists (kind 10003) contain:
|
||||
// - "e" tags for event references (the actual bookmarks)
|
||||
// - "a" tags for article references
|
||||
// - "r" tags for URL references
|
||||
|
||||
const eventTags = event.tags.filter((tag: string[]) => tag[0] === 'e')
|
||||
const articleTags = event.tags.filter((tag: string[]) => tag[0] === 'a')
|
||||
const urlTags = event.tags.filter((tag: string[]) => tag[0] === 'r')
|
||||
|
||||
// Get the title from content or use a default
|
||||
const title = event.content || `Bookmark List (${eventTags.length + articleTags.length + urlTags.length} items)`
|
||||
|
||||
if (content.bookmarks && Array.isArray(content.bookmarks)) {
|
||||
// Handle bookmark list format
|
||||
return {
|
||||
id: event.id,
|
||||
title: content.name || 'Untitled Bookmark List',
|
||||
url: '',
|
||||
title: title,
|
||||
url: '', // Bookmark lists don't have a single URL
|
||||
content: event.content,
|
||||
created_at: event.created_at,
|
||||
tags: event.tags
|
||||
tags: event.tags,
|
||||
// Add metadata about the bookmark list
|
||||
bookmarkCount: eventTags.length + articleTags.length + urlTags.length,
|
||||
eventReferences: eventTags.map(tag => tag[1]),
|
||||
articleReferences: articleTags.map(tag => tag[1]),
|
||||
urlReferences: urlTags.map(tag => tag[1])
|
||||
}
|
||||
}
|
||||
|
||||
// Handle individual bookmark entries
|
||||
const urlTag = event.tags.find((tag: string[]) => tag[0] === 'r' && tag[1])
|
||||
const titleTag = event.tags.find((tag: string[]) => tag[0] === 'title' && tag[1])
|
||||
|
||||
if (urlTag) {
|
||||
return {
|
||||
id: event.id,
|
||||
title: titleTag?.[1] || 'Untitled',
|
||||
url: urlTag[1],
|
||||
content: event.content,
|
||||
created_at: event.created_at,
|
||||
tags: event.tags
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('Error parsing bookmark event:', error)
|
||||
return null
|
||||
@@ -189,21 +187,41 @@ const Bookmarks: React.FC<BookmarksProps> = ({ addressLoader, onLogout }) => {
|
||||
{bookmarks.map((bookmark) => (
|
||||
<div key={bookmark.id} className="bookmark-item">
|
||||
<h3>{bookmark.title}</h3>
|
||||
{bookmark.url && (
|
||||
<a
|
||||
href={bookmark.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="bookmark-url"
|
||||
>
|
||||
{bookmark.url}
|
||||
{bookmark.bookmarkCount && (
|
||||
<p className="bookmark-count">
|
||||
{bookmark.bookmarkCount} bookmarks in this list
|
||||
</p>
|
||||
)}
|
||||
{bookmark.urlReferences && bookmark.urlReferences.length > 0 && (
|
||||
<div className="bookmark-urls">
|
||||
<h4>URLs:</h4>
|
||||
{bookmark.urlReferences.map((url, index) => (
|
||||
<a key={index} href={url} target="_blank" rel="noopener noreferrer" className="bookmark-url">
|
||||
{url}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{bookmark.eventReferences && bookmark.eventReferences.length > 0 && (
|
||||
<div className="bookmark-events">
|
||||
<h4>Event References ({bookmark.eventReferences.length}):</h4>
|
||||
<div className="event-ids">
|
||||
{bookmark.eventReferences.slice(0, 3).map((eventId, index) => (
|
||||
<span key={index} className="event-id">
|
||||
{eventId.slice(0, 8)}...{eventId.slice(-8)}
|
||||
</span>
|
||||
))}
|
||||
{bookmark.eventReferences.length > 3 && (
|
||||
<span className="more-events">... and {bookmark.eventReferences.length - 3} more</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{bookmark.content && (
|
||||
<p className="bookmark-content">{bookmark.content}</p>
|
||||
)}
|
||||
<div className="bookmark-meta">
|
||||
<span>Added: {formatDate(bookmark.created_at)}</span>
|
||||
<span>Created: {formatDate(bookmark.created_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -122,6 +122,65 @@ body {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.bookmark-count {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.bookmark-urls {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.bookmark-urls h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.bookmark-url {
|
||||
display: block;
|
||||
margin: 0.25rem 0;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.bookmark-url:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.bookmark-events {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.bookmark-events h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.event-ids {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.event-id {
|
||||
background: #f5f5f5;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.more-events {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.logout-button {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
|
||||
Reference in New Issue
Block a user