diff --git a/src/components/ArchiveFilters.tsx b/src/components/ArchiveFilters.tsx new file mode 100644 index 00000000..8303072a --- /dev/null +++ b/src/components/ArchiveFilters.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faBookOpen, faBookmark, faCheckCircle } from '@fortawesome/free-solid-svg-icons' +import { faBooks } from '../icons/customIcons' + +export type ArchiveFilterType = 'all' | 'to-read' | 'reading' | 'completed' | 'marked' + +interface ArchiveFiltersProps { + selectedFilter: ArchiveFilterType + onFilterChange: (filter: ArchiveFilterType) => void +} + +const ArchiveFilters: React.FC = ({ selectedFilter, onFilterChange }) => { + const filters: { id: ArchiveFilterType; label: string; icon: typeof faBookOpen }[] = [ + { id: 'all', label: 'All', icon: faBooks }, + { id: 'to-read', label: 'To Read', icon: faBookmark }, + { id: 'reading', label: 'Reading', icon: faBookOpen }, + { id: 'completed', label: 'Completed', icon: faCheckCircle }, + { id: 'marked', label: 'Marked', icon: faCheckCircle } + ] + + return ( +
+ {filters.map((filter) => ( + + ))} +
+ ) +} + +export default ArchiveFilters + diff --git a/src/components/Me.tsx b/src/components/Me.tsx index 0c08409b..d3502cea 100644 --- a/src/components/Me.tsx +++ b/src/components/Me.tsx @@ -27,6 +27,7 @@ import { groupIndividualBookmarks, hasContent } from '../utils/bookmarkUtils' import BookmarkFilters, { BookmarkFilterType } from './BookmarkFilters' import { filterBookmarksByType } from '../utils/bookmarkTypeClassifier' import { generateArticleIdentifier, loadReadingPosition } from '../services/readingPositionService' +import ArchiveFilters, { ArchiveFilterType } from './ArchiveFilters' interface MeProps { relayPool: RelayPool @@ -53,6 +54,7 @@ const Me: React.FC = ({ relayPool, activeTab: propActiveTab, pubkey: pr const [viewMode, setViewMode] = useState('cards') const [refreshTrigger, setRefreshTrigger] = useState(0) const [bookmarkFilter, setBookmarkFilter] = useState('all') + const [archiveFilter, setArchiveFilter] = useState('all') const [readingPositions, setReadingPositions] = useState>(new Map()) // Update local state when prop changes @@ -238,10 +240,34 @@ const Me: React.FC = ({ relayPool, activeTab: propActiveTab, pubkey: pr const allIndividualBookmarks = bookmarks.flatMap(b => b.individualBookmarks || []) .filter(hasContent) - // Apply filter + // Apply bookmark filter const filteredBookmarks = filterBookmarksByType(allIndividualBookmarks, bookmarkFilter) const groups = groupIndividualBookmarks(filteredBookmarks) + + // Apply archive filter + const filteredReadArticles = readArticles.filter(post => { + const position = readingPositions.get(post.event.id) + + switch (archiveFilter) { + case 'to-read': + // No position or 0% progress + return !position || position === 0 + case 'reading': + // Has some progress but not completed (0 < position < 1) + return position !== undefined && position > 0 && position < 0.95 + case 'completed': + // 95% or more read (we consider 95%+ as completed) + return position !== undefined && position >= 0.95 + case 'marked': + // Manually marked as read (in archive but no reading position data) + // These are articles that were marked via the emoji reaction + return !position || position === 0 + case 'all': + default: + return true + } + }) 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 }, @@ -375,16 +401,30 @@ const Me: React.FC = ({ relayPool, activeTab: propActiveTab, pubkey: pr ) : ( -
- {readArticles.map((post) => ( - + {readArticles.length > 0 && ( + - ))} -
+ )} + {filteredReadArticles.length === 0 ? ( +
+ No articles match this filter. +
+ ) : ( +
+ {filteredReadArticles.map((post) => ( + + ))} +
+ )} + ) case 'writings':