Teaching: hide-notes-until share, session length check, slides export

- A study share link can hide the owner's notes until a chosen time: the server
  sends only passages and discussion questions until then, with a banner in the
  shared view (new share_reveal column, migrated on start).
- Outline: a session length with "N of M min planned, X min over" and a marker
  on the point where the plan runs past it.
- Export > Slides: printable 16:9 slides (title, passage, outline points with
  their verse, discussion questions) for one session or all; light or dark.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-14 13:08:21 -04:00
1 parent 67645cf1df
commit 2c7c7145c4
14 files changed
+303 -33

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
import { test, expect } from 'vitest';
import { buildSlides, buildSlidesHtml } from './slides.js';
const project = () => ({
id: 'p', title: 'John <study>', translation: 'BSB', outline: [],
chapters: [{ book: 'John', bookAbbrev: 'JHN', chapter: '3', verses: [{ number: 16, text: 'For God so loved the world.' }, { number: 17, text: 'God sent not his Son to condemn.' }], chunks: [
{ id: 'a', startVerse: 16, endVerse: 17, episodeTitle: 'God so loved', discussionQuestions: 'Why did he give?\nWho is "the world"?',
outline: [{ id: 'n1', text: 'Love gives', children: [{ id: 'n2', text: 'He gave', scripture: { text: 'For God so loved', ref: 'John 3:16' }, children: [] }] }] },
{ id: 'b', startVerse: 17, endVerse: 17, application: 'Trust him.', outline: [] },
] }],
});
test('slides run title, then per session: section, passage, points, questions', () => {
const kinds = buildSlides(project()).map((s) => s.kind);
expect(kinds).toEqual(['title', 'section', 'passage', 'point', 'point', 'questions', 'section', 'passage', 'questions']);
const slides = buildSlides(project());
expect(slides[1]).toMatchObject({ title: 'God so loved', subtitle: 'John 3:16–17' });
expect(slides[4]).toMatchObject({ depth: 1, text: 'He gave', quote: { ref: 'John 3:16' } });
expect(slides[8]).toMatchObject({ title: 'Think about it', items: ['Trust him.'] }); // Application notes stand in for questions
});
test('one session only', () => {
const kinds = buildSlides(project(), ['b']).map((s) => s.kind);
expect(kinds).toEqual(['title', 'section', 'passage', 'questions']);
});
test('the printable page has a 16:9 slide per entry, escapes text, and can be dark', () => {
const html = buildSlidesHtml(project());
expect(html.match(/class="slide/g)).toHaveLength(9);
expect(html).toContain('John &lt;study&gt;');
expect(html).toContain('size: 13.333in 7.5in');
expect(html).not.toContain('<study>');
expect(buildSlidesHtml(project(), null, { dark: true })).toContain('#16130f');
});