From e32010771b7f25b5bb157c8f81fb9cc2ba5e5bb9 Mon Sep 17 00:00:00 2001 From: Gigi Date: Mon, 13 Oct 2025 16:41:01 +0200 Subject: [PATCH] refactor: make /me Reading List use same components as bookmark sidebar - Reuse BookmarkItem component for rendering individual bookmarks - Apply same filtering logic (hasContentOrUrl) as BookmarkList - Add view mode controls (compact/cards/large) matching sidebar - Count shows individual bookmarks not bookmark lists - Keeps code DRY by reusing existing components and logic --- src/components/Me.tsx | 83 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/src/components/Me.tsx b/src/components/Me.tsx index a35d33aa..05f6f081 100644 --- a/src/components/Me.tsx +++ b/src/components/Me.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faSpinner, faExclamationCircle, faHighlighter, faBookmark } from '@fortawesome/free-solid-svg-icons' +import { faSpinner, faExclamationCircle, faHighlighter, faBookmark, faList, faThLarge, faImage } from '@fortawesome/free-solid-svg-icons' import { Hooks } from 'applesauce-react' import { RelayPool } from 'applesauce-relay' import { nip19 } from 'nostr-tools' @@ -10,9 +10,13 @@ import { fetchHighlights } from '../services/highlightService' import { fetchBookmarks } from '../services/bookmarkService' import { fetchReadArticlesWithData } from '../services/libraryService' import { BlogPostPreview } from '../services/exploreService' -import { Bookmark } from '../types/bookmarks' +import { Bookmark, IndividualBookmark } from '../types/bookmarks' import AuthorCard from './AuthorCard' import BlogPostCard from './BlogPostCard' +import { BookmarkItem } from './BookmarkItem' +import IconButton from './IconButton' +import { ViewMode } from './Bookmarks' +import { extractUrlsFromContent } from '../services/bookmarkHelpers' import { faBooks } from '../icons/customIcons' interface MeProps { @@ -29,6 +33,7 @@ const Me: React.FC = ({ relayPool }) => { const [readArticles, setReadArticles] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + const [viewMode, setViewMode] = useState('cards') useEffect(() => { const loadData = async () => { @@ -83,6 +88,28 @@ const Me: React.FC = ({ relayPool }) => { return `/a/${naddr}` } + // Helper to check if a bookmark has either content or a URL (same logic as BookmarkList) + const hasContentOrUrl = (ib: IndividualBookmark) => { + const hasContent = ib.content && ib.content.trim().length > 0 + + let hasUrl = false + if (ib.kind === 39701) { + const dTag = ib.tags?.find((t: string[]) => t[0] === 'd')?.[1] + hasUrl = !!dTag && dTag.trim().length > 0 + } else { + const urls = extractUrlsFromContent(ib.content || '') + hasUrl = urls.length > 0 + } + + if (ib.kind === 30023) return true + return hasContent || hasUrl + } + + // Merge and flatten all individual bookmarks (same logic as BookmarkList) + 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 (loading) { return (
@@ -125,20 +152,52 @@ const Me: React.FC = ({ relayPool }) => { ) case 'reading-list': - return bookmarks.length === 0 ? ( + return allIndividualBookmarks.length === 0 ? (

No bookmarks yet. Bookmark articles to see them here!

) : (
- {bookmarks.map((bookmark) => ( - - ))} +
+ {allIndividualBookmarks.map((individualBookmark, index) => ( + + ))} +
+
+ setViewMode('compact')} + title="Compact list view" + ariaLabel="Compact list view" + variant={viewMode === 'compact' ? 'primary' : 'ghost'} + /> + setViewMode('cards')} + title="Cards view" + ariaLabel="Cards view" + variant={viewMode === 'cards' ? 'primary' : 'ghost'} + /> + setViewMode('large')} + title="Large preview view" + ariaLabel="Large preview view" + variant={viewMode === 'large' ? 'primary' : 'ghost'} + /> +
) @@ -184,7 +243,7 @@ const Me: React.FC = ({ relayPool }) => { onClick={() => setActiveTab('reading-list')} > - Reading List ({bookmarks.length}) + Reading List ({allIndividualBookmarks.length})