Redesign the study side: Outline, Study, Script and Export stages
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>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-09-29 10:13:46 -04:00
1 parent b1bc1c8ea4
commit 31abee0695
31 files changed
+1911 -2460

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
// Left rail of the Study stage: every chunk of the project as an outline, with
// three dots (Observe / Interpret / Apply) showing which notes are written.
import { formatChunkReference } from '../../utils/bibleUtils.jsx';
const filled = (s) => (s ?? '').trim().length > 0;
export default function OutlineRail({ project, selectedId, onSelect, onEditOutline }) {
return (
<nav aria-label="Chunks" className="flex h-full min-h-0 flex-col">
<div className="flex items-center justify-between px-3 pb-2 pt-3">
<span className="text-[11px] uppercase tracking-wide text-[var(--r-sub)]">Outline</span>
<button type="button" onClick={onEditOutline} className="text-[11px] text-[var(--r-accent)] hover:underline">Edit</button>
</div>
<div className="min-h-0 flex-1 overflow-y-auto px-2 pb-4">
{project.chapters.map((ch, chapterIndex) => (
<div key={`${ch.bookAbbrev}-${ch.chapter}`} className="mb-3">
{project.chapters.length > 1 && <p className="px-2 pb-1 text-[11px] text-[var(--r-sub)]">{ch.book} {ch.chapter}</p>}
{ch.chunks.length === 0 && <p className="px-2 text-xs text-[var(--r-sub)]">No chunks in this chapter.</p>}
{ch.chunks.map((chunk) => {
const selected = chunk.id === selectedId;
const first = ch.verses.find((v) => v.number === chunk.startVerse)?.text ?? '';
return (
<button key={chunk.id} type="button" onClick={() => onSelect(chunk.id)} aria-current={selected ? 'true' : undefined}
className={`mb-1 block w-full rounded-xl border px-2.5 py-2 text-left transition ${selected ? 'border-[var(--r-line)] bg-[var(--r-bg)]' : 'border-transparent hover:bg-black/5'}`}>
<span className="flex items-center justify-between gap-2">
<span className="text-[13px] font-medium">{formatChunkReference(project, chapterIndex, chunk, '–')}</span>
<span className="flex gap-1" aria-hidden="true">
{['observation', 'interpretation', 'application'].map((f) => (
<span key={f} className={`h-2 w-2 rounded-full border ${filled(chunk[f]) ? 'border-[var(--r-accent)] bg-[var(--r-accent)]' : 'border-[var(--r-sub)]'}`} />
))}
</span>
</span>
{chunk.episodeTitle && <span className="mt-0.5 block truncate text-[11px] text-[var(--r-accent)]">{chunk.episodeNumber ? `${chunk.episodeNumber} · ` : ''}{chunk.episodeTitle}</span>}
<span className="mt-0.5 block truncate font-serif text-xs text-[var(--r-sub)]">{first}</span>
</button>
);
})}
</div>
))}
</div>
</nav>
);
}