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,42 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { searchMarks, searchNotes, searchProjects } from './personalSearch.js';
|
||||
|
||||
const project = {
|
||||
id: 'p1', title: 'Romans study',
|
||||
chapters: [{
|
||||
book: 'Romans', bookAbbrev: 'ROM', chapter: '8', verses: [{ number: 1, text: 'a' }, { number: 2, text: 'b' }],
|
||||
chunks: [
|
||||
{ id: 'c1', startVerse: 1, endVerse: 2, observation: 'No condemnation for those in Christ.', interpretation: '', application: '', generalNotes: '', finalScript: '' },
|
||||
{ id: 'c2', startVerse: 2, endVerse: 2, observation: '', interpretation: 'The Spirit of life sets us free', application: '', generalNotes: '', finalScript: '' },
|
||||
],
|
||||
}],
|
||||
};
|
||||
|
||||
test('finds notes, one hit per chunk, saying which field matched', () => {
|
||||
const hits = searchNotes([project], 'spirit');
|
||||
expect(hits).toHaveLength(1);
|
||||
expect(hits[0]).toMatchObject({ projectId: 'p1', chunkId: 'c2', field: 'Interpretation' });
|
||||
expect(hits[0].snippet).toContain('Spirit of life');
|
||||
});
|
||||
|
||||
test('needs three letters before searching notes', () => {
|
||||
expect(searchNotes([project], 'sp')).toEqual([]);
|
||||
});
|
||||
|
||||
test('finds projects by title, passage or tag', () => {
|
||||
const index = [{ id: 'a', title: 'Romans study', chapterSummary: 'Romans 8', tags: ['grace'] }, { id: 'b', title: 'Psalms', chapterSummary: 'Psalms 23', tags: [] }];
|
||||
expect(searchProjects(index, 'rom').map((e) => e.id)).toEqual(['a']);
|
||||
expect(searchProjects(index, 'grace').map((e) => e.id)).toEqual(['a']);
|
||||
expect(searchProjects(index, 'zzz')).toEqual([]);
|
||||
});
|
||||
|
||||
test('finds highlights by their words or colour name, and bookmarks by reference', () => {
|
||||
const marks = {
|
||||
bookmarks: { 'JHN-3-16': '#fef08a' },
|
||||
highlights: [{ id: 'h1', book: 'ROM', chapter: 8, verse: 28, color: '#bbf7d0', text: 'all things work together', startOffset: 0, endOffset: 5 }],
|
||||
labels: { '#bbf7d0': 'Promise' },
|
||||
};
|
||||
expect(searchMarks(marks, 'together')[0]).toMatchObject({ kind: 'highlight', bookName: 'Romans', verse: 28 });
|
||||
expect(searchMarks(marks, 'promise')[0]).toMatchObject({ kind: 'highlight' });
|
||||
expect(searchMarks(marks, 'john 3')[0]).toMatchObject({ kind: 'bookmark', chapter: 3, verse: 16 });
|
||||
});
|
||||
Reference in new issue
Block a user