Version history, notes on highlights and bookmarks, "you've studied this", prayer journal
Build and Push Docker Image / build-and-push (push) Successful in 5m13s

- Earlier versions of a study: the server keeps compressed copies (about one per ten minutes of
  editing, the latest 30); Export shows what differs and puts one back (the replaced copy is kept)
- Notes on highlights and bookmarks: synced, merged without loss, in exports and backups
- Reader verse panel lists your studies and chunks that cover the verse, and opens them
- Prayer journal: requests, who for, linked verses, days prayed, answers; synced, in backups
  and the account export; daily prayer reminder through ntfy
- TODO.md lists the ideas not built yet

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-06 10:45:32 -04:00
1 parent 54cb1c217d
commit 207bfcb919
45 files changed
+1669 -75

No files matched your search

+11 -1
View File
@@ -5,6 +5,7 @@ const BOOKMARK_KEY = /^[1-3]?[A-Za-z]{2,3}-\d{1,3}-\d{1,3}$/; // e.g. "JHN-3-16"
const BOOK = /^[1-3A-Za-z]{3}$/;
const MAX_BOOKMARKS = 5000;
const MAX_HIGHLIGHTS = 20000;
const MAX_NOTE = 500;
const int = (v, min, max) => Number.isInteger(v) && v >= min && v <= max;
@@ -20,6 +21,14 @@ export function cleanMarks(body) {
}
}
// A short note on a bookmark: { "JHN-3-16": "my note" }
const bookmarkNotes = {};
if (body.bookmarkNotes && typeof body.bookmarkNotes === 'object' && !Array.isArray(body.bookmarkNotes)) {
for (const [key, note] of Object.entries(body.bookmarkNotes).slice(0, MAX_BOOKMARKS)) {
if (BOOKMARK_KEY.test(key) && typeof note === 'string' && note.trim()) bookmarkNotes[key] = note.slice(0, MAX_NOTE);
}
}
const highlights = [];
if (Array.isArray(body.highlights)) {
const seen = new Set();
@@ -39,8 +48,9 @@ export function cleanMarks(body) {
// Which translation the words were selected in, and whether it is a whole-verse highlight
if (typeof h.translation === 'string' && /^[A-Za-z0-9]{2,8}$/.test(h.translation)) entry.translation = h.translation;
if (h.whole === true) entry.whole = true;
if (typeof h.note === 'string' && h.note.trim()) entry.note = h.note.slice(0, MAX_NOTE);
highlights.push(entry);
}
}
return { bookmarks, highlights };
return { bookmarks, highlights, bookmarkNotes };
}