68 lines
5.0 KiB
React
68 lines
5.0 KiB
React
// The chunk's passage, set like the Reader. Click a verse number to open its
|
|
// interlinear words; click an original word to add it to the chunk's word study.
|
|
import { useState } from 'react';
|
|
import { NT_BOOK_NUMBER } from '../../utils/bibleUtils.jsx';
|
|
import GrammarPanel from '../GrammarPanel.jsx';
|
|
import { markUnits } from '../../utils/biblicalUnits.js';
|
|
|
|
export default function ScripturePane({ verses, chapter, interlinear, interlinearLoading, addedStrongs, onPickWord, verseNotes = {}, onVerseNote }) {
|
|
const [openVerse, setOpenVerse] = useState(null);
|
|
const [editingNote, setEditingNote] = useState(null);
|
|
const [inspect, setInspect] = useState(null); // the original word whose grammar is showing: { key, index }
|
|
const isHebrew = chapter && !NT_BOOK_NUMBER[chapter.bookAbbrev];
|
|
return (
|
|
<section aria-label="Scripture" className="rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] px-5 py-4">
|
|
<div className="font-serif text-[1.05rem] leading-[1.85]">
|
|
{verses.map((v) => {
|
|
const words = v.chapter === chapter?.chapter ? interlinear?.[String(v.number)] : null;
|
|
const open = openVerse === `${v.chapter}:${v.number}`;
|
|
return (
|
|
<div key={`${v.chapter}-${v.number}`} className="mb-1.5">
|
|
<button type="button" disabled={!words} onClick={() => setOpenVerse(open ? null : `${v.chapter}:${v.number}`)}
|
|
title={words ? 'Show original words' : undefined}
|
|
className={`mr-1.5 align-super font-sans text-[0.6em] ${words ? 'text-[var(--r-accent)] hover:underline' : 'cursor-default text-[var(--r-sub)]'} ${open ? 'font-bold' : ''}`}>
|
|
{v.chapter !== chapter?.chapter ? `${v.chapter}:` : ''}{v.number}
|
|
</button>
|
|
<span>{markUnits(v.text).map((part, i) => (part.note
|
|
? <abbr key={i} title={part.note} tabIndex={0} className="cursor-help underline decoration-dotted decoration-[var(--r-accent)] underline-offset-4">{part.text}</abbr>
|
|
: <span key={i}>{part.text}</span>))}</span>
|
|
{onVerseNote && (
|
|
<button type="button" onClick={() => setEditingNote(editingNote === `${v.chapter}:${v.number}` ? null : `${v.chapter}:${v.number}`)}
|
|
aria-label={`Note on verse ${v.number}`} title="Note on this verse"
|
|
className={`ml-1.5 align-baseline font-sans text-[0.7em] ${verseNotes[`${v.chapter}:${v.number}`] ? 'text-[var(--r-accent)]' : 'text-[var(--r-sub)] opacity-40 hover:opacity-100'}`}>✎</button>
|
|
)}
|
|
{(verseNotes[`${v.chapter}:${v.number}`] || editingNote === `${v.chapter}:${v.number}`) && (
|
|
<textarea aria-label={`Verse ${v.number} note`} value={verseNotes[`${v.chapter}:${v.number}`] ?? ''} rows={2} autoFocus={editingNote === `${v.chapter}:${v.number}`}
|
|
onChange={(e) => onVerseNote?.(`${v.chapter}:${v.number}`, e.target.value)}
|
|
placeholder="Your note on this verse"
|
|
className="mt-1 block w-full resize-y rounded-lg border border-[var(--r-line)] bg-[var(--r-bg)] px-2.5 py-1.5 font-sans text-[13px] leading-snug text-[var(--r-text)] focus:outline-none focus:ring-2 focus:ring-[var(--r-line)]" />
|
|
)}
|
|
{open && words && (
|
|
<div dir={isHebrew ? 'rtl' : 'ltr'} className="mt-2 flex flex-wrap gap-2 rounded-xl bg-[var(--r-bg)] p-2.5 font-sans">
|
|
{words.map((w, i) => {
|
|
const added = w.s && addedStrongs.has(w.s.toUpperCase());
|
|
return (
|
|
<button key={i} type="button" disabled={!w.s} onClick={() => onPickWord(w)}
|
|
onMouseEnter={() => setInspect({ key: `${v.chapter}:${v.number}`, index: i })} onFocus={() => setInspect({ key: `${v.chapter}:${v.number}`, index: i })}
|
|
title={[w.t, w.s, w.p].filter(Boolean).join(' · ') + (w.s ? (added ? ' — already in word study' : ' — click to add') : '')}
|
|
className={`flex flex-col items-center rounded-lg border px-2 py-1 text-center ${added ? 'border-[var(--r-accent)]' : 'border-[var(--r-line)] hover:bg-black/5'} disabled:cursor-default`}>
|
|
<span className={`text-base ${isHebrew ? 'font-serif' : ''}`}>{w.o}</span>
|
|
<span className="text-[11px] leading-tight text-[var(--r-sub)]">{w.g || '—'}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
{inspect?.key === `${v.chapter}:${v.number}` && words[inspect.index]?.p && (
|
|
<GrammarPanel label={words[inspect.index].p} className="basis-full" />
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
{interlinearLoading && <p className="mt-2 font-sans text-xs text-[var(--r-sub)]">Loading original words…</p>}
|
|
{!interlinearLoading && interlinear && <p className="mt-2 font-sans text-[11px] text-[var(--r-sub)]">Click a verse number to see its original words; click a word to study it.</p>}
|
|
</section>
|
|
);
|
|
}
|