Add Outline stage, parallel reading, offline saves, backup, sync-conflict handling and more
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>
This commit is contained in:
1 parent
1edbd364ea
commit
d13f55faf7
65 files changed
+2947
-208
No files matched your search
@@ -0,0 +1,37 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { formatPassage, matchBooks, parsePassageRef } from './passageRef.js';
|
||||
|
||||
const first = (text) => parsePassageRef(text)[0];
|
||||
|
||||
test('understands a book, chapter and verse in the usual ways', () => {
|
||||
expect(first('John 3:16')).toMatchObject({ book: 'JHN', chapter: 3, verse: 16 });
|
||||
expect(first('jn 3 16')).toMatchObject({ book: 'JHN', chapter: 3, verse: 16 });
|
||||
expect(first('Ps 23')).toMatchObject({ book: 'PSA', chapter: 23, verse: null });
|
||||
expect(first('1 cor 13:4')).toMatchObject({ book: '1CO', chapter: 13, verse: 4 });
|
||||
expect(first('1corinthians 13')).toMatchObject({ book: '1CO', chapter: 13 });
|
||||
expect(first('song of solomon 2')).toMatchObject({ book: 'SNG', chapter: 2 });
|
||||
expect(first('Rom. 8.28')).toMatchObject({ book: 'ROM', chapter: 8, verse: 28 });
|
||||
});
|
||||
|
||||
test('a bare book name opens its first chapter', () => {
|
||||
expect(first('romans')).toMatchObject({ book: 'ROM', chapter: 1, hasChapter: false });
|
||||
});
|
||||
|
||||
test('a name that fits several books lists them; a short form picks one', () => {
|
||||
expect(matchBooks('jo').length).toBeGreaterThan(1);
|
||||
expect(matchBooks('jn').map((b) => b.abbrev)).toEqual(['JHN']);
|
||||
});
|
||||
|
||||
test('rejects chapters a book does not have, and things that are not passages', () => {
|
||||
expect(parsePassageRef('jude 2')).toEqual([]); // Jude has one chapter
|
||||
expect(parsePassageRef('genesis 51')).toEqual([]);
|
||||
expect(parsePassageRef('')).toEqual([]);
|
||||
expect(parsePassageRef('3:16')).toEqual([]);
|
||||
expect(parsePassageRef('zzz 4')).toEqual([]);
|
||||
});
|
||||
|
||||
test('formats a place the way people write it', () => {
|
||||
expect(formatPassage(first('john 3:16'))).toBe('John 3:16');
|
||||
expect(formatPassage(first('psalm 23'))).toBe('Psalms 23');
|
||||
expect(formatPassage(first('romans'))).toBe('Romans');
|
||||
});
|
||||
Reference in new issue
Block a user