Add study templates, exports, breadcrumb, whole-Bible search, bookmarks UX, and share links

- Study templates: richer multi-line guiding questions in the OIA placeholders
- PDF/print export: reuses buildExportHtml in a new tab + window.print()
- Markdown export: new buildMarkdownExport() with matching tests
- Breadcrumb: current chunk's passage reference shown in the Study page header
- Reader bookmarks: SVG icons instead of ambiguous emoji, always visible
  (not hover-only, so it works on touch devices), plus a Bookmarks panel
  that lists all saved verses across every book and jumps + scrolls to them
- Whole-Bible search: no server-side search endpoint exists, so this fetches
  the full translation once (~7MB) and searches an in-memory flat verse
  index client-side, with results linking back into the reader
- Read-only share links: per-project share token, a public unauthenticated
  /api/share/:token endpoint, and a ?share=TOKEN view that bypasses the auth
  gate entirely and renders the export HTML in a script-sandboxed iframe

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5 committed 2026-07-06 10:12:00 -04:00
1 parent 2735ef216c
commit 37cfcd55a0
6 files changed
+632 -36

No files matched your search

+24
View File
@@ -65,6 +65,30 @@ export async function deleteRemoteProject(id) {
return request('DELETE', `/projects/${id}`);
}
// ---------------------------------------------------------------------------
// Read-only share links
// ---------------------------------------------------------------------------
/** Returns { shareToken } — the project's current share token, or null if sharing is off. */
export async function getShareStatus(id) {
return request('GET', `/projects/${id}/share`);
}
/** Enables sharing (or returns the existing token if already enabled). Returns { shareToken }. */
export async function enableSharing(id) {
return request('POST', `/projects/${id}/share`);
}
/** Revokes a project's share link. */
export async function disableSharing(id) {
return request('DELETE', `/projects/${id}/share`);
}
/** Public lookup — no session required. Returns the full project for a valid share token. */
export async function getSharedProject(token) {
return request('GET', `/share/${token}`);
}
/**
* Check whether the server is reachable.
* Returns true / false.