Add parallel translation stack book
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Added a Parallel study-stack book that follows the pinned verse, compares it against an alternate translation, and shows alternate translation notes with previous/next context.
|
||||||
- Made Bible book and chapter strips dynamically fit the available space with arrow paging while keeping the current book/chapter centered.
|
- Made Bible book and chapter strips dynamically fit the available space with arrow paging while keeping the current book/chapter centered.
|
||||||
- Reordered the study margin around verse notes, lemma text, linked English text, definitions, and translation notes, with a settings control for changing that order.
|
- Reordered the study margin around verse notes, lemma text, linked English text, definitions, and translation notes, with a settings control for changing that order.
|
||||||
- Moved audio controls into the study stack and enlarged/color-coded the stack book tabs.
|
- Moved audio controls into the study stack and enlarged/color-coded the stack book tabs.
|
||||||
|
|||||||
+100
-1
@@ -1120,6 +1120,90 @@ textarea:focus-visible {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parallel-controls {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(90px, 0.45fr) minmax(0, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-controls label {
|
||||||
|
display: grid;
|
||||||
|
gap: 5px;
|
||||||
|
color: #657061;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-controls output {
|
||||||
|
min-height: 31px;
|
||||||
|
padding: 7px 8px;
|
||||||
|
border: 1px solid #ded6c7;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fbf8ef;
|
||||||
|
color: #202124;
|
||||||
|
font-size: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-current-verse {
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid #ded6c7;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fbf8ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-current-verse p:last-child {
|
||||||
|
color: #202124;
|
||||||
|
font-family: Georgia, 'Times New Roman', serif;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-context,
|
||||||
|
.parallel-note-sections {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-context section,
|
||||||
|
.parallel-note-sections section {
|
||||||
|
display: grid;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #eee7d8;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: #fffdf6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-context strong,
|
||||||
|
.parallel-note-sections h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: #657061;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 900;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-context p,
|
||||||
|
.parallel-note-sections p {
|
||||||
|
margin: 0;
|
||||||
|
color: #3f443d;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-note-sections p strong {
|
||||||
|
display: block;
|
||||||
|
color: #735c0f;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallel-note-sections p span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.notes-workspace {
|
.notes-workspace {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1213,6 +1297,10 @@ textarea:focus-visible {
|
|||||||
background: #6e4f8f;
|
background: #6e4f8f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.study-stack-tabs .stack-tab-parallel {
|
||||||
|
background: #2d6f8f;
|
||||||
|
}
|
||||||
|
|
||||||
.study-stack-tabs .stack-tab-search {
|
.study-stack-tabs .stack-tab-search {
|
||||||
background: #5b6570;
|
background: #5b6570;
|
||||||
}
|
}
|
||||||
@@ -2046,6 +2134,10 @@ textarea:focus-visible {
|
|||||||
.theme-dark .english-strong-line,
|
.theme-dark .english-strong-line,
|
||||||
.theme-dark .resource-card,
|
.theme-dark .resource-card,
|
||||||
.theme-dark .margin-order-list div,
|
.theme-dark .margin-order-list div,
|
||||||
|
.theme-dark .parallel-current-verse,
|
||||||
|
.theme-dark .parallel-context section,
|
||||||
|
.theme-dark .parallel-note-sections section,
|
||||||
|
.theme-dark .parallel-controls output,
|
||||||
.theme-dark .place-list section,
|
.theme-dark .place-list section,
|
||||||
.theme-dark .route-list span,
|
.theme-dark .route-list span,
|
||||||
.theme-dark .audio-controls .secondary-button {
|
.theme-dark .audio-controls .secondary-button {
|
||||||
@@ -2110,6 +2202,9 @@ textarea:focus-visible {
|
|||||||
.theme-dark .audio-sliders label,
|
.theme-dark .audio-sliders label,
|
||||||
.theme-dark .audio-status,
|
.theme-dark .audio-status,
|
||||||
.theme-dark .audio-status strong,
|
.theme-dark .audio-status strong,
|
||||||
|
.theme-dark .parallel-controls label,
|
||||||
|
.theme-dark .parallel-context strong,
|
||||||
|
.theme-dark .parallel-note-sections h3,
|
||||||
.theme-dark .session-facts dt,
|
.theme-dark .session-facts dt,
|
||||||
.theme-dark .about-list dt,
|
.theme-dark .about-list dt,
|
||||||
.theme-dark .modal-section label,
|
.theme-dark .modal-section label,
|
||||||
@@ -2133,7 +2228,11 @@ textarea:focus-visible {
|
|||||||
.theme-dark .about-modal p,
|
.theme-dark .about-modal p,
|
||||||
.theme-dark .resource-toggles label,
|
.theme-dark .resource-toggles label,
|
||||||
.theme-dark .checkbox-row,
|
.theme-dark .checkbox-row,
|
||||||
.theme-dark .segmented-control button {
|
.theme-dark .segmented-control button,
|
||||||
|
.theme-dark .parallel-current-verse p:last-child,
|
||||||
|
.theme-dark .parallel-context p,
|
||||||
|
.theme-dark .parallel-note-sections p,
|
||||||
|
.theme-dark .parallel-controls output {
|
||||||
color: #eee8d8 !important;
|
color: #eee8d8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+212
@@ -37,6 +37,7 @@ import type {
|
|||||||
AudioBibleSegment,
|
AudioBibleSegment,
|
||||||
CommentaryEntry,
|
CommentaryEntry,
|
||||||
DictionaryEntry,
|
DictionaryEntry,
|
||||||
|
Footnote,
|
||||||
MapContext,
|
MapContext,
|
||||||
TranslationResource,
|
TranslationResource,
|
||||||
Verse,
|
Verse,
|
||||||
@@ -350,6 +351,7 @@ function App() {
|
|||||||
const [marginColumnPercent, setMarginColumnPercent] = useState(20)
|
const [marginColumnPercent, setMarginColumnPercent] = useState(20)
|
||||||
const [studyStackPinned, setStudyStackPinned] = useState(true)
|
const [studyStackPinned, setStudyStackPinned] = useState(true)
|
||||||
const [activeStudyBook, setActiveStudyBook] = useState<StudyBook>('notebook')
|
const [activeStudyBook, setActiveStudyBook] = useState<StudyBook>('notebook')
|
||||||
|
const [parallelTranslationId, setParallelTranslationId] = useState<string | null>(null)
|
||||||
const [marginPanelOrder, setMarginPanelOrder] = useState<MarginPanelId[]>([
|
const [marginPanelOrder, setMarginPanelOrder] = useState<MarginPanelId[]>([
|
||||||
'margin-note',
|
'margin-note',
|
||||||
'original',
|
'original',
|
||||||
@@ -359,6 +361,13 @@ function App() {
|
|||||||
])
|
])
|
||||||
const [commentaryEntries, setCommentaryEntries] = useState<CommentaryEntry[]>([])
|
const [commentaryEntries, setCommentaryEntries] = useState<CommentaryEntry[]>([])
|
||||||
const [dictionaryEntries, setDictionaryEntries] = useState<DictionaryEntry[]>([])
|
const [dictionaryEntries, setDictionaryEntries] = useState<DictionaryEntry[]>([])
|
||||||
|
const [parallelVerses, setParallelVerses] = useState<Verse[]>([])
|
||||||
|
const [parallelNotes, setParallelNotes] = useState<{ footnotes: Footnote[]; studyNotes: Footnote[] }>({
|
||||||
|
footnotes: [],
|
||||||
|
studyNotes: [],
|
||||||
|
})
|
||||||
|
const [parallelLoading, setParallelLoading] = useState(false)
|
||||||
|
const [parallelError, setParallelError] = useState<string | null>(null)
|
||||||
const [mapContext, setMapContext] = useState<MapContext>({
|
const [mapContext, setMapContext] = useState<MapContext>({
|
||||||
selectedPlaces: [],
|
selectedPlaces: [],
|
||||||
pagePlaces: [],
|
pagePlaces: [],
|
||||||
@@ -418,6 +427,7 @@ function App() {
|
|||||||
setMarginColumnPercent(settings.marginColumnPercent ?? 20)
|
setMarginColumnPercent(settings.marginColumnPercent ?? 20)
|
||||||
setStudyStackPinned(settings.studyStackPinned ?? true)
|
setStudyStackPinned(settings.studyStackPinned ?? true)
|
||||||
setActiveStudyBook(settings.activeStudyBook ?? 'notebook')
|
setActiveStudyBook(settings.activeStudyBook ?? 'notebook')
|
||||||
|
setParallelTranslationId(settings.parallelTranslationId ?? null)
|
||||||
setMarginPanelOrder(settings.marginPanelOrder ?? ['margin-note', 'original', 'linked', 'definition', 'study-notes'])
|
setMarginPanelOrder(settings.marginPanelOrder ?? ['margin-note', 'original', 'linked', 'definition', 'study-notes'])
|
||||||
setThemeMode(settings.themeMode ?? 'light')
|
setThemeMode(settings.themeMode ?? 'light')
|
||||||
}
|
}
|
||||||
@@ -572,6 +582,7 @@ function App() {
|
|||||||
marginColumnPercent,
|
marginColumnPercent,
|
||||||
studyStackPinned,
|
studyStackPinned,
|
||||||
activeStudyBook,
|
activeStudyBook,
|
||||||
|
parallelTranslationId,
|
||||||
marginPanelOrder,
|
marginPanelOrder,
|
||||||
themeMode,
|
themeMode,
|
||||||
}),
|
}),
|
||||||
@@ -590,6 +601,7 @@ function App() {
|
|||||||
marginPanelOrder,
|
marginPanelOrder,
|
||||||
notesPinned,
|
notesPinned,
|
||||||
originalCollapsed,
|
originalCollapsed,
|
||||||
|
parallelTranslationId,
|
||||||
showCommentaryPanel,
|
showCommentaryPanel,
|
||||||
showDefinitionPanel,
|
showDefinitionPanel,
|
||||||
showDictionaryPanel,
|
showDictionaryPanel,
|
||||||
@@ -715,6 +727,13 @@ function App() {
|
|||||||
verses[0],
|
verses[0],
|
||||||
[hoveredId, libraryVerses, selectedId, verses],
|
[hoveredId, libraryVerses, selectedId, verses],
|
||||||
)
|
)
|
||||||
|
const pinnedVerse = useMemo(
|
||||||
|
() =>
|
||||||
|
verses.find((verse) => verse.id === selectedId) ??
|
||||||
|
libraryVerses.find((verse) => verse.id === selectedId) ??
|
||||||
|
selectedVerse,
|
||||||
|
[libraryVerses, selectedId, selectedVerse, verses],
|
||||||
|
)
|
||||||
const selectedStrongEntry = useMemo(() => {
|
const selectedStrongEntry = useMemo(() => {
|
||||||
if (!selectedVerse?.strongs.length) return null
|
if (!selectedVerse?.strongs.length) return null
|
||||||
return (
|
return (
|
||||||
@@ -732,6 +751,20 @@ function App() {
|
|||||||
translations.find((translation) => translation.id === defaultTranslationId),
|
translations.find((translation) => translation.id === defaultTranslationId),
|
||||||
[activeSession?.baseTranslation, translations],
|
[activeSession?.baseTranslation, translations],
|
||||||
)
|
)
|
||||||
|
const availableParallelTranslations = useMemo(
|
||||||
|
() => translations.filter((translation) => translation.id !== activeSession?.baseTranslation),
|
||||||
|
[activeSession?.baseTranslation, translations],
|
||||||
|
)
|
||||||
|
const selectedParallelTranslationId = useMemo(() => {
|
||||||
|
if (parallelTranslationId && availableParallelTranslations.some((translation) => translation.id === parallelTranslationId)) {
|
||||||
|
return parallelTranslationId
|
||||||
|
}
|
||||||
|
return availableParallelTranslations[0]?.id ?? null
|
||||||
|
}, [availableParallelTranslations, parallelTranslationId])
|
||||||
|
const parallelTranslation = useMemo(
|
||||||
|
() => translations.find((translation) => translation.id === selectedParallelTranslationId) ?? null,
|
||||||
|
[selectedParallelTranslationId, translations],
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBookTabOffset(0)
|
setBookTabOffset(0)
|
||||||
@@ -741,6 +774,70 @@ function App() {
|
|||||||
setChapterTabOffset(0)
|
setChapterTabOffset(0)
|
||||||
}, [selectedVerse?.book, selectedVerse?.chapter])
|
}, [selectedVerse?.book, selectedVerse?.chapter])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedParallelTranslationId || !pinnedVerse) {
|
||||||
|
setParallelVerses([])
|
||||||
|
setParallelNotes({ footnotes: [], studyNotes: [] })
|
||||||
|
setParallelError(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelled = false
|
||||||
|
|
||||||
|
async function loadParallelVerse() {
|
||||||
|
setParallelLoading(true)
|
||||||
|
setParallelError(null)
|
||||||
|
try {
|
||||||
|
const state = await getLibraryState(selectedParallelTranslationId)
|
||||||
|
const currentIndex = state.verses.findIndex(
|
||||||
|
(verse) =>
|
||||||
|
verse.book === pinnedVerse.book &&
|
||||||
|
verse.chapter === pinnedVerse.chapter &&
|
||||||
|
verse.verse === pinnedVerse.verse,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (currentIndex < 0) {
|
||||||
|
if (!cancelled) {
|
||||||
|
setParallelVerses([])
|
||||||
|
setParallelNotes({ footnotes: [], studyNotes: [] })
|
||||||
|
setParallelError(`No matching verse found in ${parallelTranslation?.abbreviation ?? 'parallel translation'}.`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentVerse = state.verses[currentIndex]
|
||||||
|
const context = [
|
||||||
|
state.verses[currentIndex - 1],
|
||||||
|
currentVerse,
|
||||||
|
state.verses[currentIndex + 1],
|
||||||
|
].filter(
|
||||||
|
(verse): verse is Verse =>
|
||||||
|
Boolean(verse && verse.book === currentVerse.book),
|
||||||
|
)
|
||||||
|
const notesByVerse = await getTranslationNotesForVerses(selectedParallelTranslationId, [currentVerse])
|
||||||
|
const notes = notesByVerse.get(String(currentVerse.id)) ?? { footnotes: [], studyNotes: [] }
|
||||||
|
|
||||||
|
if (!cancelled) {
|
||||||
|
setParallelVerses(context)
|
||||||
|
setParallelNotes(notes)
|
||||||
|
}
|
||||||
|
} catch (reason) {
|
||||||
|
if (!cancelled) {
|
||||||
|
setParallelVerses([])
|
||||||
|
setParallelNotes({ footnotes: [], studyNotes: [] })
|
||||||
|
setParallelError(String(reason))
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!cancelled) setParallelLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadParallelVerse()
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
}, [parallelTranslation?.abbreviation, pinnedVerse, selectedParallelTranslationId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
|
|
||||||
@@ -2294,6 +2391,118 @@ function App() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderParallelBook() {
|
||||||
|
const currentParallelVerse = pinnedVerse
|
||||||
|
? parallelVerses.find(
|
||||||
|
(verse) =>
|
||||||
|
verse.book === pinnedVerse.book &&
|
||||||
|
verse.chapter === pinnedVerse.chapter &&
|
||||||
|
verse.verse === pinnedVerse.verse,
|
||||||
|
) ?? null
|
||||||
|
: null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="stack-book parallel-book article-book" aria-label="Parallel translation">
|
||||||
|
<header>
|
||||||
|
<div>
|
||||||
|
<span className="eyebrow">Parallel</span>
|
||||||
|
<h2>{pinnedVerse ? reference(pinnedVerse) : 'Parallel Translation'}</h2>
|
||||||
|
</div>
|
||||||
|
<span>{parallelLoading ? 'Loading' : parallelTranslation?.abbreviation ?? 'None'}</span>
|
||||||
|
</header>
|
||||||
|
<div className="parallel-controls">
|
||||||
|
<label>
|
||||||
|
Base
|
||||||
|
<output>{activeTranslation?.abbreviation ?? activeSession?.baseTranslation ?? 'Base'}</output>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Compare
|
||||||
|
<select
|
||||||
|
value={selectedParallelTranslationId ?? ''}
|
||||||
|
onChange={(event) => setParallelTranslationId(event.target.value || null)}
|
||||||
|
>
|
||||||
|
{availableParallelTranslations.length ? null : (
|
||||||
|
<option value="">No alternate translations</option>
|
||||||
|
)}
|
||||||
|
{availableParallelTranslations.map((translation) => (
|
||||||
|
<option key={translation.id} value={translation.id}>
|
||||||
|
{translation.abbreviation} - {translation.shortTitle}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{parallelError ? (
|
||||||
|
<p className="resource-disabled">{parallelError}</p>
|
||||||
|
) : currentParallelVerse ? (
|
||||||
|
<>
|
||||||
|
<article className="parallel-current-verse">
|
||||||
|
<p className="article-kicker">
|
||||||
|
{parallelTranslation?.title ?? selectedParallelTranslationId}
|
||||||
|
</p>
|
||||||
|
<h3>{reference(currentParallelVerse)}</h3>
|
||||||
|
<p>{currentParallelVerse.text}</p>
|
||||||
|
</article>
|
||||||
|
<div className="parallel-context">
|
||||||
|
{parallelVerses
|
||||||
|
.filter((verse) => verse.id !== currentParallelVerse.id)
|
||||||
|
.map((verse) => (
|
||||||
|
<section key={verse.id}>
|
||||||
|
<strong>{reference(verse)}</strong>
|
||||||
|
<p>{verse.text}</p>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="parallel-note-sections">
|
||||||
|
<section>
|
||||||
|
<h3>Translation Notes</h3>
|
||||||
|
{parallelNotes.footnotes.length ? (
|
||||||
|
parallelNotes.footnotes.map((note) => (
|
||||||
|
<p
|
||||||
|
key={note.id}
|
||||||
|
draggable
|
||||||
|
onDragStart={(event) => startTextDrag(event, `${note.reference} ${note.text}`)}
|
||||||
|
>
|
||||||
|
<strong>{note.reference}</strong>
|
||||||
|
<span>{note.text}</span>
|
||||||
|
</p>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<p className="resource-disabled">No translation notes for this verse.</p>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>Study Notes</h3>
|
||||||
|
{parallelNotes.studyNotes.length ? (
|
||||||
|
parallelNotes.studyNotes.map((note) => (
|
||||||
|
<p
|
||||||
|
key={note.id}
|
||||||
|
draggable
|
||||||
|
onDragStart={(event) => startTextDrag(event, `${note.reference} ${note.text}`)}
|
||||||
|
>
|
||||||
|
<strong>{note.reference}</strong>
|
||||||
|
<span>{note.text}</span>
|
||||||
|
</p>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<p className="resource-disabled">No study notes for this verse.</p>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<p className="map-attribution">
|
||||||
|
{parallelTranslation?.licenseName ?? 'Parallel translation package'}
|
||||||
|
{parallelTranslation?.attribution ? ` - ${parallelTranslation.attribution}` : ''}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<p className="resource-disabled">
|
||||||
|
{parallelLoading ? 'Loading parallel verse...' : 'Choose an alternate translation to compare.'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function renderSearchBook() {
|
function renderSearchBook() {
|
||||||
return (
|
return (
|
||||||
<section className="stack-book search-book" aria-label="Search results">
|
<section className="stack-book search-book" aria-label="Search results">
|
||||||
@@ -2351,6 +2560,8 @@ function App() {
|
|||||||
return renderCommentaryBook()
|
return renderCommentaryBook()
|
||||||
case 'audio':
|
case 'audio':
|
||||||
return renderAudioBook()
|
return renderAudioBook()
|
||||||
|
case 'parallel':
|
||||||
|
return renderParallelBook()
|
||||||
case 'search':
|
case 'search':
|
||||||
return renderSearchBook()
|
return renderSearchBook()
|
||||||
case 'notebook':
|
case 'notebook':
|
||||||
@@ -2367,6 +2578,7 @@ function App() {
|
|||||||
{ id: 'atlas', label: 'Atlas' },
|
{ id: 'atlas', label: 'Atlas' },
|
||||||
{ id: 'commentary', label: 'Comm' },
|
{ id: 'commentary', label: 'Comm' },
|
||||||
{ id: 'audio', label: 'Audio' },
|
{ id: 'audio', label: 'Audio' },
|
||||||
|
{ id: 'parallel', label: 'Para' },
|
||||||
{ id: 'search', label: 'Search' },
|
{ id: 'search', label: 'Search' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -88,11 +88,12 @@ export type StudySettings = {
|
|||||||
marginColumnPercent: number
|
marginColumnPercent: number
|
||||||
studyStackPinned: boolean
|
studyStackPinned: boolean
|
||||||
activeStudyBook: StudyBook
|
activeStudyBook: StudyBook
|
||||||
|
parallelTranslationId: string | null
|
||||||
marginPanelOrder: MarginPanelId[]
|
marginPanelOrder: MarginPanelId[]
|
||||||
themeMode: ThemeMode
|
themeMode: ThemeMode
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StudyBook = 'notebook' | 'dictionary' | 'lexicon' | 'atlas' | 'commentary' | 'audio' | 'search'
|
export type StudyBook = 'notebook' | 'dictionary' | 'lexicon' | 'atlas' | 'commentary' | 'audio' | 'parallel' | 'search'
|
||||||
export type MarginPanelId = 'margin-note' | 'original' | 'linked' | 'definition' | 'study-notes'
|
export type MarginPanelId = 'margin-note' | 'original' | 'linked' | 'definition' | 'study-notes'
|
||||||
|
|
||||||
export const defaultMarginPanelOrder: MarginPanelId[] = [
|
export const defaultMarginPanelOrder: MarginPanelId[] = [
|
||||||
@@ -161,6 +162,7 @@ export function defaultStudySettings(): StudySettings {
|
|||||||
marginColumnPercent: 20,
|
marginColumnPercent: 20,
|
||||||
studyStackPinned: true,
|
studyStackPinned: true,
|
||||||
activeStudyBook: 'notebook',
|
activeStudyBook: 'notebook',
|
||||||
|
parallelTranslationId: null,
|
||||||
marginPanelOrder: defaultMarginPanelOrder,
|
marginPanelOrder: defaultMarginPanelOrder,
|
||||||
themeMode: 'light',
|
themeMode: 'light',
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user