Build and Push Docker Image / build-and-push (push) Successful in 4m15s
Studies now move through a stage bar in the reader's themes. Outline splits chunks by clicking between verses (join merges notes) and suggests chunks from section headings. Study is three panes: outline, passage with an Observe / Interpret / Apply accordion, and commentary / word study / cross-refs / people & places for the chunk; original words are added by clicking them in the interlinear. Script drafts an outline from notes; Export holds files and the share link. Home, Import and the Pronunciation guide are restyled. Study projects are BSB only. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
51 lines
3.4 KiB
React
51 lines
3.4 KiB
React
// Picker for "suggest words from this passage": checkbox list of candidate words.
|
|
import DOMPurify from 'dompurify';
|
|
import Sheet from '../reader/Sheet.jsx';
|
|
import { buildGreekDefinitionHtml } from '../../utils/wordStudy.js';
|
|
|
|
export default function SuggestWordsSheet({ wordStudy }) {
|
|
const { suggestModal, setSuggestModal, suggestSelection, setSuggestSelection, confirmSuggestWords } = wordStudy;
|
|
if (!suggestModal) return null;
|
|
const close = () => { setSuggestModal(null); setSuggestSelection(new Set()); };
|
|
const n = suggestSelection.size;
|
|
return (
|
|
<Sheet open onClose={close} title={`Select ${suggestModal.language === 'hebrew' ? 'Hebrew' : 'Greek'} words to add`}>
|
|
<p className="mb-2 text-xs text-[var(--r-sub)]">{suggestModal.helperText || "Content words are pre-checked. Uncheck any you don't need."}</p>
|
|
<div className="mb-2 flex items-center gap-3 text-xs">
|
|
<button type="button" onClick={() => setSuggestSelection(new Set(suggestModal.words.map((w) => w.strongKey)))} className="text-[var(--r-accent)] hover:underline">Select all</button>
|
|
<button type="button" onClick={() => setSuggestSelection(new Set())} className="text-[var(--r-accent)] hover:underline">Select none</button>
|
|
<span className="ml-auto text-[var(--r-sub)]">{n} selected</span>
|
|
</div>
|
|
<ul className="max-h-[40vh] divide-y divide-[var(--r-line)] overflow-y-auto rounded-xl border border-[var(--r-line)] px-3">
|
|
{suggestModal.words.map((w) => (
|
|
<li key={w.strongKey}>
|
|
<label className="flex cursor-pointer items-center gap-3 py-2.5">
|
|
<input type="checkbox" checked={suggestSelection.has(w.strongKey)} className="h-4 w-4 shrink-0 accent-[var(--r-accent)]"
|
|
onChange={(e) => setSuggestSelection((prev) => { const next = new Set(prev); if (e.target.checked) next.add(w.strongKey); else next.delete(w.strongKey); return next; })} />
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex flex-wrap items-baseline gap-2">
|
|
<span className="text-sm font-medium">{w.def || w.strongKey}</span>
|
|
<span className="text-sm text-[var(--r-sub)]">{w.lexeme}</span>
|
|
{w.translit && <span className="text-xs italic text-[var(--r-sub)]">{w.translit}</span>}
|
|
<span className="font-mono text-[10px] text-[var(--r-sub)]">{w.strongKey}</span>
|
|
</div>
|
|
{w.entry && (w.entry.strongs_def || w.entry.kjv_def || w.entry.derivation) && (
|
|
<details className="mt-1">
|
|
<summary className="cursor-pointer text-xs text-[var(--r-accent)]" onClick={(e) => e.stopPropagation()}>Definition</summary>
|
|
<div className="mt-1 text-xs leading-5" dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(buildGreekDefinitionHtml(w.strongKey, w.entry)) }} />
|
|
</details>
|
|
)}
|
|
</div>
|
|
</label>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
<div className="mt-3 flex gap-2">
|
|
<button type="button" onClick={close} className="flex-1 rounded-xl border border-[var(--r-line)] py-2 text-sm hover:bg-black/5">Cancel</button>
|
|
<button type="button" onClick={confirmSuggestWords} disabled={n === 0}
|
|
className="flex-1 rounded-xl bg-[var(--r-accent)] py-2 text-sm font-medium text-[var(--r-on)] disabled:opacity-40">Add {n > 0 ? `${n} word${n > 1 ? 's' : ''}` : 'words'}</button>
|
|
</div>
|
|
</Sheet>
|
|
);
|
|
}
|