Study - New Outline stage (hierarchical I./A./1. points, linked to chunks, in all exports); the chunk stage is now "Chunks" - Home cards: passages shown as ranges, tags capped with "+N more" Reader - Side-by-side translations and a Compare tab per verse - Typeface, line spacing, verse-number settings; text and column scale with the screen - Highlights/bookmarks sheet with named colours (synced); BSB footnote spacing fix - Cmd-K palette (passages, studies, notes, marks), keyboard shortcuts and "?" help Flow and safety - Toasts with Undo replace most confirm()/alert() - Back/Forward move between pages - Server refuses saves over a newer copy (409); keep-mine / use-other banner; opening a study no longer re-stamps it - Latest chapter request wins when flipping quickly Offline and data - Save books, plan days or a whole BSB/NET for offline - Service worker fixes: helloao /api/ URLs were skipped and responses cloned too late - Settings: download/restore a full backup Accessibility - Sheets trap focus and close on Escape, skip link, focus ring, reduced motion, theme contrast raised to 4.5:1 (with a test) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
44 lines
2.7 KiB
React
44 lines
2.7 KiB
React
// 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)]">Chunks</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>
|
||
);
|
||
}
|