// Bible tab — King James 1611, served entirely from the local CSV (offline, instant). // Floating navigator (BIBLE App Labs style): book search + book/chapter/verse pickers + All/OT/NT + GO. function BibleTab(){ const meta = window.BIBLE_BOOKS; const testOf = React.useMemo(()=>{ const m={}; meta.forEach(b=>m[b.name]=b.testament); return m; }, [meta]); const [bible, setBible] = React.useState(null); // { data, order, chapterCount } const [loadErr, setLoadErr] = React.useState(''); const [ref, setRef] = React.useState({ book:'Genesis', chapter:1, verse:1 }); const [open, setOpen] = React.useState(false); const scrollRef = React.useRef(null); // panel working selection const [test, setTest] = React.useState('All'); const [selBook, setSelBook] = React.useState('Genesis'); const [selCh, setSelCh] = React.useState(1); const [selV, setSelV] = React.useState(1); const [query, setQuery] = React.useState(''); const [fontScale, setFontScale] = React.useState(()=> parseFloat(localStorage.getItem('cwa-biblefont')||'1') || 1); React.useEffect(()=>{ localStorage.setItem('cwa-biblefont', String(fontScale)); }, [fontScale]); const bump = (d)=> setFontScale(s=> Math.min(1.9, Math.max(0.8, Math.round((s+d)*10)/10))); React.useEffect(()=>{ let alive = true; window.loadBible().then(b=>{ if(alive){ setBible(b); } }) .catch(()=>{ if(alive) setLoadErr('Could not load the Bible file (uploads/kjv1611_full.csv).'); }); return ()=>{ alive=false; }; }, []); const verses = bible && bible.data[ref.book] && bible.data[ref.book][ref.chapter] ? bible.data[ref.book][ref.chapter] : []; const chCount = bible ? bible.chapterCount(selBook) : 1; const chapters = Array.from({length: Math.max(chCount,1)}, (_,n)=>n+1); const vCount = bible && bible.data[selBook] && bible.data[selBook][selCh] ? bible.data[selBook][selCh].length : 1; const verseList = Array.from({length: Math.max(vCount,1)}, (_,n)=>n+1); const order = bible ? bible.order : meta.map(b=>b.name); const filtered = order.filter(name => (test==='All' || testOf[name]===test) && name.toLowerCase().includes(query.toLowerCase())); function go(book, chapter, verse){ setRef({ book, chapter, verse }); setOpen(false); requestAnimationFrame(()=>{ const el = scrollRef.current; if(!el) return; el.scrollTop = 0; if(verse>1){ const t = el.querySelector(`[data-v="${verse}"]`); if(t) el.scrollTop = t.offsetTop - 30; } }); } function openPanel(){ setSelBook(ref.book); setSelCh(ref.chapter); setSelV(ref.verse); setQuery(''); setOpen(o=>!o); } return (
{v.verse}{v.text}
))} {bible && !verses.length && !loadErr &&