Add text highlighting in reader — select text to color, visible in read and draw mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-08-13 15:03:08 -04:00
1 parent b4ccc15f98
commit 22ad12e677
2 files changed
+162 -19

No files matched your search

+26
View File
@@ -1199,6 +1199,12 @@ const App = () => {
try { return JSON.parse(localStorage.getItem('readerInkByPage') ?? '{}'); }
catch { return {}; }
});
const [readerTextHighlights, setReaderTextHighlights] = useState(() => {
try {
const val = JSON.parse(localStorage.getItem('readerTextHighlights') || '[]');
return Array.isArray(val) ? val : [];
} catch { return []; }
});
// Debounce timer ref so rapid stroke updates don't flood the server
const inkSaveTimerRef = useRef({});
const audioRef = useRef(null);
@@ -1582,6 +1588,23 @@ const App = () => {
});
};
const addTextHighlight = (highlight) => {
const id = (typeof crypto !== 'undefined' && crypto.randomUUID) ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
setReaderTextHighlights(prev => {
const next = [...prev, { id, ...highlight }];
try { localStorage.setItem('readerTextHighlights', JSON.stringify(next)); } catch {}
return next;
});
};
const removeTextHighlight = (id) => {
setReaderTextHighlights(prev => {
const next = prev.filter(h => h.id !== id);
try { localStorage.setItem('readerTextHighlights', JSON.stringify(next)); } catch {}
return next;
});
};
const loadReaderCrossRefs = async (bookAbbrev, chapterNumber) => {
const cacheKey = `${bookAbbrev}/${chapterNumber}`;
if (_readerCrossRefCacheRef.current[cacheKey]) {
@@ -3772,6 +3795,9 @@ const deleteProject = (id) => {
readerAudioState,
readerInkByPage,
updateReaderPageInk,
readerTextHighlights,
addTextHighlight,
removeTextHighlight,
bibleIndexStatus,
loadReaderChapter,
_bibleIndexCacheRef,