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

+30
View File
@@ -0,0 +1,30 @@
// Export → Slides: a printable slide deck for a session or the whole study (Save as PDF in the print dialog).
import { useState } from 'react';
import { sessionsFor } from '../utils/handout.js';
import { printSlides } from '../utils/slides.js';
export default function SlidesExport({ project }) {
const sessions = sessionsFor(project);
const [which, setWhich] = useState('all');
const [dark, setDark] = useState(false);
const [blocked, setBlocked] = useState(false);
if (sessions.length === 0) return null;
const go = () => setBlocked(!printSlides(project, which === 'all' ? null : [which], { dark }));
return (
<section className="rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] p-5" aria-label="Slides">
<h2 className="text-sm font-medium">Slides</h2>
<p className="mb-3 mt-1 text-xs text-[var(--r-sub)]">A 16:9 slide for each session’s passage, each outline point (with the verse it quotes) and the discussion questions. Choose “Save as PDF” in the print dialog, then open it in any slide viewer or project it from the PDF. It isn’t a PowerPoint file.</p>
<div className="flex flex-wrap items-end gap-3">
<label className="text-xs text-[var(--r-sub)]">Sessions
<select value={which} onChange={(e) => setWhich(e.target.value)} className="mt-1 block rounded-lg border border-[var(--r-line)] bg-[var(--r-bg)] px-2.5 py-1.5 text-sm text-[var(--r-text)]">
<option value="all">All {sessions.length}</option>
{sessions.map((s) => <option key={s.chunk.id} value={s.chunk.id}>{s.number}. {s.reference}</option>)}
</select>
</label>
<label className="flex items-center gap-2 pb-2 text-xs text-[var(--r-sub)]"><input type="checkbox" checked={dark} onChange={(e) => setDark(e.target.checked)} className="accent-[var(--r-accent)]" /> Dark slides</label>
<button type="button" onClick={go} className="rounded-xl border border-[var(--r-line)] px-4 py-2 text-sm hover:bg-black/5">Print / Save PDF</button>
</div>
{blocked && <p role="alert" className="mt-2 text-xs text-[var(--r-danger,#b42318)]">Allow pop-ups for this site to print the slides.</p>}
</section>
);
}