import React from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faChevronLeft, faBookmark, faSpinner, faList, faThLarge, faImage } from '@fortawesome/free-solid-svg-icons' import { RelayPool } from 'applesauce-relay' import { Bookmark, IndividualBookmark } from '../types/bookmarks' import { BookmarkItem } from './BookmarkItem' import SidebarHeader from './SidebarHeader' import IconButton from './IconButton' import { ViewMode } from './Bookmarks' import { extractUrlsFromContent } from '../services/bookmarkHelpers' interface BookmarkListProps { bookmarks: Bookmark[] onSelectUrl?: (url: string, bookmark?: { id: string; kind: number; tags: string[][]; pubkey: string }) => void isCollapsed: boolean onToggleCollapse: () => void onLogout: () => void viewMode: ViewMode onViewModeChange: (mode: ViewMode) => void selectedUrl?: string onOpenSettings: () => void onRefresh?: () => void isRefreshing?: boolean loading?: boolean relayPool: RelayPool | null } export const BookmarkList: React.FC = ({ bookmarks, onSelectUrl, isCollapsed, onToggleCollapse, onLogout, viewMode, onViewModeChange, selectedUrl, onOpenSettings, onRefresh, isRefreshing, loading = false, relayPool }) => { // Helper to check if a bookmark has either content or a URL const hasContentOrUrl = (ib: IndividualBookmark) => { // Check if has content (text) const hasContent = ib.content && ib.content.trim().length > 0 // Check if has URL let hasUrl = false // For web bookmarks (kind:39701), URL is in the 'd' tag if (ib.kind === 39701) { const dTag = ib.tags?.find((t: string[]) => t[0] === 'd')?.[1] hasUrl = !!dTag && dTag.trim().length > 0 } else { // For other bookmarks, extract URLs from content const urls = extractUrlsFromContent(ib.content || '') hasUrl = urls.length > 0 } // Always show articles (kind:30023) as they have special handling if (ib.kind === 30023) return true // Otherwise, must have either content or URL return hasContent || hasUrl } // Merge and flatten all individual bookmarks from all lists // Re-sort after flattening to ensure newest first across all lists const allIndividualBookmarks = bookmarks.flatMap(b => b.individualBookmarks || []) .filter(hasContentOrUrl) .sort((a, b) => ((b.added_at || 0) - (a.added_at || 0)) || ((b.created_at || 0) - (a.created_at || 0))) if (isCollapsed) { // Check if the selected URL is in bookmarks const isBookmarked = selectedUrl && bookmarks.some(bookmark => { const bookmarkUrl = bookmark.url return bookmarkUrl === selectedUrl || selectedUrl.includes(bookmarkUrl) || bookmarkUrl.includes(selectedUrl) }) return (
) } return (
{loading ? (
) : allIndividualBookmarks.length === 0 ? (

No bookmarks found.

Add bookmarks using your nostr client to see them here.

) : (
{allIndividualBookmarks.map((individualBookmark, index) => )}
)}
onViewModeChange('compact')} title="Compact list view" ariaLabel="Compact list view" variant={viewMode === 'compact' ? 'primary' : 'ghost'} /> onViewModeChange('cards')} title="Cards view" ariaLabel="Cards view" variant={viewMode === 'cards' ? 'primary' : 'ghost'} /> onViewModeChange('large')} title="Large preview view" ariaLabel="Large preview view" variant={viewMode === 'large' ? 'primary' : 'ghost'} />
) }