mirror of
https://github.com/dergigi/boris.git
synced 2026-02-22 23:44:51 +01:00
chore: commit pending working changes before implementing unarchive behavior
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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]) => ({
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user