chore: commit pending working changes before implementing unarchive behavior

This commit is contained in:
Gigi
2025-10-20 12:36:27 +02:00
parent 49745e1b8a
commit f272943b64
8 changed files with 39 additions and 33 deletions

View File

@@ -574,7 +574,9 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
const naddr = nip19.naddrEncode({ kind: 30023, pubkey: currentArticle.pubkey, identifier: dTag })
hasRead = hasRead || archiveController.isMarked(naddr)
console.log('[archive][content] check article', { naddr: naddr.slice(0, 24) + '...', hasRead })
} catch {}
} catch (e) {
console.warn('[archive][content] encode naddr failed', e)
}
}
} else {
hasRead = await hasMarkedWebsiteAsRead(
@@ -617,7 +619,9 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
const naddr = nip19.naddrEncode({ kind: 30023, pubkey: currentArticle.pubkey, identifier: dTag })
archiveController.unmark(naddr)
}
} catch {}
} catch (e) {
console.warn('[archive][content] encode naddr failed', e)
}
} else if (selectedUrl) {
archiveController.unmark(selectedUrl)
}
@@ -665,7 +669,9 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
archiveController.mark(naddr)
console.log('[archive][content] optimistic mark article', naddr.slice(0, 24) + '...')
}
} catch {}
} catch (err) {
console.warn('[archive][content] optimistic article mark failed', err)
}
} else if (selectedUrl) {
await createWebsiteReaction(
selectedUrl,

View File

@@ -833,13 +833,13 @@ const Debug: React.FC<DebugProps> = ({
setLiveTiming(prev => ({ ...prev, loadMarkAsRead: { startTime: start } }))
const { queryEvents } = await import('../services/dataFetch')
const { MARK_AS_READ_EMOJI } = await import('../services/reactionService')
const { ARCHIVE_EMOJI } = await import('../services/reactionService')
// Load both kind:7 (reactions to events) and kind:17 (reactions to URLs)
const [kind7Events, kind17Events] = await Promise.all([
queryEvents(relayPool, { kinds: [7], authors: [activeAccount.pubkey] }, {
onEvent: (evt) => {
if (evt.content === MARK_AS_READ_EMOJI) {
if (evt.content === ARCHIVE_EMOJI) {
if (firstEventTime === null) {
firstEventTime = performance.now() - start
setTFirstMarkAsRead(Math.round(firstEventTime))
@@ -850,7 +850,7 @@ const Debug: React.FC<DebugProps> = ({
}),
queryEvents(relayPool, { kinds: [17], authors: [activeAccount.pubkey] }, {
onEvent: (evt) => {
if (evt.content === MARK_AS_READ_EMOJI) {
if (evt.content === ARCHIVE_EMOJI) {
if (firstEventTime === null) {
firstEventTime = performance.now() - start
setTFirstMarkAsRead(Math.round(firstEventTime))
@@ -1638,7 +1638,7 @@ const Debug: React.FC<DebugProps> = ({
{/* Mark-as-read Reactions Loading Section */}
<div className="settings-section">
<h3 className="section-title">Mark-as-read Reactions Loading</h3>
<div className="text-sm opacity-70 mb-3">Test loading mark-as-read reactions (kind: 7 and 17) with the MARK_AS_READ_EMOJI for the logged-in user</div>
<div className="text-sm opacity-70 mb-3">Test loading mark-as-read reactions (kind: 7 and 17) with the ARCHIVE_EMOJI for the logged-in user</div>
<div className="flex gap-2 mb-3 items-center">
<button
className="btn btn-primary"

View File

@@ -205,7 +205,7 @@ const Me: React.FC<MeProps> = ({
// Subscribe to archiveController for marked-only items and rebuild read lists
useEffect(() => {
const unsubMarked = archiveController.onMarked((_marked) => {
const unsubMarked = archiveController.onMarked(() => {
// Rebuild reads list including marked-as-read-only items
const progressMap = readingProgressController.getProgressMap()
const readItems: ReadItem[] = Array.from(progressMap.entries()).map(([id, progress]) => ({

View File

@@ -141,6 +141,7 @@ export function useExternalUrlLoader({
}
loadExternalUrl()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, relayPool, eventStore, setSelectedUrl, setReaderContent, setReaderLoading, setIsCollapsed, setHighlights, setHighlightsLoading, setCurrentArticleCoordinate, setCurrentArticleEventId])
// Keep UI highlights synced with cached store updates without reloading content

View File

@@ -4,7 +4,7 @@ import { NostrEvent } from 'nostr-tools'
import { queryEvents } from './dataFetch'
import { KINDS } from '../config/kinds'
import { RELAYS } from '../config/relays'
import { MARK_AS_READ_EMOJI } from './reactionService'
import { ARCHIVE_EMOJI } from './reactionService'
import { nip19 } from 'nostr-tools'
type MarkedChangeCallback = (markedIds: Set<string>) => void
@@ -60,10 +60,10 @@ class ArchiveController {
reset(): void {
this.generation++
if (this.timelineSubscription) {
try { this.timelineSubscription.unsubscribe() } catch {}
this.timelineSubscription = null
}
if (this.timelineSubscription) {
try { this.timelineSubscription.unsubscribe() } catch (e) { console.warn('[archive] timeline unsub error', e) }
this.timelineSubscription = null
}
this.markedIds = new Set()
this.pendingEventIds = new Set()
this.lastLoadedPubkey = null
@@ -90,7 +90,7 @@ class ArchiveController {
// Handlers for streaming queries
const handleUrlReaction = (evt: NostrEvent) => {
if (evt.content !== MARK_AS_READ_EMOJI) return
if (evt.content !== ARCHIVE_EMOJI) return
const rTag = evt.tags.find(t => t[0] === 'r')?.[1]
if (!rTag) return
this.markedIds.add(rTag)
@@ -99,7 +99,7 @@ class ArchiveController {
}
const handleEventReaction = (evt: NostrEvent) => {
if (evt.content !== MARK_AS_READ_EMOJI) return
if (evt.content !== ARCHIVE_EMOJI) return
// Direct coordinate tag ('a') - can be mapped immediately
const aTag = evt.tags.find(t => t[0] === 'a')?.[1]
if (aTag) {
@@ -172,13 +172,13 @@ class ArchiveController {
} else {
stillPending.add(eId)
}
} catch { stillPending.add(eId) }
} catch (e) { stillPending.add(eId) }
}
this.pendingEventIds = stillPending
if (stillPending.size > 0) {
// Subscribe to future 30023 arrivals to finalize mapping
if (this.timelineSubscription) {
try { this.timelineSubscription.unsubscribe() } catch {}
try { this.timelineSubscription.unsubscribe() } catch (e) { console.warn('[archive] timeline unsub error', e) }
this.timelineSubscription = null
}
const sub$ = eventStore.timeline({ kinds: [KINDS.BlogPost] })
@@ -195,7 +195,7 @@ class ArchiveController {
this.pendingEventIds.delete(evt.id)
console.log('[archive] map via timeline naddr:', naddr.slice(0, 24), '...')
this.emit()
} catch {}
} catch (e) { console.warn('[archive] map via timeline encode error', e) }
}
})
}

View File

@@ -3,7 +3,7 @@ import { NostrEvent } from 'nostr-tools'
import { Helpers } from 'applesauce-core'
import { RELAYS } from '../config/relays'
import { KINDS } from '../config/kinds'
import { MARK_AS_READ_EMOJI } from './reactionService'
import { ARCHIVE_EMOJI } from './reactionService'
import { BlogPostPreview } from './exploreService'
import { queryEvents } from './dataFetch'
@@ -38,7 +38,7 @@ export async function fetchReadArticles(
// Process kind:7 reactions (nostr-native articles)
for (const event of kind7Events) {
if (event.content === MARK_AS_READ_EMOJI) {
if (event.content === ARCHIVE_EMOJI) {
const eTag = event.tags.find((t) => t[0] === 'e')
const pTag = event.tags.find((t) => t[0] === 'p')
const kTag = event.tags.find((t) => t[0] === 'k')
@@ -58,7 +58,7 @@ export async function fetchReadArticles(
// Process kind:17 reactions (external URLs)
for (const event of kind17Events) {
if (event.content === MARK_AS_READ_EMOJI) {
if (event.content === ARCHIVE_EMOJI) {
const rTag = event.tags.find((t) => t[0] === 'r')
if (rTag && rTag[1]) {

View File

@@ -1,4 +1,3 @@
import { EventFactory } from 'applesauce-factory'
import { RelayPool, completeOnEose, onlyEvents } from 'applesauce-relay'
import { IAccount } from 'applesauce-accounts'
import { NostrEvent } from 'nostr-tools'
@@ -6,9 +5,9 @@ import { lastValueFrom, takeUntil, timer, toArray } from 'rxjs'
import { RELAYS } from '../config/relays'
import { EventFactory } from 'applesauce-factory'
const MARK_AS_READ_EMOJI = '📚'
const ARCHIVE_EMOJI = '📚'
export { MARK_AS_READ_EMOJI }
export { ARCHIVE_EMOJI }
/**
* Creates a kind:7 reaction to a nostr event (for nostr-native articles)
@@ -41,7 +40,7 @@ export async function createEventReaction(
const draft = await factory.create(async () => ({
kind: 7, // Reaction
content: MARK_AS_READ_EMOJI,
content: ARCHIVE_EMOJI,
tags,
created_at: Math.floor(Date.now() / 1000)
}))
@@ -91,7 +90,7 @@ export async function createWebsiteReaction(
const draft = await factory.create(async () => ({
kind: 17, // Reaction to a website
content: MARK_AS_READ_EMOJI,
content: ARCHIVE_EMOJI,
tags,
created_at: Math.floor(Date.now() / 1000)
}))
@@ -157,8 +156,8 @@ export async function hasMarkedEventAsRead(
const events: NostrEvent[] = await lastValueFrom(events$)
// Check if any reaction has our mark-as-read emoji
const hasReadReaction = events.some((event: NostrEvent) => event.content === MARK_AS_READ_EMOJI)
// Check if any reaction has our archive emoji
const hasReadReaction = events.some((event: NostrEvent) => event.content === ARCHIVE_EMOJI)
return hasReadReaction
} catch (error) {
@@ -210,8 +209,8 @@ export async function hasMarkedWebsiteAsRead(
const events: NostrEvent[] = await lastValueFrom(events$)
// Check if any reaction has our mark-as-read emoji
const hasReadReaction = events.some((event: NostrEvent) => event.content === MARK_AS_READ_EMOJI)
// Check if any reaction has our archive emoji
const hasReadReaction = events.some((event: NostrEvent) => event.content === ARCHIVE_EMOJI)
return hasReadReaction
} catch (error) {

View File

@@ -6,7 +6,7 @@ import { KINDS } from '../config/kinds'
import { RELAYS } from '../config/relays'
import { processReadingProgress } from './readingDataProcessor'
import { ReadItem } from './readsService'
import { MARK_AS_READ_EMOJI } from './reactionService'
import { ARCHIVE_EMOJI } from './reactionService'
import { nip19 } from 'nostr-tools'
console.log('[readingProgress] Module loaded')
@@ -324,7 +324,7 @@ class ReadingProgressController {
const handleUrlReaction = (evt: NostrEvent) => {
if (seenReactionIds.has(evt.id)) return
seenReactionIds.add(evt.id)
if (evt.content !== MARK_AS_READ_EMOJI) return
if (evt.content !== ARCHIVE_EMOJI) return
const rTag = evt.tags.find(t => t[0] === 'r')?.[1]
if (!rTag) return
this.markedAsReadIds.add(rTag)
@@ -335,7 +335,7 @@ class ReadingProgressController {
const handleEventReaction = (evt: NostrEvent) => {
if (seenReactionIds.has(evt.id)) return
seenReactionIds.add(evt.id)
if (evt.content !== MARK_AS_READ_EMOJI) return
if (evt.content !== ARCHIVE_EMOJI) return
const eTag = evt.tags.find(t => t[0] === 'e')?.[1]
if (!eTag) return
pendingEventIds.add(eTag)