Extract project header, share link, exports, and auth status

- ProjectHeader component replaces the headerButtons JSX in context; it
  owns the export menu and share panel state.
- useShareLink (share status/enable/revoke/copy) and useSharedView
  (?share= read-only view, now used directly by the router).
- utils/projectExport: HTML/Markdown/DOCX download and print-to-PDF.
- AuthStatus component replaces the authStatus JSX in context.
- Pages import wordStudy helpers directly instead of via context.
- Remove dead copyPronunciationGuide (PronunciationPage has its own).
- Tests: Markdown export, enabling a share link, the ?share= view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Opus 5.5 committed 2026-09-22 14:56:31 -04:00
1 parent 365fb1b567
commit 4b14b3fbe6
14 files changed
+425 -393

No files matched your search

+3 -2
View File
@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import { useApp } from '../context/AppContext.js';
import AuthStatus from '../components/AuthStatus.jsx';
import { buildExportHtml } from '../utils/bibleUtils.jsx';
import {
adminListUsers,
@@ -11,7 +12,7 @@ import {
} from '../syncService.js';
export default function AdminPage() {
const { authUser, authStatus, goHome } = useApp();
const { authUser, goHome } = useApp();
const [adminTab, setAdminTab] = useState('users'); // 'users' | 'projects'
const [adminUsers, setAdminUsers] = useState([]);
const [adminProjects, setAdminProjects] = useState([]);
@@ -82,7 +83,7 @@ export default function AdminPage() {
>
← Back
</button>
{authStatus}
<AuthStatus />
</div>
</div>
</header>
+2 -2
View File
@@ -1,5 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { useApp } from '../context/AppContext.js';
import AuthStatus from '../components/AuthStatus.jsx';
import {
bookOptions,
CHAPTER_COUNTS,
@@ -11,7 +12,6 @@ import { loadProjectById } from '../utils/projectStorage.js';
export default function HomePage() {
const {
authStatus,
autoRestoredCount,
staleLocalProjects,
projectIndex,
@@ -109,7 +109,7 @@ export default function HomePage() {
>
+ New Project
</button>
{authStatus}
<AuthStatus />
</div>
</div>
</header>
+3 -2
View File
@@ -1,11 +1,12 @@
import { useState } from 'react';
import { useApp } from '../context/AppContext.js';
import AuthStatus from '../components/AuthStatus.jsx';
import { useAvailableTranslations } from '../hooks/useAvailableTranslations.js';
import { bookOptions, makeId, parseBibleChapter } from '../utils/bibleUtils.jsx';
import { parseEpisodeListDocx, parseEpisodePassage } from '../utils/importParsers.js';
export default function ImportPage() {
const { authStatus, setCurrentPage, setProject, setActiveChapterIndex } = useApp();
const { setCurrentPage, setProject, setActiveChapterIndex } = useApp();
const availableTranslations = useAvailableTranslations();
const [importBookAbbrev, setImportBookAbbrev] = useState(bookOptions[0].abbrev);
const [importTranslation, setImportTranslation] = useState('BSB');
@@ -165,7 +166,7 @@ export default function ImportPage() {
>
← Back
</button>
{authStatus}
<AuthStatus />
</div>
</div>
</header>
+3 -4
View File
@@ -1,5 +1,7 @@
import { useState, useEffect, useRef, useMemo, useDeferredValue } from 'react';
import { useApp } from '../context/AppContext.js';
import { formatCrossRef, speakOriginalWord } from '../utils/wordStudy.js';
import AuthStatus from '../components/AuthStatus.jsx';
import { bookOptions, BookmarkIcon, CopyIcon } from '../utils/bibleUtils.jsx';
import DrawCanvas from './DrawCanvas.jsx';
@@ -7,7 +9,6 @@ const NO_STROKES = []; // stable fallback so DrawCanvas doesn't redraw every ren
export default function ReaderPage() {
const {
authStatus,
goHome,
readerBookAbbrev,
readerChapter, setReaderChapter,
@@ -41,9 +42,7 @@ export default function ReaderPage() {
handlePlayReaderAudio,
handleToggleReaderAudioPause,
handleStopBookAudio,
speakOriginalWord,
copyVerse,
formatCrossRef,
setReaderCrossRefs,
readerInkByPage,
updateReaderPageInk,
@@ -270,7 +269,7 @@ export default function ReaderPage() {
>
← Back to Studies
</button>
{authStatus}
<AuthStatus />
</div>
</div>
</header>
+2 -2
View File
@@ -1,5 +1,6 @@
import { useState } from 'react';
import { useApp } from '../context/AppContext.js';
import AuthStatus from '../components/AuthStatus.jsx';
import {
startMfaSetup,
confirmMfaSetup,
@@ -11,7 +12,6 @@ import {
export default function SettingsPage() {
const {
authUser, setAuthUser,
authStatus,
goHome,
} = useApp();
const [mfaSetup, setMfaSetup] = useState(null); // { secret, qrCodeDataUrl } while setup is in progress
@@ -123,7 +123,7 @@ export default function SettingsPage() {
>
← Back
</button>
{authStatus}
<AuthStatus />
</div>
</div>
</header>
+2 -2
View File
@@ -1,4 +1,5 @@
import { useApp } from '../context/AppContext.js';
import ProjectHeader from '../components/ProjectHeader.jsx';
import { useAvailableTranslations } from '../hooks/useAvailableTranslations.js';
import { bookOptions, formatChunkReference } from '../utils/bibleUtils.jsx';
@@ -81,7 +82,6 @@ function SetupForm({ setup, availableTranslations, titleEdited, loadingChapter,
export default function SetupPage() {
const {
headerButtons,
project,
setup,
titleEdited, setTitleEdited,
@@ -125,7 +125,7 @@ export default function SetupPage() {
{project ? project.title : 'New Study'}
</h1>
</div>
{headerButtons}
<ProjectHeader loading={loadingChapter} />
</div>
</header>
+3 -5
View File
@@ -1,11 +1,12 @@
import { createPortal } from 'react-dom';
import DOMPurify from 'dompurify';
import { useApp } from '../context/AppContext.js';
import { buildGreekDefinitionHtml, externalLookupLinks, speakOriginalWord } from '../utils/wordStudy.js';
import ProjectHeader from '../components/ProjectHeader.jsx';
import { STUDY_TABS, COMMENTARY_OPTIONS, NT_BOOK_NUMBER, formatChunkReference, CrossRefChip } from '../utils/bibleUtils.jsx';
export default function StudyPage() {
const {
headerButtons,
project,
allChunks,
selectedChunk,
@@ -50,9 +51,6 @@ export default function StudyPage() {
suggestGreekWordsForChunk,
suggestHebrewWordsForChunk,
confirmSuggestWords,
speakOriginalWord,
externalLookupLinks,
buildGreekDefinitionHtml,
loadVerseText,
importFinalScriptDocx,
formatChunkReference: _ignored,
@@ -71,7 +69,7 @@ export default function StudyPage() {
</p>
)}
</div>
{headerButtons}
<ProjectHeader />
</div>
</header>