feat(reads): separate archive vs reading-progress filters; archive shows emoji-only, progress filters ignore emoji

This commit is contained in:
Gigi
2025-10-20 13:00:34 +02:00
parent 31b005a989
commit 8d08911bd3
2 changed files with 74 additions and 20 deletions

View File

@@ -626,6 +626,39 @@ const Me: React.FC<MeProps> = ({
highlights
)
// Archive-only list: independent of reading progress
const archiveOnlyReads: ReadItem[] = (() => {
if (readingProgressFilter !== 'archive') return []
const markedIds = new Set<string>([
...archiveController.getMarkedIds(),
// We intentionally ignore readingProgress marks here per requirement
])
const items: ReadItem[] = []
// Add items from existing reads/links that are marked
for (const item of [...readsWithProgress, ...linksWithProgress]) {
const id = item.type === 'article' ? item.id : (item.url || item.id)
if (id && markedIds.has(id)) {
items.push({ ...item, markedAsRead: true })
}
}
// Add any marked IDs not present in reads/links yet
for (const id of markedIds) {
const exists = items.find(i => (i.type === 'article' ? i.id : (i.url || i.id)) === id)
if (!exists) {
const isArticle = id.startsWith('naddr1')
items.push({
id,
source: 'marked-as-read',
type: isArticle ? 'article' : 'external',
url: isArticle ? undefined : id,
markedAsRead: true,
readingTimestamp: Math.floor(Date.now() / 1000)
})
}
}
return items
})()
// Debug logs for archive filter issues
if (readingProgressFilter === 'archive') {
const ids = Array.from(new Set([
@@ -785,21 +818,42 @@ const Me: React.FC<MeProps> = ({
selectedFilter={readingProgressFilter}
onFilterChange={handleReadingProgressFilterChange}
/>
{filteredReads.length === 0 ? (
<div className="explore-loading" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '4rem', color: 'var(--text-secondary)' }}>
No articles match this filter.
</div>
{readingProgressFilter === 'archive' ? (
archiveOnlyReads.length === 0 ? (
<div className="explore-loading" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '4rem', color: 'var(--text-secondary)' }}>
No articles in archive.
</div>
) : (
<div className="explore-grid">
{archiveOnlyReads
.filter(item => item.type === 'article')
.map((item) => (
<BlogPostCard
key={item.id}
post={convertReadItemToBlogPostPreview(item)}
href={getReadItemUrl(item)}
readingProgress={item.readingProgress}
/>
))}
</div>
)
) : (
<div className="explore-grid">
{filteredReads.map((item) => (
<BlogPostCard
key={item.id}
post={convertReadItemToBlogPostPreview(item)}
href={getReadItemUrl(item)}
readingProgress={item.readingProgress}
/>
))}
</div>
filteredReads.length === 0 ? (
<div className="explore-loading" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '4rem', color: 'var(--text-secondary)' }}>
No articles match this filter.
</div>
) : (
<div className="explore-grid">
{filteredReads.map((item) => (
<BlogPostCard
key={item.id}
post={convertReadItemToBlogPostPreview(item)}
href={getReadItemUrl(item)}
readingProgress={item.readingProgress}
/>
))}
</div>
)
)}
</>
)

View File

@@ -50,23 +50,23 @@ export function filterByReadingProgress(
return items.filter((item) => {
const progress = item.readingProgress || 0
const isMarked = item.markedAsRead || false
// Reading progress filters MUST ignore emoji/archive reactions
const hasHighlights = (articleHighlightCount.get(item.id) || 0) > 0 ||
(item.url && (articleHighlightCount.get(item.url) || 0) > 0)
switch (filter) {
case 'unopened':
return progress === 0 && !isMarked
return progress === 0
case 'started':
return progress > 0 && progress <= 0.10 && !isMarked
return progress > 0 && progress <= 0.10
case 'reading':
return progress > 0.10 && progress <= 0.94 && !isMarked
return progress > 0.10 && progress <= 0.94
case 'completed':
// Completed is 95%+ progress only (no emoji fallback)
return progress >= 0.95
case 'archive':
// Archive-marked items (previously emoji-marked) regardless of progress
return isMarked
// Archive filter handled upstream; keep fallback as false to avoid mixing
return false
case 'highlighted':
return hasHighlights
case 'all':