Files
study-bible-project/src/utils/ownWork.js
T
nmemmertandClaude Sonnet 5.5 648c3206df Highlight translation differences, first-draft snapshot, verse notes, paste check
- 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>
2026-10-14 12:56:57 -04:00

64 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// "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 };
}