Outline: per-chunk outlines, richer points, print and share
- One outline for the whole study plus one per chunk (picker at the top); chunk outlines can start from the chunk's verses, each carrying its words - Points can have a type (illustration, application, quote, question, transition), minutes (with a running total), a longer note, verse text fetched from a passage, and cross-references / word studies attached from the chunk - Share (system share sheet, or copy), Print / PDF, Copy as text, Word and Markdown downloads for any one outline - All of it included in the Markdown, HTML/PDF and Word study exports, with each chunk's outline under that chunk Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d273c8cb3e
commit
820886e3ab
12 files changed
+741
-103
No files matched your search
+40
-12
@@ -14,7 +14,8 @@ import {
|
||||
WidthType,
|
||||
} from 'docx';
|
||||
import { formatChunkReference, getChunkVerseEntries, htmlToPlainText } from './bibleUtils.jsx';
|
||||
import { flatten } from './outline.js';
|
||||
import { detailLines, flatten, timeSummary } from './outline.js';
|
||||
import { kindLabel } from './outlineLabels.js';
|
||||
|
||||
export function createParagraphsFromText(text) {
|
||||
return text
|
||||
@@ -73,6 +74,37 @@ export function sectionLabel(text) {
|
||||
});
|
||||
}
|
||||
|
||||
// The paragraphs of an outline: each point indented by level, with its note, verse and attachments under it.
|
||||
export const outlineParagraphs = (tree) => flatten(tree).flatMap(({ node, depth, label }) => [
|
||||
new Paragraph({
|
||||
indent: { left: 420 * depth, hanging: 420 },
|
||||
spacing: { after: 60 },
|
||||
children: [
|
||||
new TextRun({ text: `${label}\t`, bold: true, color: DOCX_ACCENT }),
|
||||
...(node.kind ? [new TextRun({ text: `${kindLabel(node.kind)}: `, italics: true, color: '92400E' })] : []),
|
||||
new TextRun({ text: (node.text ?? '').trim() || '(untitled)' }),
|
||||
...(node.ref ? [new TextRun({ text: ` (${node.ref})`, italics: true, color: '7A7060' })] : []),
|
||||
...(Number.isFinite(node.minutes) && node.minutes > 0 ? [new TextRun({ text: ` · ${node.minutes} min`, color: '7A7060' })] : []),
|
||||
],
|
||||
}),
|
||||
...detailLines(node).map((line) => new Paragraph({
|
||||
indent: { left: 420 * depth + 420 },
|
||||
spacing: { after: 40 },
|
||||
children: [new TextRun({ text: line, italics: true, color: '4B5563', size: 20 })],
|
||||
})),
|
||||
]);
|
||||
|
||||
// Just one outline, as its own Word document.
|
||||
export async function buildOutlineDocxBlob({ title, subtitle = '', tree }) {
|
||||
const children = [
|
||||
new Paragraph({ text: title, heading: HeadingLevel.TITLE }),
|
||||
new Paragraph({ children: [new TextRun({ text: [subtitle, timeSummary(tree)].filter(Boolean).join(' · '), italics: true, color: '7A7060' })], spacing: { after: 300 } }),
|
||||
...outlineParagraphs(tree),
|
||||
];
|
||||
const doc = new Document({ styles: DOCX_STYLES, sections: [{ children }] });
|
||||
return Packer.toBlob(doc);
|
||||
}
|
||||
|
||||
export async function buildStudyDocxBlob(project, chapterSummary) {
|
||||
const children = [
|
||||
new Paragraph({ text: project.title, heading: HeadingLevel.TITLE }),
|
||||
@@ -93,17 +125,8 @@ export async function buildStudyDocxBlob(project, chapterSummary) {
|
||||
// The outline comes first, indented by level like the page
|
||||
if ((project.outline ?? []).length > 0) {
|
||||
children.push(new Paragraph({ text: 'Outline', heading: HeadingLevel.HEADING_1, spacing: { before: 240, after: 160 } }));
|
||||
flatten(project.outline).forEach(({ node, depth, label }) => {
|
||||
children.push(new Paragraph({
|
||||
indent: { left: 420 * depth, hanging: 420 },
|
||||
spacing: { after: 80 },
|
||||
children: [
|
||||
new TextRun({ text: `${label}\t`, bold: true, color: DOCX_ACCENT }),
|
||||
new TextRun({ text: (node.text ?? '').trim() || '(untitled)' }),
|
||||
...(node.ref ? [new TextRun({ text: ` (${node.ref})`, italics: true, color: '7A7060' })] : []),
|
||||
],
|
||||
}));
|
||||
});
|
||||
if (timeSummary(project.outline)) children.push(new Paragraph({ children: [new TextRun({ text: timeSummary(project.outline), italics: true, color: '7A7060' })], spacing: { after: 120 } }));
|
||||
children.push(...outlineParagraphs(project.outline));
|
||||
}
|
||||
|
||||
project.chapters.forEach((ch, chapterIndex) => {
|
||||
@@ -154,6 +177,11 @@ export async function buildStudyDocxBlob(project, chapterSummary) {
|
||||
}));
|
||||
children.push(new Paragraph({ text: '', spacing: { after: 120 } }));
|
||||
|
||||
if ((chunk.outline ?? []).length > 0) {
|
||||
children.push(sectionLabel('Outline'));
|
||||
children.push(...outlineParagraphs(chunk.outline));
|
||||
}
|
||||
|
||||
if (chunk.generalNotes?.trim()) {
|
||||
children.push(sectionLabel('Background / General Notes'));
|
||||
children.push(...createParagraphsFromText(chunk.generalNotes));
|
||||
|
||||
Reference in new issue
Block a user