- Compare translations can highlight the words that differ from the first translation (toggle remembered). - A copy of your notes is kept the first time commentary is shown; "First draft, before commentary" under More shows what changed since. Saving it doesn't count as editing the chunk. - Notes on single verses: a pencil next to each verse in Study, and a note line under each verse in Compare. They merge per verse across devices. - Pasting 15+ words into a note asks "Is this from AI?"; "I wrote it" counts the words as yours again. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
64 lines
3.1 KiB
JavaScript
64 lines
3.1 KiB
JavaScript
// "Is this study my own work?" — how much of each chunk's Observe / Interpret /
|
||
// Apply notes has been written by hand (long pastes don't count as your own). Used to hold back the "→ Claude" prompts
|
||
// until the thinking has been done by you, not handed to AI.
|
||
export const OWN_WORK_MINIMUMS = { observation: 20, interpretation: 20, application: 10 };
|
||
const LABELS = { observation: 'Observe', interpretation: 'Interpret', application: 'Apply' };
|
||
|
||
const words = (s) => (s ?? '').trim().split(/\s+/).filter(Boolean).length;
|
||
|
||
// A paste this long into a note box is remembered as "not typed by me" (chunk.aiPastes[field] = [text, …]).
|
||
export const PASTE_MIN_WORDS = 15;
|
||
export const NOTE_FIELDS = Object.keys(OWN_WORK_MINIMUMS);
|
||
|
||
// -> the chunk's new aiPastes after pasting `pasted` into `field`, or null when the paste is too short to count.
|
||
export function withPaste(chunk, field, pasted) {
|
||
const text = (pasted ?? '').trim();
|
||
if (words(text) < PASTE_MIN_WORDS) return null;
|
||
const all = chunk?.aiPastes ?? {};
|
||
return { ...all, [field]: [...(all[field] ?? []), text] };
|
||
}
|
||
|
||
// Words in `field` that came from a long paste still present in the note (delete or rewrite it and it stops counting).
|
||
export function pastedWords(chunk, field) {
|
||
const body = chunk?.[field] ?? '';
|
||
return (chunk?.aiPastes?.[field] ?? []).filter((t) => body.includes(t)).reduce((n, t) => n + words(t), 0);
|
||
}
|
||
|
||
export const ownWords = (chunk, field) => Math.max(0, words(chunk?.[field]) - pastedWords(chunk, field));
|
||
|
||
// Share of the three notes' words that are typed or dictated rather than pasted, 0–100 (null when nothing is written).
|
||
export function ownShare(chunk) {
|
||
const total = NOTE_FIELDS.reduce((n, f) => n + words(chunk?.[f]), 0);
|
||
if (!total) return null;
|
||
return Math.round((NOTE_FIELDS.reduce((n, f) => n + ownWords(chunk, f), 0) / total) * 100);
|
||
}
|
||
|
||
// "That's mine": stop counting the pastes in one field.
|
||
export const clearPastes = (chunk, field) => ({ ...(chunk?.aiPastes ?? {}), [field]: [] });
|
||
|
||
// The note fields of one chunk that are still under their minimum word count.
|
||
export function thinFields(chunk) {
|
||
return Object.entries(OWN_WORK_MINIMUMS)
|
||
.filter(([field, min]) => ownWords(chunk, field) < min)
|
||
.map(([field]) => ({ field, label: LABELS[field], have: ownWords(chunk, field), need: OWN_WORK_MINIMUMS[field] }));
|
||
}
|
||
|
||
// Chunks that still need your own notes, with what's missing in each.
|
||
export function chunksNeedingWork(chunks) {
|
||
return (chunks ?? []).map((chunk) => ({ chunk, missing: thinFields(chunk) })).filter((entry) => entry.missing.length > 0);
|
||
}
|
||
|
||
// Commentary and study aids stay folded away until you've written this much of your own Observe notes.
|
||
export const OBSERVE_FIRST_MIN = 15;
|
||
export const observeFirstDone = (chunk) => ownWords(chunk, 'observation') >= OBSERVE_FIRST_MIN;
|
||
|
||
// "No, I wrote it": take one remembered paste back out, so those words count as your own again.
|
||
export function withoutPaste(chunk, field, pasted) {
|
||
const text = (pasted ?? '').trim();
|
||
const all = chunk?.aiPastes ?? {};
|
||
const list = [...(all[field] ?? [])];
|
||
const at = list.lastIndexOf(text);
|
||
if (at >= 0) list.splice(at, 1);
|
||
return { ...all, [field]: list };
|
||
}
|