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

+6 -4
View File
@@ -13,8 +13,8 @@ const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
export default function DataSection() {
const {
authUser, readerBookmarks, readerTextHighlights, readerColorLabels, readerInkByPage, readingPlansState,
importReaderMarks, importReadingPlans, refreshProjectIndex,
authUser, readerBookmarks, readerBookmarkNotes, readerTextHighlights, readerColorLabels, readerInkByPage, readingPlansState,
importReaderMarks, importReadingPlans, refreshProjectIndex, prayers, importPrayers,
} = useApp();
const { toast } = useToast();
const offline = useOfflineSave();
@@ -26,8 +26,9 @@ export default function DataSection() {
const download = () => {
const backup = buildBackup({
email: authUser?.email ?? null,
reader: { bookmarks: readerBookmarks, highlights: readerTextHighlights, colorLabels: readerColorLabels, ink: readerInkByPage },
reader: { bookmarks: readerBookmarks, bookmarkNotes: readerBookmarkNotes, highlights: readerTextHighlights, colorLabels: readerColorLabels, ink: readerInkByPage },
readingPlans: readingPlansState,
prayers,
});
const url = URL.createObjectURL(new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' }));
const link = document.createElement('a');
@@ -59,6 +60,7 @@ export default function DataSection() {
const written = restoreProjects(backup.projects);
importReaderMarks(backup.reader);
importReadingPlans(backup.readingPlans);
importPrayers?.(backup.prayers);
refreshProjectIndex();
// Studies restored here also go to the account, so they follow you to other devices
if (authUser) await Promise.all(written.map((p) => saveRemoteProject(p)));
@@ -88,7 +90,7 @@ export default function DataSection() {
<div className="rounded-xl border border-[var(--r-line)] bg-[var(--r-bg)] p-4 text-sm">
<p className="font-medium">{pending.name}</p>
<p className="mt-1 text-[var(--r-sub)]">
Contains {plural(s.projects, 'study', 'studies')}, {plural(s.bookmarks, 'bookmark')}, {plural(s.highlights, 'highlight')}, {plural(s.inkPages, 'ink page')} and {plural(s.plans, 'reading plan')}.
Contains {plural(s.projects, 'study', 'studies')}, {plural(s.bookmarks, 'bookmark')}, {plural(s.highlights, 'highlight')}, {plural(s.inkPages, 'ink page')}, {plural(s.plans, 'reading plan')} and {plural(s.prayers ?? 0, 'prayer')}.
Restoring adds these to what you have — nothing is deleted, and a study on this device is only replaced if the backup’s copy is newer.
</p>
<div className="mt-3 flex gap-2">