mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 14:44:26 +01:00
fix(highlights): preserve immediate UI highlight after creation by merging streaming results instead of overwriting in article and external URL loaders
This commit is contained in:
@@ -74,19 +74,18 @@ export function useArticleLoader({
|
|||||||
try {
|
try {
|
||||||
setHighlightsLoading(true)
|
setHighlightsLoading(true)
|
||||||
setHighlights([]) // Clear old highlights
|
setHighlights([]) // Clear old highlights
|
||||||
const highlightsMap = new Map<string, Highlight>()
|
|
||||||
|
|
||||||
await fetchHighlightsForArticle(
|
await fetchHighlightsForArticle(
|
||||||
relayPool,
|
relayPool,
|
||||||
articleCoordinate,
|
articleCoordinate,
|
||||||
article.event.id,
|
article.event.id,
|
||||||
(highlight) => {
|
(highlight) => {
|
||||||
// Deduplicate highlights by ID as they arrive
|
// Merge streaming results with existing UI state to preserve locally created highlights
|
||||||
if (!highlightsMap.has(highlight.id)) {
|
setHighlights((prev) => {
|
||||||
highlightsMap.set(highlight.id, highlight)
|
if (prev.some(h => h.id === highlight.id)) return prev
|
||||||
const highlightsList = Array.from(highlightsMap.values())
|
const next = [highlight, ...prev]
|
||||||
setHighlights(highlightsList.sort((a, b) => b.created_at - a.created_at))
|
return next.sort((a, b) => b.created_at - a.created_at)
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
settings
|
settings
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -87,7 +87,13 @@ export function useExternalUrlLoader({
|
|||||||
|
|
||||||
// Seed with cached highlights first
|
// Seed with cached highlights first
|
||||||
if (cachedUrlHighlights.length > 0) {
|
if (cachedUrlHighlights.length > 0) {
|
||||||
setHighlights(cachedUrlHighlights.sort((a, b) => b.created_at - a.created_at))
|
setHighlights((prev) => {
|
||||||
|
// Seed with cache but keep any locally created highlights already in state
|
||||||
|
const seen = new Set<string>(cachedUrlHighlights.map(h => h.id))
|
||||||
|
const localOnly = prev.filter(h => !seen.has(h.id))
|
||||||
|
const next = [...cachedUrlHighlights, ...localOnly]
|
||||||
|
return next.sort((a, b) => b.created_at - a.created_at)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
setHighlights([])
|
setHighlights([])
|
||||||
}
|
}
|
||||||
@@ -106,7 +112,7 @@ export function useExternalUrlLoader({
|
|||||||
seen.add(highlight.id)
|
seen.add(highlight.id)
|
||||||
setHighlights((prev) => {
|
setHighlights((prev) => {
|
||||||
if (prev.some(h => h.id === highlight.id)) return prev
|
if (prev.some(h => h.id === highlight.id)) return prev
|
||||||
const next = [...prev, highlight]
|
const next = [highlight, ...prev]
|
||||||
return next.sort((a, b) => b.created_at - a.created_at)
|
return next.sort((a, b) => b.created_at - a.created_at)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -113,32 +113,6 @@ export const useHighlightInteractions = ({
|
|||||||
}, 10)
|
}, 10)
|
||||||
}, [onTextSelection, onClearSelection])
|
}, [onTextSelection, onClearSelection])
|
||||||
|
|
||||||
// Listen to document-level selection changes to catch keyboard/touch/ios cases
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = () => {
|
|
||||||
// Defer to allow DOM selection to settle
|
|
||||||
setTimeout(() => {
|
|
||||||
const selection = window.getSelection()
|
|
||||||
if (!selection || selection.rangeCount === 0) {
|
|
||||||
onClearSelection?.()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const range = selection.getRangeAt(0)
|
|
||||||
const text = selection.toString().trim()
|
|
||||||
|
|
||||||
if (text.length > 0 && contentRef.current?.contains(range.commonAncestorContainer)) {
|
|
||||||
onTextSelection?.(text)
|
|
||||||
} else {
|
|
||||||
onClearSelection?.()
|
|
||||||
}
|
|
||||||
}, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('selectionchange', handler)
|
|
||||||
return () => document.removeEventListener('selectionchange', handler)
|
|
||||||
}, [onTextSelection, onClearSelection])
|
|
||||||
|
|
||||||
return { contentRef, handleSelectionEnd }
|
return { contentRef, handleSelectionEnd }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user