Import: downloadable Word template for the session list
Build and Push Docker Image / build-and-push (push) Failing after 20s
Build and Push Docker Image / build-and-push (push) Failing after 20s
A blank three-column session list (Session #, Title, Passage) with instructions and example rows, built in the browser on demand. A test imports the generated file back through the real importer. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7a010fcda8
commit
ec59f7c82d
4 files changed
+136
-1
No files matched your search
@@ -0,0 +1,63 @@
|
||||
// A blank "Session list" Word document for the Import page: a three-column table
|
||||
// (session number, title, passage) in exactly the shape the importer reads, with a few example
|
||||
// rows to overwrite. Built in the browser on demand, so the `docx` library only downloads when
|
||||
// someone actually asks for the template.
|
||||
import {
|
||||
Document, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, TextRun, WidthType, HeadingLevel,
|
||||
} from 'docx';
|
||||
|
||||
export const TEMPLATE_FILENAME = 'session-list-template.docx';
|
||||
|
||||
// Example rows show each kind of passage the importer understands.
|
||||
export const TEMPLATE_ROWS = [
|
||||
['1', 'Paul’s greeting', '1:1–4'],
|
||||
['2', 'Appointing elders', '1:5–9'],
|
||||
['3', 'Rebuking false teachers', '1:10–16'],
|
||||
['4', 'A recap of chapter 1', '—'], // no passage: becomes a divider or intro with no verses
|
||||
['5', 'Teaching sound doctrine', '2:1–10'],
|
||||
['6', 'A passage that crosses a chapter', '2:11–3:2'],
|
||||
];
|
||||
|
||||
const cell = (text, { bold = false, shade = false, width } = {}) => new TableCell({
|
||||
width: { size: width, type: WidthType.PERCENTAGE },
|
||||
shading: shade ? { type: ShadingType.CLEAR, fill: 'EDE7D9', color: 'auto' } : undefined,
|
||||
margins: { top: 80, bottom: 80, left: 120, right: 120 },
|
||||
children: [new Paragraph({ children: [new TextRun({ text, bold })] })],
|
||||
});
|
||||
|
||||
const row = (cells, header = false) => new TableRow({
|
||||
tableHeader: header,
|
||||
children: cells.map((text, i) => cell(text, { bold: header, shade: header, width: [15, 55, 30][i] })),
|
||||
});
|
||||
|
||||
const note = (text) => new Paragraph({ spacing: { after: 100 }, children: [new TextRun({ text })] });
|
||||
|
||||
export function buildImportTemplateDocument() {
|
||||
return new Document({
|
||||
sections: [{
|
||||
children: [
|
||||
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun({ text: 'Session list' })] }),
|
||||
note('Replace the example rows below with your own, one row per session, then upload this file on the Import page.'),
|
||||
note('Passage: chapter:verse, like 1:1–4. To cross a chapter, write both chapters, like 2:11–3:2. For a session with no passage (an intro or a recap), write — (a dash).'),
|
||||
note('You choose the book on the Import page, so leave it out of the Passage column. Keep the three columns, and delete any example rows you don’t need.'),
|
||||
new Table({
|
||||
width: { size: 100, type: WidthType.PERCENTAGE },
|
||||
rows: [row(['Session #', 'Title', 'Passage'], true), ...TEMPLATE_ROWS.map((r) => row(r))],
|
||||
}),
|
||||
],
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
// Builds the template and hands it to the browser as a download.
|
||||
export async function downloadImportTemplate() {
|
||||
const blob = await Packer.toBlob(buildImportTemplateDocument());
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = TEMPLATE_FILENAME;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
Reference in new issue
Block a user