From 85fc566adee00397944f1a5ceb629fe324375a46 Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:27:52 -0400 Subject: [PATCH] Add Pronunciation Guide page with word cards and TTS Replace the copy-to-clipboard button with a dedicated page that shows all collected Greek/Hebrew words as cards grouped by language. Each card displays the original script large, transliteration, Strong's number, English gloss, definition, part of speech, and a Speak button. Includes a search/filter and a "Copy all" fallback for the old behavior. Move buildPronunciationGuide to bibleUtils.jsx to avoid circular imports. Co-Authored-By: Claude Sonnet 4.6 --- src/App.jsx | 25 +---- src/pages/PronunciationPage.jsx | 188 ++++++++++++++++++++++++++++++++ src/utils/bibleUtils.jsx | 19 ++++ 3 files changed, 212 insertions(+), 20 deletions(-) create mode 100644 src/pages/PronunciationPage.jsx diff --git a/src/App.jsx b/src/App.jsx index eb0f2e1..1cd5d3b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -9,6 +9,7 @@ import ReaderPage from './pages/ReaderPage.jsx'; import SettingsPage from './pages/SettingsPage.jsx'; import SetupPage from './pages/SetupPage.jsx'; import StudyPage from './pages/StudyPage.jsx'; +import PronunciationPage from './pages/PronunciationPage.jsx'; import { AlignmentType, BorderStyle, @@ -48,6 +49,7 @@ import { BookmarkIcon, CopyIcon, CrossRefChip, + buildPronunciationGuide, } from './utils/bibleUtils.jsx'; import { @@ -410,24 +412,6 @@ PASSAGE: ${chapterLabel} return header + buildChunkBodies(project); } -export function buildPronunciationGuide(project) { - const chapters = Array.isArray(project.chapters) ? project.chapters : []; - const lines = []; - chapters.forEach((ch) => { - ch.chunks.forEach((chunk) => { - (chunk.greekWords ?? []).forEach((word) => { - const gloss = word.shortDefinition || word.englishGloss || ''; - const lexeme = word.lexeme || ''; - const translit = word.transliteration || ''; - if (!lexeme && !translit) return; - const label = gloss ? `${gloss} β€” ` : ''; - lines.push(`${label}${lexeme}${translit ? ` (${translit})` : ''}`); - }); - }); - }); - if (lines.length === 0) return 'No Greek/Hebrew words collected yet.'; - return lines.join('\n'); -} export function buildPodcastPrompt(project, podcastName) { const chapters = Array.isArray(project.chapters) ? project.chapters : []; @@ -3243,9 +3227,9 @@ const deleteProject = (id) => { + + + + + {/* Search */} +
+ setSearch(e.target.value)} + className="w-full rounded-2xl border border-slate-300 bg-white px-4 py-3 text-sm text-slate-900 shadow-sm placeholder:text-slate-400 focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200" + /> +
+ + {entries.length === 0 ? ( +
+

πŸ”€

+

No words yet

+

+ Add Greek or Hebrew words in the Word Studies panel on the Study page. +

+
+ ) : filtered.length === 0 ? ( +

No words match "{search}"

+ ) : ( +
+ {greek.length > 0 && } + {hebrew.length > 0 && } +
+ )} + + + ); +} + +function WordGroup({ title, color, words, onSpeak }) { + const accent = { + sky: { badge: 'bg-sky-100 text-sky-700 border-sky-200', speak: 'bg-sky-100 text-sky-700 hover:bg-sky-200', heading: 'text-sky-800 border-sky-200 bg-sky-50' }, + emerald: { badge: 'bg-emerald-100 text-emerald-700 border-emerald-200', speak: 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200', heading: 'text-emerald-800 border-emerald-200 bg-emerald-50' }, + }[color]; + + return ( +
+

+ {title} Β· {words.length} word{words.length !== 1 ? 's' : ''} +

+
+ {words.map(({ word, chapterRef }) => ( + + ))} +
+
+ ); +} + +function WordCard({ word, chapterRef, accent, onSpeak }) { + return ( +
+ {/* Top row: lexeme + speak */} +
+
+ {word.lexeme && ( +

+ {word.lexeme} +

+ )} + {word.transliteration && ( +

+ {word.transliteration} +

+ )} +
+
+ {word.lexeme && ( + + )} + {word.strongNumber && ( + + {word.strongNumber} + + )} +
+
+ + {/* Gloss + definition */} +
+ {word.englishGloss && ( +

{word.englishGloss}

+ )} + {word.shortDefinition && word.shortDefinition !== word.englishGloss && ( +

{word.shortDefinition}

+ )} +
+ + {/* Footer: part of speech + source passage */} +
+ {word.partOfSpeech && ( + {word.partOfSpeech} + )} + {chapterRef} +
+
+ ); +} diff --git a/src/utils/bibleUtils.jsx b/src/utils/bibleUtils.jsx index 6069879..94032c2 100644 --- a/src/utils/bibleUtils.jsx +++ b/src/utils/bibleUtils.jsx @@ -540,3 +540,22 @@ export function CrossRefChip({ label, onRemove, loadVerseText }) { ); } + +export function buildPronunciationGuide(project) { + const chapters = Array.isArray(project?.chapters) ? project.chapters : []; + const lines = []; + chapters.forEach((ch) => { + ch.chunks.forEach((chunk) => { + (chunk.greekWords ?? []).forEach((word) => { + const gloss = word.shortDefinition || word.englishGloss || ''; + const lexeme = word.lexeme || ''; + const translit = word.transliteration || ''; + if (!lexeme && !translit) return; + const label = gloss ? `${gloss} β€” ` : ''; + lines.push(`${label}${lexeme}${translit ? ` (${translit})` : ''}`); + }); + }); + }); + if (lines.length === 0) return 'No Greek/Hebrew words collected yet.'; + return lines.join('\n'); +}