Files
study-bible-project/src/components/reader/MarkNote.jsx
T
nmemmertandClaude Sonnet 5.5 207bfcb919
Build and Push Docker Image / build-and-push (push) Successful in 5m13s
Version history, notes on highlights and bookmarks, "you've studied this", prayer journal
- 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>
2026-10-06 10:45:32 -04:00

34 lines
2.0 KiB
React

// A short note on a highlight or a bookmark: shown under it, added or edited in place.
import { useState } from 'react';
export default function MarkNote({ note = '', onSave, label = 'note', className = '' }) {
const [editing, setEditing] = useState(false);
const [draft, setDraft] = useState('');
const open = () => { setDraft(note); setEditing(true); };
const save = () => { onSave(draft.trim()); setEditing(false); };
if (editing) {
return (
<div className={className}>
<textarea autoFocus value={draft} maxLength={500} rows={2} aria-label={`Your ${label}`} onChange={(e) => setDraft(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); save(); } else if (e.key === 'Escape') { e.stopPropagation(); setEditing(false); } }}
className="w-full resize-y rounded-lg border border-[var(--r-line)] bg-[var(--r-bg)] px-2.5 py-1.5 text-sm text-[var(--r-text)] focus:outline-none focus:ring-2 focus:ring-[var(--r-line)]" placeholder="What does this mean to you?" />
<div className="mt-1 flex items-center gap-3 text-xs">
<button type="button" onClick={save} className="font-medium text-[var(--r-accent)] hover:underline">Save</button>
<button type="button" onClick={() => setEditing(false)} className="text-[var(--r-sub)] hover:underline">Cancel</button>
<span className="ml-auto text-[10px] text-[var(--r-sub)]">{draft.length}/500</span>
</div>
</div>
);
}
if (!note) {
return <div className={className}><button type="button" onClick={open} className="text-xs text-[var(--r-accent)] hover:underline">+ Add {label}</button></div>;
}
return (
<div className={`${className} flex items-start gap-2`}>
<p className="min-w-0 flex-1 whitespace-pre-wrap rounded-lg bg-[var(--r-bg)] px-2.5 py-1.5 text-[13px] italic text-[var(--r-text)]">{note}</p>
<button type="button" onClick={open} aria-label={`Edit ${label}`} className="shrink-0 text-xs text-[var(--r-sub)] hover:underline">Edit</button>
</div>
);
}