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
@@ -0,0 +1,45 @@
|
||||
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
|
||||
import { attachableFromChunk, fetchPassageText, parsePassageRange } from './passageText.js';
|
||||
|
||||
const chapter = { chapter: { content: [1, 2, 3, 4, 5].map((n) => ({ type: 'verse', number: n, content: [`Verse ${n} text.`] })) } };
|
||||
beforeEach(() => vi.stubGlobal('fetch', vi.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(chapter) }))));
|
||||
afterEach(() => vi.unstubAllGlobals());
|
||||
|
||||
test('reads a verse, a range, or a whole chapter', () => {
|
||||
expect(parsePassageRange('Titus 1:5')).toMatchObject({ book: 'TIT', chapter: 1, start: 5, end: 5 });
|
||||
expect(parsePassageRange('titus 1:5-9')).toMatchObject({ start: 5, end: 9 });
|
||||
expect(parsePassageRange('1 Cor 13:4–7')).toMatchObject({ book: '1CO', chapter: 13, start: 4, end: 7 });
|
||||
expect(parsePassageRange('John 3')).toMatchObject({ chapter: 3, start: null });
|
||||
});
|
||||
|
||||
test('rejects things that are not passages, or backwards ranges', () => {
|
||||
expect(parsePassageRange('hello')).toBeNull();
|
||||
expect(parsePassageRange('Titus 9:1')).toBeNull();
|
||||
expect(parsePassageRange('Titus 1:9-5')).toBeNull();
|
||||
});
|
||||
|
||||
test('fetches just the verses asked for, and names the passage', async () => {
|
||||
const got = await fetchPassageText('Titus 1:2-3');
|
||||
expect(got).toEqual({ ref: 'Titus 1:2–3', text: 'Verse 2 text. Verse 3 text.', translation: 'BSB' });
|
||||
});
|
||||
|
||||
test('says so when the verses are not there, or the passage is not understood', async () => {
|
||||
await expect(fetchPassageText('Titus 1:50')).rejects.toThrow(/weren’t found/);
|
||||
await expect(fetchPassageText('nonsense')).rejects.toThrow(/Type a passage/);
|
||||
});
|
||||
|
||||
test('offers a chunk\'s cross-references and studied words to attach', () => {
|
||||
const chunk = {
|
||||
crossReferences: ['John 1:1'],
|
||||
greekWords: [
|
||||
{ strongNumber: 'G1401', lexeme: 'δοῦλος', shortDefinition: 'a slave' },
|
||||
{ query: 'xyz', shortDefinition: 'No definition found.' },
|
||||
],
|
||||
};
|
||||
expect(attachableFromChunk(chunk)).toEqual([
|
||||
{ key: 'x:John 1:1', type: 'xref', label: 'John 1:1' },
|
||||
{ key: 'w:G1401', type: 'word', label: 'δοῦλος (G1401)', detail: 'a slave' },
|
||||
{ key: 'w:xyz', type: 'word', label: 'xyz', detail: undefined },
|
||||
]);
|
||||
expect(attachableFromChunk(null)).toEqual([]);
|
||||
});
|
||||
Reference in new issue
Block a user