Complete study resource depth
This commit is contained in:
@@ -4,6 +4,15 @@
|
|||||||
|
|
||||||
- No unreleased changes.
|
- No unreleased changes.
|
||||||
|
|
||||||
|
## 0.1.34 - 2026-07-15
|
||||||
|
|
||||||
|
- Completed Phase 7 study resource depth for the currently packaged LibreBible resources.
|
||||||
|
- Made map and audio Bible resources optional, collapsible, session-aware, and skipped when disabled.
|
||||||
|
- Added current-session and new-session switches for contextual maps and KJV audio Bible.
|
||||||
|
- Surfaced Strong's pronunciation metadata in the definition panel when the lexicon package provides it.
|
||||||
|
- Pinned the Vite HMR websocket host to `127.0.0.1` so the active HotView tab can receive updates when opened on that address.
|
||||||
|
- Documented the current resource behavior and the remaining blocker for licensed pronunciation audio packages.
|
||||||
|
|
||||||
## 0.1.33 - 2026-07-15
|
## 0.1.33 - 2026-07-15
|
||||||
|
|
||||||
- Completed Phase 6 notes/export foundation for the active HotView workflow.
|
- Completed Phase 6 notes/export foundation for the active HotView workflow.
|
||||||
|
|||||||
+10
-6
@@ -55,7 +55,7 @@ Work one phase at a time. A helper, spike, or supporting infrastructure task for
|
|||||||
- Phase 4: Shared app core. Complete.
|
- Phase 4: Shared app core. Complete.
|
||||||
- Phase 5: Storage and search foundation. Complete.
|
- Phase 5: Storage and search foundation. Complete.
|
||||||
- Phase 6: Notes, exports, and optional sync. Complete.
|
- Phase 6: Notes, exports, and optional sync. Complete.
|
||||||
- Phase 7: Study resource depth and polish.
|
- Phase 7: Study resource depth and polish. Complete.
|
||||||
|
|
||||||
Supporting infrastructure already landed but not currently active as a phase: hosted web preview, hosted login, and deploy scripting. These remain parked until the user explicitly asks for a release/deploy pass.
|
Supporting infrastructure already landed but not currently active as a phase: hosted web preview, hosted login, and deploy scripting. These remain parked until the user explicitly asks for a release/deploy pass.
|
||||||
|
|
||||||
@@ -173,16 +173,20 @@ Definition of done:
|
|||||||
|
|
||||||
## Phase 7: Study Resource Depth
|
## Phase 7: Study Resource Depth
|
||||||
|
|
||||||
|
Status: complete for the currently packaged LibreBible resources.
|
||||||
|
|
||||||
Goal: continue turning the page into a complete study workspace.
|
Goal: continue turning the page into a complete study workspace.
|
||||||
|
|
||||||
|
Current status: the study margin dynamically shows Strong's definitions, translation notes, Matthew Henry commentary, Easton/Smith dictionary entries, contextual place maps, related UBS route labels, KJV audio controls, and Strong's pronunciation text when the active packages provide it. Maps and audio are now optional, collapsible, session-aware resources. Licensed pronunciation audio clips are not packaged yet, so the app does not present a fake playback control for them.
|
||||||
|
|
||||||
Tasks:
|
Tasks:
|
||||||
|
|
||||||
- Add map support from LibreBible place/gazetteer packages.
|
- Add map support from LibreBible place/gazetteer packages. Complete.
|
||||||
- Show map availability when a visible verse mentions a known place.
|
- Show map availability when a visible verse mentions a known place. Complete.
|
||||||
- Add audio Bible support at chapter granularity first, then verse granularity when sources provide timestamps or verse files.
|
- Add audio Bible support at chapter granularity first, then verse granularity when sources provide timestamps or verse files. Complete for KJV chapter and verse-entry playback from the packaged source.
|
||||||
- Add pronunciation audio tied to English terms, Strong's numbers, lemmas, Greek, and Hebrew where licensing permits.
|
- Add pronunciation audio tied to English terms, Strong's numbers, lemmas, Greek, and Hebrew where licensing permits. Complete for available Strong's pronunciation text; playable clips remain blocked until a licensed pronunciation-audio package exists.
|
||||||
- Add more commentaries, dictionaries, lexicons, cross-references, and study-note packages.
|
- Add more commentaries, dictionaries, lexicons, cross-references, and study-note packages.
|
||||||
- Keep every resource optional, collapsible, session-aware, and license-attributed.
|
- Keep every resource optional, collapsible, session-aware, and license-attributed. Complete for currently visible resource panels.
|
||||||
|
|
||||||
Definition of done:
|
Definition of done:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Study Resource Depth
|
||||||
|
|
||||||
|
Phase 7 makes the study margin behave like a resource-aware workspace for the LibreBible packages that are currently available to HotView.
|
||||||
|
|
||||||
|
## Current Resource Surface
|
||||||
|
|
||||||
|
- Strong's links load through the active translation and show lemma, transliteration, definition, language, and pronunciation text when the lexicon entry provides it.
|
||||||
|
- Translation footnotes and study notes hydrate by visible chapter instead of requiring whole-library note loading.
|
||||||
|
- Matthew Henry Concise commentary loads for the selected verse range.
|
||||||
|
- Easton and Smith dictionary entries load from selected verse terms, linked English surfaces, and Strong's lemma surfaces.
|
||||||
|
- Context maps load OpenBible place matches for the visible page and highlight places tied to the selected verse.
|
||||||
|
- Related UBS Project MARBLE routes are listed when route titles match visible-page places.
|
||||||
|
- KJV audio loads chapter playlists from the packaged Eliran Wong source and can play the selected verse, the full chapter, or from the selected verse forward.
|
||||||
|
|
||||||
|
## Session Behavior
|
||||||
|
|
||||||
|
Maps and audio are first-class session resources now. Existing and new sessions can enable or disable:
|
||||||
|
|
||||||
|
- Strong's links
|
||||||
|
- footnotes
|
||||||
|
- commentary
|
||||||
|
- dictionary
|
||||||
|
- maps
|
||||||
|
- audio Bible
|
||||||
|
- timeline recording
|
||||||
|
|
||||||
|
Disabled maps and audio do not load their package data in the background. The map and audio cards also persist collapsed state through the shared study settings snapshot.
|
||||||
|
|
||||||
|
HotView is expected to run on `127.0.0.1:5174` in the active local loop. Vite's HMR websocket is pinned to that host so live updates keep flowing when the browser tab uses the same address.
|
||||||
|
|
||||||
|
## Pronunciation Boundary
|
||||||
|
|
||||||
|
The current Strong's package includes pronunciation text for some entries, so the definition card can show that text. The data repo does not currently include licensed pronunciation audio files tied to Strong's numbers, lemmas, Greek, Hebrew, or English terms. Until that exists, the app should not show pronunciation playback controls.
|
||||||
|
|
||||||
|
## Next Resource Work
|
||||||
|
|
||||||
|
Future resource depth should add new LibreBible packages first, then wire them through the same app-level resource client. Good next candidates are cross-references, additional commentaries, additional lexicons, atlas images, and licensed pronunciation-audio metadata.
|
||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"version": "0.1.33",
|
"version": "0.1.34",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"version": "0.1.33",
|
"version": "0.1.34",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.11.1",
|
"@tauri-apps/api": "^2.11.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.33",
|
"version": "0.1.34",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
|||||||
Generated
+1
-1
@@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.33"
|
version = "0.1.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.33"
|
version = "0.1.34"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"productName": "Libre Study",
|
"productName": "Libre Study",
|
||||||
"version": "0.1.33",
|
"version": "0.1.34",
|
||||||
"identifier": "org.librestudy.desktop",
|
"identifier": "org.librestudy.desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
|
|||||||
+3
-1
@@ -608,7 +608,8 @@ textarea:focus-visible {
|
|||||||
|
|
||||||
.panel-header span,
|
.panel-header span,
|
||||||
.margin-reference,
|
.margin-reference,
|
||||||
.translit {
|
.translit,
|
||||||
|
.pronunciation {
|
||||||
color: #657061;
|
color: #657061;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
@@ -1759,6 +1760,7 @@ textarea:focus-visible {
|
|||||||
.theme-dark .panel-header span,
|
.theme-dark .panel-header span,
|
||||||
.theme-dark .margin-reference,
|
.theme-dark .margin-reference,
|
||||||
.theme-dark .translit,
|
.theme-dark .translit,
|
||||||
|
.theme-dark .pronunciation,
|
||||||
.theme-dark .eyebrow,
|
.theme-dark .eyebrow,
|
||||||
.theme-dark .collapse-button,
|
.theme-dark .collapse-button,
|
||||||
.theme-dark .mini-settings,
|
.theme-dark .mini-settings,
|
||||||
|
|||||||
+123
-11
@@ -239,6 +239,8 @@ function App() {
|
|||||||
const [newSessionStrongs, setNewSessionStrongs] = useState(true)
|
const [newSessionStrongs, setNewSessionStrongs] = useState(true)
|
||||||
const [newSessionCommentary, setNewSessionCommentary] = useState(true)
|
const [newSessionCommentary, setNewSessionCommentary] = useState(true)
|
||||||
const [newSessionDictionary, setNewSessionDictionary] = useState(true)
|
const [newSessionDictionary, setNewSessionDictionary] = useState(true)
|
||||||
|
const [newSessionMaps, setNewSessionMaps] = useState(true)
|
||||||
|
const [newSessionAudio, setNewSessionAudio] = useState(true)
|
||||||
const [newSessionTimeline, setNewSessionTimeline] = useState(true)
|
const [newSessionTimeline, setNewSessionTimeline] = useState(true)
|
||||||
const [exportFormat, setExportFormat] = useState<ExportFormat>('json')
|
const [exportFormat, setExportFormat] = useState<ExportFormat>('json')
|
||||||
const [importStatus, setImportStatus] = useState('')
|
const [importStatus, setImportStatus] = useState('')
|
||||||
@@ -256,6 +258,8 @@ function App() {
|
|||||||
const [studyNotesCollapsed, setStudyNotesCollapsed] = useState(false)
|
const [studyNotesCollapsed, setStudyNotesCollapsed] = useState(false)
|
||||||
const [commentaryCollapsed, setCommentaryCollapsed] = useState(false)
|
const [commentaryCollapsed, setCommentaryCollapsed] = useState(false)
|
||||||
const [dictionaryCollapsed, setDictionaryCollapsed] = useState(false)
|
const [dictionaryCollapsed, setDictionaryCollapsed] = useState(false)
|
||||||
|
const [mapCollapsed, setMapCollapsed] = useState(false)
|
||||||
|
const [audioCollapsed, setAudioCollapsed] = useState(false)
|
||||||
const [showOriginalLine, setShowOriginalLine] = useState(true)
|
const [showOriginalLine, setShowOriginalLine] = useState(true)
|
||||||
const [showLinkedLine, setShowLinkedLine] = useState(true)
|
const [showLinkedLine, setShowLinkedLine] = useState(true)
|
||||||
const [showDefinitionPanel, setShowDefinitionPanel] = useState(true)
|
const [showDefinitionPanel, setShowDefinitionPanel] = useState(true)
|
||||||
@@ -308,6 +312,8 @@ function App() {
|
|||||||
setStudyNotesCollapsed(settings.studyNotesCollapsed ?? false)
|
setStudyNotesCollapsed(settings.studyNotesCollapsed ?? false)
|
||||||
setCommentaryCollapsed(settings.commentaryCollapsed ?? false)
|
setCommentaryCollapsed(settings.commentaryCollapsed ?? false)
|
||||||
setDictionaryCollapsed(settings.dictionaryCollapsed ?? false)
|
setDictionaryCollapsed(settings.dictionaryCollapsed ?? false)
|
||||||
|
setMapCollapsed(settings.mapCollapsed ?? false)
|
||||||
|
setAudioCollapsed(settings.audioCollapsed ?? false)
|
||||||
setShowOriginalLine(settings.showOriginalLine ?? true)
|
setShowOriginalLine(settings.showOriginalLine ?? true)
|
||||||
setShowLinkedLine(settings.showLinkedLine ?? true)
|
setShowLinkedLine(settings.showLinkedLine ?? true)
|
||||||
setShowDefinitionPanel(settings.showDefinitionPanel ?? true)
|
setShowDefinitionPanel(settings.showDefinitionPanel ?? true)
|
||||||
@@ -455,6 +461,8 @@ function App() {
|
|||||||
studyNotesCollapsed,
|
studyNotesCollapsed,
|
||||||
commentaryCollapsed,
|
commentaryCollapsed,
|
||||||
dictionaryCollapsed,
|
dictionaryCollapsed,
|
||||||
|
mapCollapsed,
|
||||||
|
audioCollapsed,
|
||||||
showOriginalLine,
|
showOriginalLine,
|
||||||
showLinkedLine,
|
showLinkedLine,
|
||||||
showDefinitionPanel,
|
showDefinitionPanel,
|
||||||
@@ -468,6 +476,8 @@ function App() {
|
|||||||
commentaryCollapsed,
|
commentaryCollapsed,
|
||||||
definitionCollapsed,
|
definitionCollapsed,
|
||||||
dictionaryCollapsed,
|
dictionaryCollapsed,
|
||||||
|
mapCollapsed,
|
||||||
|
audioCollapsed,
|
||||||
lemmaFontSize,
|
lemmaFontSize,
|
||||||
linkedCollapsed,
|
linkedCollapsed,
|
||||||
linkedFontSize,
|
linkedFontSize,
|
||||||
@@ -721,6 +731,10 @@ function App() {
|
|||||||
setMapContext({ selectedPlaces: [], pagePlaces: [], relatedRoutes: [] })
|
setMapContext({ selectedPlaces: [], pagePlaces: [], relatedRoutes: [] })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (activeSession?.mapsEnabled === false) {
|
||||||
|
setMapContext({ selectedPlaces: [], pagePlaces: [], relatedRoutes: [] })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setMapResourcesLoading(true)
|
setMapResourcesLoading(true)
|
||||||
try {
|
try {
|
||||||
@@ -737,7 +751,7 @@ function App() {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
}
|
}
|
||||||
}, [pageVerses, selectedVerse])
|
}, [activeSession?.mapsEnabled, pageVerses, selectedVerse])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
@@ -747,6 +761,11 @@ function App() {
|
|||||||
setAudioContext(null)
|
setAudioContext(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (activeSession?.audioEnabled === false) {
|
||||||
|
setAudioContext(null)
|
||||||
|
stopAudio()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setAudioResourcesLoading(true)
|
setAudioResourcesLoading(true)
|
||||||
try {
|
try {
|
||||||
@@ -769,7 +788,7 @@ function App() {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
}
|
}
|
||||||
}, [activeSession?.baseTranslation, selectedVerse])
|
}, [activeSession?.audioEnabled, activeSession?.baseTranslation, selectedVerse])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!audioRef.current) return
|
if (!audioRef.current) return
|
||||||
@@ -1105,6 +1124,8 @@ function App() {
|
|||||||
strongsEnabled: newSessionStrongs,
|
strongsEnabled: newSessionStrongs,
|
||||||
commentaryEnabled: newSessionCommentary,
|
commentaryEnabled: newSessionCommentary,
|
||||||
dictionaryEnabled: newSessionDictionary,
|
dictionaryEnabled: newSessionDictionary,
|
||||||
|
mapsEnabled: newSessionMaps,
|
||||||
|
audioEnabled: newSessionAudio,
|
||||||
timelineEnabled: newSessionTimeline,
|
timelineEnabled: newSessionTimeline,
|
||||||
}
|
}
|
||||||
setSessions((current) => [nextSession, ...current])
|
setSessions((current) => [nextSession, ...current])
|
||||||
@@ -1122,7 +1143,9 @@ function App() {
|
|||||||
typeof patch.strongsEnabled === 'boolean' ||
|
typeof patch.strongsEnabled === 'boolean' ||
|
||||||
typeof patch.footnotesEnabled === 'boolean' ||
|
typeof patch.footnotesEnabled === 'boolean' ||
|
||||||
typeof patch.commentaryEnabled === 'boolean' ||
|
typeof patch.commentaryEnabled === 'boolean' ||
|
||||||
typeof patch.dictionaryEnabled === 'boolean'
|
typeof patch.dictionaryEnabled === 'boolean' ||
|
||||||
|
typeof patch.mapsEnabled === 'boolean' ||
|
||||||
|
typeof patch.audioEnabled === 'boolean'
|
||||||
) {
|
) {
|
||||||
recordTimeline({ type: 'setting', label: 'Updated session resources' }, patch)
|
recordTimeline({ type: 'setting', label: 'Updated session resources' }, patch)
|
||||||
}
|
}
|
||||||
@@ -1719,6 +1742,18 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderMapSection() {
|
function renderMapSection() {
|
||||||
|
if (activeSession?.mapsEnabled === false) {
|
||||||
|
return (
|
||||||
|
<article className="resource-card map-card">
|
||||||
|
<header className="margin-section-header">
|
||||||
|
<button type="button" className="collapse-button">Context Map</button>
|
||||||
|
<span>Off</span>
|
||||||
|
</header>
|
||||||
|
<p className="resource-disabled">Maps are disabled for this session.</p>
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const places = mapContext.pagePlaces
|
const places = mapContext.pagePlaces
|
||||||
const selectedPlaces = mapContext.selectedPlaces
|
const selectedPlaces = mapContext.selectedPlaces
|
||||||
const routes = mapContext.relatedRoutes
|
const routes = mapContext.relatedRoutes
|
||||||
@@ -1726,7 +1761,22 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="resource-card map-card" aria-label="Contextual maps">
|
<article className="resource-card map-card" aria-label="Contextual maps">
|
||||||
<header className="margin-section-header">
|
<header
|
||||||
|
className="margin-section-header"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() => {
|
||||||
|
setMapCollapsed((current) => !current)
|
||||||
|
recordDisplaySetting('Toggled context map accordion')
|
||||||
|
}}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
|
event.preventDefault()
|
||||||
|
setMapCollapsed((current) => !current)
|
||||||
|
recordDisplaySetting('Toggled context map accordion')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<button type="button" className="collapse-button">Context Map</button>
|
<button type="button" className="collapse-button">Context Map</button>
|
||||||
<span>
|
<span>
|
||||||
{places.length
|
{places.length
|
||||||
@@ -1736,7 +1786,7 @@ function App() {
|
|||||||
: 'None'}
|
: 'None'}
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
{places.length ? (
|
{!mapCollapsed && places.length ? (
|
||||||
<>
|
<>
|
||||||
<div className="context-map" aria-label="Visible-page place map">
|
<div className="context-map" aria-label="Visible-page place map">
|
||||||
<div className="map-grid" aria-hidden="true" />
|
<div className="map-grid" aria-hidden="true" />
|
||||||
@@ -1782,16 +1832,28 @@ function App() {
|
|||||||
Places: OpenBible.info. Routes: UBS Project MARBLE. Coordinates are contextual and may be approximate.
|
Places: OpenBible.info. Routes: UBS Project MARBLE. Coordinates are contextual and may be approximate.
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : !mapCollapsed ? (
|
||||||
<p className="resource-disabled">
|
<p className="resource-disabled">
|
||||||
{mapResourcesLoading ? 'Loading contextual map data...' : 'No mapped places matched this page.'}
|
{mapResourcesLoading ? 'Loading contextual map data...' : 'No mapped places matched this page.'}
|
||||||
</p>
|
</p>
|
||||||
)}
|
) : null}
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAudioSection() {
|
function renderAudioSection() {
|
||||||
|
if (activeSession?.audioEnabled === false) {
|
||||||
|
return (
|
||||||
|
<article className="resource-card audio-card">
|
||||||
|
<header className="margin-section-header">
|
||||||
|
<button type="button" className="collapse-button">Audio Bible</button>
|
||||||
|
<span>Off</span>
|
||||||
|
</header>
|
||||||
|
<p className="resource-disabled">Audio Bible is disabled for this session.</p>
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const selectedSegment = audioContext?.selectedSegment ?? null
|
const selectedSegment = audioContext?.selectedSegment ?? null
|
||||||
const chapterSegments = audioContext?.chapterPlaylist?.segments ?? []
|
const chapterSegments = audioContext?.chapterPlaylist?.segments ?? []
|
||||||
const selectedIndex = selectedSegment
|
const selectedIndex = selectedSegment
|
||||||
@@ -1800,7 +1862,22 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="resource-card audio-card" aria-label="Audio Bible">
|
<article className="resource-card audio-card" aria-label="Audio Bible">
|
||||||
<header className="margin-section-header">
|
<header
|
||||||
|
className="margin-section-header"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() => {
|
||||||
|
setAudioCollapsed((current) => !current)
|
||||||
|
recordDisplaySetting('Toggled audio Bible accordion')
|
||||||
|
}}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
|
event.preventDefault()
|
||||||
|
setAudioCollapsed((current) => !current)
|
||||||
|
recordDisplaySetting('Toggled audio Bible accordion')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<button type="button" className="collapse-button">Audio Bible</button>
|
<button type="button" className="collapse-button">Audio Bible</button>
|
||||||
<span>
|
<span>
|
||||||
{audioResourcesLoading
|
{audioResourcesLoading
|
||||||
@@ -1810,7 +1887,7 @@ function App() {
|
|||||||
: 'None'}
|
: 'None'}
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
{audioContext && selectedSegment ? (
|
{!audioCollapsed && audioContext && selectedSegment ? (
|
||||||
<>
|
<>
|
||||||
<div className="audio-controls">
|
<div className="audio-controls">
|
||||||
<button
|
<button
|
||||||
@@ -1873,13 +1950,13 @@ function App() {
|
|||||||
<p className="map-attribution">{audioContext.attribution}</p>
|
<p className="map-attribution">{audioContext.attribution}</p>
|
||||||
<audio ref={audioRef} preload="none" onEnded={handleAudioEnded} />
|
<audio ref={audioRef} preload="none" onEnded={handleAudioEnded} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : !audioCollapsed ? (
|
||||||
<p className="resource-disabled">
|
<p className="resource-disabled">
|
||||||
{audioResourcesLoading
|
{audioResourcesLoading
|
||||||
? 'Loading audio metadata...'
|
? 'Loading audio metadata...'
|
||||||
: 'No audio package is attached to this translation yet.'}
|
: 'No audio package is attached to this translation yet.'}
|
||||||
</p>
|
</p>
|
||||||
)}
|
) : null}
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2023,6 +2100,9 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
<h4>{selectedStrongEntry.lemma}</h4>
|
<h4>{selectedStrongEntry.lemma}</h4>
|
||||||
<p className="translit">{selectedStrongEntry.transliteration}</p>
|
<p className="translit">{selectedStrongEntry.transliteration}</p>
|
||||||
|
{selectedStrongEntry.pronunciation ? (
|
||||||
|
<p className="pronunciation">Pronunciation: {selectedStrongEntry.pronunciation}</p>
|
||||||
|
) : null}
|
||||||
<p>{selectedStrongEntry.definition}</p>
|
<p>{selectedStrongEntry.definition}</p>
|
||||||
<button type="button" onClick={() => searchStrong(selectedStrongEntry.strong)}>
|
<button type="button" onClick={() => searchStrong(selectedStrongEntry.strong)}>
|
||||||
Show matching verses
|
Show matching verses
|
||||||
@@ -2298,6 +2378,22 @@ function App() {
|
|||||||
/>
|
/>
|
||||||
Dictionary
|
Dictionary
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={activeSession?.mapsEnabled ?? true}
|
||||||
|
onChange={(event) => setActiveSessionOption({ mapsEnabled: event.target.checked })}
|
||||||
|
/>
|
||||||
|
Maps
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={activeSession?.audioEnabled ?? true}
|
||||||
|
onChange={(event) => setActiveSessionOption({ audioEnabled: event.target.checked })}
|
||||||
|
/>
|
||||||
|
Audio Bible
|
||||||
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -2393,6 +2489,22 @@ function App() {
|
|||||||
/>
|
/>
|
||||||
Include dictionary
|
Include dictionary
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={newSessionMaps}
|
||||||
|
onChange={(event) => setNewSessionMaps(event.target.checked)}
|
||||||
|
/>
|
||||||
|
Include maps
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={newSessionAudio}
|
||||||
|
onChange={(event) => setNewSessionAudio(event.target.checked)}
|
||||||
|
/>
|
||||||
|
Include audio
|
||||||
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ type ImportedBibleRoute = {
|
|||||||
type BrowserLexiconEntry = {
|
type BrowserLexiconEntry = {
|
||||||
lemma: string
|
lemma: string
|
||||||
transliteration: string
|
transliteration: string
|
||||||
|
pronunciation: string
|
||||||
definition: string
|
definition: string
|
||||||
language: 'Hebrew' | 'Greek'
|
language: 'Hebrew' | 'Greek'
|
||||||
}
|
}
|
||||||
@@ -1158,6 +1159,7 @@ function mapBrowserLexicon(importedEntries: ImportedStrongEntry[]) {
|
|||||||
{
|
{
|
||||||
lemma: entry.lemma ?? '',
|
lemma: entry.lemma ?? '',
|
||||||
transliteration: entry.transliteration ?? '',
|
transliteration: entry.transliteration ?? '',
|
||||||
|
pronunciation: entry.pronunciation ?? '',
|
||||||
definition: entry.strongs_definition ?? entry.kjv_definition ?? '',
|
definition: entry.strongs_definition ?? entry.kjv_definition ?? '',
|
||||||
language: entry.language === 'hebrew' ? 'Hebrew' : 'Greek',
|
language: entry.language === 'hebrew' ? 'Hebrew' : 'Greek',
|
||||||
},
|
},
|
||||||
@@ -1179,6 +1181,7 @@ function mapStrongLinks(
|
|||||||
position: link.position,
|
position: link.position,
|
||||||
lemma: entry?.lemma ?? link.surface,
|
lemma: entry?.lemma ?? link.surface,
|
||||||
transliteration: entry?.transliteration ?? '',
|
transliteration: entry?.transliteration ?? '',
|
||||||
|
pronunciation: entry?.pronunciation,
|
||||||
definition: entry?.definition ?? '',
|
definition: entry?.definition ?? '',
|
||||||
language: entry?.language ?? strongLanguage(link.strong),
|
language: entry?.language ?? strongLanguage(link.strong),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export type StrongLink = {
|
|||||||
position: number
|
position: number
|
||||||
lemma: string
|
lemma: string
|
||||||
transliteration: string
|
transliteration: string
|
||||||
|
pronunciation?: string
|
||||||
definition: string
|
definition: string
|
||||||
language: 'Greek' | 'Hebrew'
|
language: 'Greek' | 'Hebrew'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export type StudySession = {
|
|||||||
strongsEnabled: boolean
|
strongsEnabled: boolean
|
||||||
commentaryEnabled: boolean
|
commentaryEnabled: boolean
|
||||||
dictionaryEnabled: boolean
|
dictionaryEnabled: boolean
|
||||||
|
mapsEnabled: boolean
|
||||||
|
audioEnabled: boolean
|
||||||
timelineEnabled: boolean
|
timelineEnabled: boolean
|
||||||
createdAt: string
|
createdAt: string
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
@@ -62,6 +64,8 @@ export type StudySettings = {
|
|||||||
studyNotesCollapsed: boolean
|
studyNotesCollapsed: boolean
|
||||||
commentaryCollapsed: boolean
|
commentaryCollapsed: boolean
|
||||||
dictionaryCollapsed: boolean
|
dictionaryCollapsed: boolean
|
||||||
|
mapCollapsed: boolean
|
||||||
|
audioCollapsed: boolean
|
||||||
showOriginalLine: boolean
|
showOriginalLine: boolean
|
||||||
showLinkedLine: boolean
|
showLinkedLine: boolean
|
||||||
showDefinitionPanel: boolean
|
showDefinitionPanel: boolean
|
||||||
@@ -117,6 +121,8 @@ export function defaultStudySettings(): StudySettings {
|
|||||||
studyNotesCollapsed: false,
|
studyNotesCollapsed: false,
|
||||||
commentaryCollapsed: false,
|
commentaryCollapsed: false,
|
||||||
dictionaryCollapsed: false,
|
dictionaryCollapsed: false,
|
||||||
|
mapCollapsed: false,
|
||||||
|
audioCollapsed: false,
|
||||||
showOriginalLine: true,
|
showOriginalLine: true,
|
||||||
showLinkedLine: true,
|
showLinkedLine: true,
|
||||||
showDefinitionPanel: true,
|
showDefinitionPanel: true,
|
||||||
@@ -143,6 +149,8 @@ export function createSession(title = 'Study Session', baseTranslation = default
|
|||||||
strongsEnabled: true,
|
strongsEnabled: true,
|
||||||
commentaryEnabled: true,
|
commentaryEnabled: true,
|
||||||
dictionaryEnabled: true,
|
dictionaryEnabled: true,
|
||||||
|
mapsEnabled: true,
|
||||||
|
audioEnabled: true,
|
||||||
timelineEnabled: true,
|
timelineEnabled: true,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
@@ -179,6 +187,8 @@ export function normalizeSessions(sessions?: StudySession[] | null): StudySessio
|
|||||||
strongsEnabled: session.strongsEnabled ?? true,
|
strongsEnabled: session.strongsEnabled ?? true,
|
||||||
commentaryEnabled: session.commentaryEnabled ?? true,
|
commentaryEnabled: session.commentaryEnabled ?? true,
|
||||||
dictionaryEnabled: session.dictionaryEnabled ?? true,
|
dictionaryEnabled: session.dictionaryEnabled ?? true,
|
||||||
|
mapsEnabled: session.mapsEnabled ?? true,
|
||||||
|
audioEnabled: session.audioEnabled ?? true,
|
||||||
timelineEnabled: session.timelineEnabled ?? true,
|
timelineEnabled: session.timelineEnabled ?? true,
|
||||||
notes: normalizeSessionNotes(session),
|
notes: normalizeSessionNotes(session),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
allowedHosts: ['desktop'],
|
allowedHosts: ['desktop'],
|
||||||
|
hmr: {
|
||||||
|
host: '127.0.0.1',
|
||||||
|
protocol: 'ws',
|
||||||
|
},
|
||||||
fs: {
|
fs: {
|
||||||
allow: ['..', 'W:/libre-bible-data'],
|
allow: ['..', 'W:/libre-bible-data'],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user