Wire Strong's dictionary concordance UI
This commit is contained in:
+72
-4
@@ -218,6 +218,37 @@ input:focus-visible {
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.linked-word-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 22px;
|
||||
padding-top: 18px;
|
||||
border-top: 1px solid #e4e0d6;
|
||||
}
|
||||
|
||||
.word-link {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 7px;
|
||||
padding: 7px 9px;
|
||||
border-color: #cfc8b8;
|
||||
background: #f3efe4;
|
||||
color: #202124;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.word-link small {
|
||||
color: #657061;
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.word-link.active {
|
||||
border-color: #2f6f5e;
|
||||
background: #e7f0eb;
|
||||
}
|
||||
|
||||
.study-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.65fr);
|
||||
@@ -255,13 +286,17 @@ input:focus-visible {
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.strong-entry {
|
||||
border: 1px solid #e4e0d6;
|
||||
.strong-focus {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
margin-top: 14px;
|
||||
padding: 16px;
|
||||
border: 1px solid #b9cabf;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
background: #fbfaf4;
|
||||
background: #eef6f1;
|
||||
}
|
||||
|
||||
.strong-focus div,
|
||||
.strong-entry div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -271,6 +306,39 @@ input:focus-visible {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.strong-focus h4 {
|
||||
margin: 0;
|
||||
color: #1f211e;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.strong-focus p {
|
||||
margin: 0;
|
||||
color: #3f443d;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.strong-focus button {
|
||||
justify-self: start;
|
||||
margin-top: 4px;
|
||||
background: #2f6f5e;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.strong-entry {
|
||||
border: 1px solid #e4e0d6;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
background: #fbfaf4;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.strong-entry.active {
|
||||
border-color: #2f6f5e;
|
||||
background: #f3faf6;
|
||||
}
|
||||
|
||||
.strong-entry h4 {
|
||||
margin-top: 8px;
|
||||
color: #1f211e;
|
||||
|
||||
+48
-2
@@ -14,6 +14,7 @@ function App() {
|
||||
const [verses, setVerses] = useState<Verse[]>([])
|
||||
const [tags, setTags] = useState<Tag[]>([])
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||
const [selectedStrong, setSelectedStrong] = useState<string | null>(null)
|
||||
const [tagInput, setTagInput] = useState('')
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
@@ -60,6 +61,19 @@ function App() {
|
||||
() => verses.find((verse) => verse.id === selectedId) ?? verses[0],
|
||||
[selectedId, verses],
|
||||
)
|
||||
const selectedStrongEntry = useMemo(() => {
|
||||
if (!selectedVerse?.strongs.length) return null
|
||||
return (
|
||||
selectedVerse.strongs.find((entry) => entry.strong === selectedStrong) ??
|
||||
selectedVerse.strongs[0]
|
||||
)
|
||||
}, [selectedStrong, selectedVerse])
|
||||
|
||||
function searchStrong(strong: string) {
|
||||
setQuery(strong)
|
||||
setSelectedStrong(strong)
|
||||
runSearch(strong).catch((reason) => setError(String(reason)))
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="app-shell">
|
||||
@@ -154,6 +168,20 @@ function App() {
|
||||
|
||||
<article className="verse-card">
|
||||
<p>{selectedVerse.text}</p>
|
||||
<div className="linked-word-list" aria-label="Linked Strong's words">
|
||||
{selectedVerse.strongs.map((entry) => (
|
||||
<button
|
||||
key={`${entry.strong}-${entry.position}`}
|
||||
className={entry.strong === selectedStrongEntry?.strong ? 'word-link active' : 'word-link'}
|
||||
type="button"
|
||||
title={`${entry.surface}: ${entry.strong}`}
|
||||
onClick={() => setSelectedStrong(entry.strong)}
|
||||
>
|
||||
<span>{entry.surface}</span>
|
||||
<small>{entry.strong}</small>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div className="study-grid">
|
||||
@@ -162,12 +190,30 @@ function App() {
|
||||
<h3>Strong's Links</h3>
|
||||
<span>{selectedVerse.strongs.length}</span>
|
||||
</div>
|
||||
{selectedStrongEntry ? (
|
||||
<article className="strong-focus">
|
||||
<div>
|
||||
<strong>{selectedStrongEntry.strong}</strong>
|
||||
<span>{selectedStrongEntry.language}</span>
|
||||
</div>
|
||||
<h4>{selectedStrongEntry.lemma}</h4>
|
||||
<p className="translit">{selectedStrongEntry.transliteration}</p>
|
||||
<p>{selectedStrongEntry.definition}</p>
|
||||
<button type="button" onClick={() => searchStrong(selectedStrongEntry.strong)}>
|
||||
Show matching verses
|
||||
</button>
|
||||
</article>
|
||||
) : null}
|
||||
<div className="strong-list">
|
||||
{selectedVerse.strongs.map((entry) => (
|
||||
<article key={entry.strong} className="strong-entry">
|
||||
<article
|
||||
key={`${entry.strong}-${entry.position}`}
|
||||
className={entry.strong === selectedStrongEntry?.strong ? 'strong-entry active' : 'strong-entry'}
|
||||
onClick={() => setSelectedStrong(entry.strong)}
|
||||
>
|
||||
<div>
|
||||
<strong>{entry.strong}</strong>
|
||||
<span>{entry.language}</span>
|
||||
<span>{entry.surface}</span>
|
||||
</div>
|
||||
<h4>{entry.lemma}</h4>
|
||||
<p className="translit">{entry.transliteration}</p>
|
||||
|
||||
@@ -19,6 +19,8 @@ const browserVerses: Verse[] = [
|
||||
strongs: [
|
||||
{
|
||||
strong: 'H7225',
|
||||
surface: 'beginning',
|
||||
position: 1,
|
||||
lemma: 'רֵאשִׁית',
|
||||
transliteration: 'reshith',
|
||||
definition: 'Beginning, first, chief, the first part.',
|
||||
@@ -26,6 +28,8 @@ const browserVerses: Verse[] = [
|
||||
},
|
||||
{
|
||||
strong: 'H430',
|
||||
surface: 'God',
|
||||
position: 2,
|
||||
lemma: 'אֱלֹהִים',
|
||||
transliteration: 'elohim',
|
||||
definition: 'God, gods, judges, rulers; plural form often used of the one true God.',
|
||||
@@ -43,6 +47,8 @@ const browserVerses: Verse[] = [
|
||||
strongs: [
|
||||
{
|
||||
strong: 'H3068',
|
||||
surface: 'LORD',
|
||||
position: 1,
|
||||
lemma: 'יְהוָֹה',
|
||||
transliteration: 'YHWH',
|
||||
definition: 'The covenant name of the LORD.',
|
||||
@@ -50,6 +56,8 @@ const browserVerses: Verse[] = [
|
||||
},
|
||||
{
|
||||
strong: 'H7462',
|
||||
surface: 'shepherd',
|
||||
position: 2,
|
||||
lemma: 'רָעָה',
|
||||
transliteration: 'raah',
|
||||
definition: 'To shepherd, pasture, feed, tend a flock.',
|
||||
@@ -67,6 +75,8 @@ const browserVerses: Verse[] = [
|
||||
strongs: [
|
||||
{
|
||||
strong: 'G25',
|
||||
surface: 'loved',
|
||||
position: 1,
|
||||
lemma: 'ἀγαπάω',
|
||||
transliteration: 'agapao',
|
||||
definition: 'To love, value, welcome, or take pleasure in.',
|
||||
@@ -74,6 +84,8 @@ const browserVerses: Verse[] = [
|
||||
},
|
||||
{
|
||||
strong: 'G4100',
|
||||
surface: 'believeth',
|
||||
position: 3,
|
||||
lemma: 'πιστεύω',
|
||||
transliteration: 'pisteuo',
|
||||
definition: 'To believe, trust, have faith in.',
|
||||
@@ -91,6 +103,8 @@ const browserVerses: Verse[] = [
|
||||
strongs: [
|
||||
{
|
||||
strong: 'G2822',
|
||||
surface: 'called',
|
||||
position: 2,
|
||||
lemma: 'κλητός',
|
||||
transliteration: 'kletos',
|
||||
definition: 'Called, invited, appointed.',
|
||||
@@ -98,6 +112,8 @@ const browserVerses: Verse[] = [
|
||||
},
|
||||
{
|
||||
strong: 'G4286',
|
||||
surface: 'purpose',
|
||||
position: 3,
|
||||
lemma: 'πρόθεσις',
|
||||
transliteration: 'prothesis',
|
||||
definition: 'Purpose, setting forth, deliberate plan.',
|
||||
|
||||
@@ -10,6 +10,8 @@ export type Verse = {
|
||||
|
||||
export type StrongLink = {
|
||||
strong: string
|
||||
surface: string
|
||||
position: number
|
||||
lemma: string
|
||||
transliteration: string
|
||||
definition: string
|
||||
|
||||
Reference in New Issue
Block a user