Add Strong display modes and book page boundaries
This commit is contained in:
+51
-9
@@ -7,6 +7,7 @@ import './App.css'
|
||||
const tagColors = ['#2f6f5e', '#735c0f', '#8a3ffc', '#b42318', '#245ba7']
|
||||
const pageSize = 34
|
||||
type ViewMode = 'page' | 'study' | 'notes' | 'compare'
|
||||
type StrongDisplayMode = 'off' | 'highlight' | 'numbers'
|
||||
|
||||
function reference(verse: Verse) {
|
||||
return `${verse.book} ${verse.chapter}:${verse.verse}`
|
||||
@@ -20,6 +21,7 @@ function App() {
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||
const [pageStartId, setPageStartId] = useState<number | null>(null)
|
||||
const [selectedStrong, setSelectedStrong] = useState<string | null>(null)
|
||||
const [strongDisplay, setStrongDisplay] = useState<StrongDisplayMode>('highlight')
|
||||
const [tagInput, setTagInput] = useState('')
|
||||
const [noteDraft, setNoteDraft] = useState('')
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -85,9 +87,19 @@ function App() {
|
||||
const pageAnchors = useMemo(() => {
|
||||
const source = libraryVerses.length ? libraryVerses : verses
|
||||
const anchors: Verse[] = []
|
||||
let index = 0
|
||||
|
||||
for (let index = 0; index < source.length; index += pageSize) {
|
||||
anchors.push(source[index])
|
||||
while (index < source.length) {
|
||||
const book = source[index].book
|
||||
let bookVerseIndex = 0
|
||||
|
||||
while (index < source.length && source[index].book === book) {
|
||||
if (bookVerseIndex % pageSize === 0) {
|
||||
anchors.push(source[index])
|
||||
}
|
||||
bookVerseIndex += 1
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
return anchors
|
||||
@@ -98,7 +110,10 @@ function App() {
|
||||
const pageStartIndex = source.findIndex((verse) => verse.id === pageStartId)
|
||||
const selectedIndex = source.findIndex((verse) => verse.id === selectedVerse.id)
|
||||
const start = Math.max(0, pageStartIndex >= 0 ? pageStartIndex : selectedIndex)
|
||||
return source.slice(start, start + pageSize)
|
||||
const book = source[start]?.book
|
||||
return source
|
||||
.slice(start, start + pageSize)
|
||||
.filter((verse) => verse.book === book)
|
||||
}, [libraryVerses, pageStartId, selectedVerse, verses])
|
||||
const pageRange = pageVerses.length
|
||||
? `${reference(pageVerses[0])} - ${reference(pageVerses[pageVerses.length - 1])}`
|
||||
@@ -169,8 +184,17 @@ function App() {
|
||||
const source = libraryVerses.length ? libraryVerses : verses
|
||||
const index = source.findIndex((entry) => entry.id === verse.id)
|
||||
if (index < 0) return pageStartId ?? verse.id
|
||||
const pageIndex = Math.floor(index / pageSize) * pageSize
|
||||
return source[pageIndex]?.id ?? verse.id
|
||||
|
||||
let anchor = source[index]
|
||||
for (const pageAnchor of pageAnchors) {
|
||||
const anchorIndex = source.findIndex((entry) => entry.id === pageAnchor.id)
|
||||
if (anchorIndex > index) break
|
||||
if (pageAnchor.book === verse.book) {
|
||||
anchor = pageAnchor
|
||||
}
|
||||
}
|
||||
|
||||
return anchor.id
|
||||
}
|
||||
|
||||
function selectVerse(verse: Verse) {
|
||||
@@ -184,7 +208,7 @@ function App() {
|
||||
}
|
||||
|
||||
function renderVerseText(verse: Verse) {
|
||||
if (!verse.strongs.length) return verse.text
|
||||
if (!verse.strongs.length || strongDisplay === 'off') return verse.text
|
||||
|
||||
const parts: ReactNode[] = []
|
||||
let cursor = 0
|
||||
@@ -203,10 +227,15 @@ function App() {
|
||||
|
||||
const linkedText = verse.text.slice(index, index + surface.length)
|
||||
const isActive = entry.strong === selectedStrong
|
||||
const showCode = strongDisplay === 'numbers' || isActive
|
||||
parts.push(
|
||||
<span
|
||||
key={`${verse.id}-${entry.strong}-${entry.position}`}
|
||||
className={isActive ? 'strong-token active' : 'strong-token'}
|
||||
className={[
|
||||
'strong-token',
|
||||
strongDisplay,
|
||||
isActive ? 'active' : '',
|
||||
].filter(Boolean).join(' ')}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
title={`${entry.surface}: ${entry.strong}`}
|
||||
@@ -222,8 +251,8 @@ function App() {
|
||||
}}
|
||||
>
|
||||
<span className="strong-surface">{linkedText}</span>
|
||||
{(verse.id === selectedId || isActive) ? (
|
||||
<small className="strong-code">{entry.strong}</small>
|
||||
{showCode ? (
|
||||
<sup className="strong-code">{entry.strong}</sup>
|
||||
) : null}
|
||||
</span>,
|
||||
)
|
||||
@@ -388,6 +417,19 @@ function App() {
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Strong's
|
||||
<select
|
||||
value={strongDisplay}
|
||||
onChange={(event) =>
|
||||
setStrongDisplay(event.target.value as StrongDisplayMode)
|
||||
}
|
||||
>
|
||||
<option value="off">Off</option>
|
||||
<option value="highlight">Highlight</option>
|
||||
<option value="numbers">Numbers</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<form
|
||||
className="search-box"
|
||||
|
||||
Reference in New Issue
Block a user