Skip to content

Commit 097b3f1

Browse files
committed
Books
1 parent d005e86 commit 097b3f1

340 files changed

Lines changed: 278444 additions & 60 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

assets/data/bible-books.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
{"name":"Proverbs","slug":"proverbs","file":"Proverbs.json","testament":"ot","chapters":31},
2222
{"name":"Ecclesiastes","slug":"ecclesiastes","file":"Ecclesiastes.json","testament":"ot","chapters":12},
2323
{"name":"Song of Solomon","slug":"song-of-solomon","file":"SongofSolomon.json","testament":"ot","chapters":8},
24+
2425
{"name":"Isaiah","slug":"isaiah","file":"Isaiah.json","testament":"ot","chapters":66},
2526
{"name":"Jeremiah","slug":"jeremiah","file":"Jeremiah.json","testament":"ot","chapters":52},
2627
{"name":"Lamentations","slug":"lamentations","file":"Lamentations.json","testament":"ot","chapters":5},

assets/js/bible-portal.js

Lines changed: 152 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
/* ============================================================
1515
* Constants
1616
* ============================================================ */
17+
// Translations with full per-book JSON data available under bible-data/{value}/
1718
const EN_TRANSLATIONS = [
1819
{ value: "kjv", label: "KJV — King James Version", full: true },
1920
{ value: "nkjv", label: "NKJV — New King James Version", full: false },
@@ -22,11 +23,14 @@
2223
];
2324

2425
const TA_TRANSLATIONS = [
25-
{ value: "pv", label: "PV — பரிசுத்த வேதாகமம்" }
26+
{ value: "pv", label: "PV — பரிசுத்த வேதாகமம் (Tamil OV)" }
2627
];
2728

2829
const ALL_TRANSLATIONS = EN_TRANSLATIONS.concat(TA_TRANSLATIONS);
2930

31+
// Translations whose per-book files are currently just placeholder stubs
32+
const STUB_TRANSLATIONS = new Set(["nkjv", "niv", "esv"]);
33+
3034
/* ============================================================
3135
* App State
3236
* ============================================================ */
@@ -209,26 +213,113 @@
209213
* Helper: Toast notifications
210214
* ============================================================ */
211215
function toast(msg, color) {
212-
// Simple toast notification
213-
console.log(msg);
216+
var existing = document.getElementById("_zgm-toast");
217+
if (existing) existing.remove();
218+
var t = document.createElement("div");
219+
t.id = "_zgm-toast";
220+
t.textContent = msg;
221+
t.style.cssText = [
222+
"position:fixed", "bottom:1.5rem", "right:1.5rem", "z-index:9999",
223+
"background:" + (color || "#2e7d32"), "color:#fff",
224+
"padding:0.7rem 1.2rem", "border-radius:8px",
225+
"font-size:0.9rem", "box-shadow:0 4px 14px rgba(0,0,0,0.25)",
226+
"opacity:0", "transition:opacity 0.2s"
227+
].join(";");
228+
document.body.appendChild(t);
229+
requestAnimationFrame(function () { t.style.opacity = "1"; });
230+
setTimeout(function () {
231+
t.style.opacity = "0";
232+
setTimeout(function () { t.remove(); }, 200);
233+
}, 2800);
214234
}
215235

216-
async function loadBooks() {
217-
try {
218-
const res = await fetch("assets/data/bible-books.json");
219-
if (!res.ok) throw new Error("books list not found");
220-
const list = await res.json();
221-
state.books = list;
222-
list.forEach(function (book) {
223-
state.booksMap[book.name] = book;
224-
});
225-
} catch (_) {
226-
const sample = (window.SAMPLE_BIBLE_DATA || {}).books || [];
227-
state.books = sample;
228-
sample.forEach(function (book) {
229-
state.booksMap[book.name] = book;
236+
async function tryFetchJson(paths) {
237+
for (var i = 0; i < paths.length; i++) {
238+
try {
239+
var res = await fetch(paths[i]);
240+
if (!res.ok) continue;
241+
var data = await res.json();
242+
return data;
243+
} catch (_) {
244+
// Continue trying remaining paths.
245+
}
246+
}
247+
return null;
248+
}
249+
250+
function bookNameToFile(bookName) {
251+
return String(bookName || "").replace(/\s+/g, "") + ".json";
252+
}
253+
254+
function setBooks(list) {
255+
state.books = Array.isArray(list) ? list : [];
256+
state.booksMap = {};
257+
state.books.forEach(function (book) {
258+
if (book && book.name) state.booksMap[book.name] = book;
259+
});
260+
}
261+
262+
async function buildBooksFromNames(bookNames) {
263+
var out = [];
264+
for (var i = 0; i < bookNames.length; i++) {
265+
var name = String(bookNames[i] || "").trim();
266+
if (!name) continue;
267+
268+
var file = bookNameToFile(name);
269+
var chapterCount = 1;
270+
var raw = await tryFetchJson([
271+
"bible-data/kjv/" + file,
272+
"./bible-data/kjv/" + file,
273+
"/bible-data/kjv/" + file
274+
]);
275+
276+
if (raw && Array.isArray(raw.chapters) && raw.chapters.length) {
277+
chapterCount = raw.chapters.length;
278+
}
279+
280+
out.push({
281+
name: name,
282+
slug: name.toLowerCase().replace(/\s+/g, "-"),
283+
file: file,
284+
testament: i < 39 ? "ot" : "nt",
285+
chapters: chapterCount
230286
});
231287
}
288+
return out;
289+
}
290+
291+
async function loadBooks() {
292+
var list = await tryFetchJson([
293+
"assets/data/bible-books.json",
294+
"./assets/data/bible-books.json",
295+
"/assets/data/bible-books.json"
296+
]);
297+
298+
if (Array.isArray(list) && list.length && list[0] && list[0].name) {
299+
setBooks(list);
300+
return;
301+
}
302+
303+
var names = await tryFetchJson([
304+
"bible-data/Books.json",
305+
"./bible-data/Books.json",
306+
"/bible-data/Books.json"
307+
]);
308+
309+
if (Array.isArray(names) && names.length) {
310+
var rebuilt = await buildBooksFromNames(names);
311+
setBooks(rebuilt);
312+
return;
313+
}
314+
315+
var sample = (window.SAMPLE_BIBLE_DATA || {}).books || [];
316+
if (Array.isArray(sample) && sample.length) {
317+
setBooks(sample);
318+
return;
319+
}
320+
321+
setBooks([]);
322+
toast("Unable to load Bible books. Please refresh.", "#e53935");
232323
}
233324

234325
function syncTileActive(gridId, value) {
@@ -329,41 +420,32 @@
329420
var cacheKey = bookName + "|" + chapter + "|" + translationKey;
330421
if (state.chapterCache[cacheKey]) return state.chapterCache[cacheKey];
331422

332-
var sample = (window.SAMPLE_BIBLE_DATA || {}).translations || {};
333-
334-
if (translationKey === "kjv") {
335-
var bookMeta = state.booksMap[bookName];
336-
if (bookMeta) {
337-
try {
338-
var res = await fetch("bible-data/" + bookMeta.file);
339-
if (res.ok) {
340-
var raw = await res.json();
341-
var data = extractChapter(raw, bookName, chapter);
342-
if (data && Object.keys(data).length) {
343-
state.chapterCache[cacheKey] = data;
344-
return data;
345-
}
346-
}
347-
} catch (_) { }
348-
}
423+
var bookMeta = state.booksMap[bookName];
424+
if (!bookMeta) return null;
425+
426+
// All translations now live at bible-data/{translationKey}/{Book}.json
427+
// NKJV / NIV / ESV files are stubs (chapters:[]) until full data is added
428+
if (STUB_TRANSLATIONS.has(translationKey)) {
429+
return null; // stubs have no verse content yet
349430
}
350431

351-
var translationData = sample[translationKey] || {};
352-
var bookData = translationData[bookName] || {};
353-
var chData = bookData[String(chapter)] || null;
432+
var filePath = "bible-data/" + translationKey + "/" + bookMeta.file;
433+
try {
434+
var res = await fetch(filePath);
435+
if (!res.ok) return null;
436+
var raw = await res.json();
354437

355-
if (chData) {
356-
state.chapterCache[cacheKey] = chData;
357-
return chData;
358-
}
438+
// Stub check: placeholder files have no chapters
439+
if (raw && raw.status === "placeholder") return null;
359440

360-
return null;
361-
}
441+
var data = extractChapter(raw, bookName, chapter);
442+
if (data && Object.keys(data).length) {
443+
state.chapterCache[cacheKey] = data;
444+
return data;
445+
}
446+
} catch (_) {}
362447

363-
function setCombinedSelection(bookName, chapter) {
364-
const sel = q("book-chapter-select");
365-
if (!sel || !bookName || !chapter) return;
366-
sel.value = bookName + "|" + chapter;
448+
return null;
367449
}
368450

369451
/* ============================================================
@@ -1067,22 +1149,38 @@
10671149
* Bootstrap
10681150
* ============================================================ */
10691151
async function init() {
1070-
const sampleData = window.SAMPLE_BIBLE_DATA || {};
1071-
state.sermons = sampleData.sermons || [];
1072-
state.verses = sampleData.verses || [];
1073-
10741152
await loadBooks();
10751153

1076-
const translationSel = q("translation-select");
1154+
// Load sermons for the related-content panel
1155+
try {
1156+
var sermonsRes = await fetch("assets/data/sermons.json");
1157+
if (sermonsRes.ok) state.sermons = await sermonsRes.json();
1158+
} catch (_) {}
1159+
1160+
// Build daily-verse pool from devotions
1161+
try {
1162+
var devRes = await fetch("assets/data/devotions.json");
1163+
if (devRes.ok) {
1164+
var devotions = await devRes.json();
1165+
state.verses = Array.isArray(devotions)
1166+
? devotions.map(function (d) {
1167+
return { reference: d.scripture || d.reference || "", text: d.reflection || d.text || "" };
1168+
})
1169+
: [];
1170+
}
1171+
} catch (_) {}
1172+
1173+
state.tamilData = null; // Loaded lazily on first Tamil PV request
1174+
1175+
var translationSel = q("translation-select");
10771176
if (translationSel) translationSel.value = state.primaryTranslation;
10781177

10791178
populateBookSelect();
10801179
bindEvents();
10811180
renderDailyVerse();
10821181
updateRelatedSermons();
10831182

1084-
// Populate related sermons placeholder with default text
1085-
const rSermons = q("related-sermons");
1183+
var rSermons = q("related-sermons");
10861184
if (rSermons) rSermons.innerHTML = '<p class="muted">Select a passage to see related sermons.</p>';
10871185
}
10881186

bible-data/esv/1Chronicles.json

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
{
2+
"book": "1 Chronicles",
3+
"translation": "esv",
4+
"status": "placeholder",
5+
"note": "Text not bundled in this repo. Add licensed/public-domain text for this translation.",
6+
"chapters": [
7+
{
8+
"chapter": 1,
9+
"verses": []
10+
},
11+
{
12+
"chapter": 2,
13+
"verses": []
14+
},
15+
{
16+
"chapter": 3,
17+
"verses": []
18+
},
19+
{
20+
"chapter": 4,
21+
"verses": []
22+
},
23+
{
24+
"chapter": 5,
25+
"verses": []
26+
},
27+
{
28+
"chapter": 6,
29+
"verses": []
30+
},
31+
{
32+
"chapter": 7,
33+
"verses": []
34+
},
35+
{
36+
"chapter": 8,
37+
"verses": []
38+
},
39+
{
40+
"chapter": 9,
41+
"verses": []
42+
},
43+
{
44+
"chapter": 10,
45+
"verses": []
46+
},
47+
{
48+
"chapter": 11,
49+
"verses": []
50+
},
51+
{
52+
"chapter": 12,
53+
"verses": []
54+
},
55+
{
56+
"chapter": 13,
57+
"verses": []
58+
},
59+
{
60+
"chapter": 14,
61+
"verses": []
62+
},
63+
{
64+
"chapter": 15,
65+
"verses": []
66+
},
67+
{
68+
"chapter": 16,
69+
"verses": []
70+
},
71+
{
72+
"chapter": 17,
73+
"verses": []
74+
},
75+
{
76+
"chapter": 18,
77+
"verses": []
78+
},
79+
{
80+
"chapter": 19,
81+
"verses": []
82+
},
83+
{
84+
"chapter": 20,
85+
"verses": []
86+
},
87+
{
88+
"chapter": 21,
89+
"verses": []
90+
},
91+
{
92+
"chapter": 22,
93+
"verses": []
94+
},
95+
{
96+
"chapter": 23,
97+
"verses": []
98+
},
99+
{
100+
"chapter": 24,
101+
"verses": []
102+
},
103+
{
104+
"chapter": 25,
105+
"verses": []
106+
},
107+
{
108+
"chapter": 26,
109+
"verses": []
110+
},
111+
{
112+
"chapter": 27,
113+
"verses": []
114+
},
115+
{
116+
"chapter": 28,
117+
"verses": []
118+
},
119+
{
120+
"chapter": 29,
121+
"verses": []
122+
}
123+
]
124+
}

0 commit comments

Comments
 (0)