Phase 5 publish LibreBible catalog page
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"schema_version": "librebible.index-catalog.v1",
|
||||
"project": "LibreBible",
|
||||
"generated_at": "2026-07-12T03:10:02.881Z",
|
||||
"resources": [
|
||||
{
|
||||
"id": "kjv-eng-kjv2006",
|
||||
"resource_type": "translation",
|
||||
"title": "King James (Authorized) Version",
|
||||
"short_title": "King James Version",
|
||||
"abbreviation": "KJV",
|
||||
"alternate_ids": [
|
||||
"ENGKJV",
|
||||
"eng-kjv2006"
|
||||
],
|
||||
"language": {
|
||||
"code": "eng",
|
||||
"name": "English",
|
||||
"dialect": "archaic British"
|
||||
},
|
||||
"script": "Latn",
|
||||
"canon": {
|
||||
"scope": "protocanon",
|
||||
"notes": "eBible describes this package as protocanon only."
|
||||
},
|
||||
"translation": {
|
||||
"base_title": "King James Version",
|
||||
"edition": "1769 standardized text with Strong's numbers added",
|
||||
"translation_year": 1611,
|
||||
"edition_year": 1769,
|
||||
"source_text_basis": "Authorized Version / King James Version standardized text of 1769",
|
||||
"tradition": "Protestant",
|
||||
"public_description": "The King James Version or Authorized Version of the Holy Bible, using the standardized text of 1769, protocanon only, with Strong's numbers added."
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "King James Version translators",
|
||||
"role": "translation"
|
||||
},
|
||||
{
|
||||
"name": "CrossWire Bible Society",
|
||||
"role": "source text provider"
|
||||
},
|
||||
{
|
||||
"name": "eBible.org",
|
||||
"role": "publisher and package provider"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "bible-text",
|
||||
"type": "translation_text",
|
||||
"label": "Bible text",
|
||||
"languages": [
|
||||
"eng"
|
||||
],
|
||||
"embedded": true
|
||||
},
|
||||
{
|
||||
"id": "strongs-links",
|
||||
"type": "concordance_links",
|
||||
"label": "Strong's-linked words",
|
||||
"languages": [
|
||||
"hebrew",
|
||||
"aramaic",
|
||||
"greek"
|
||||
],
|
||||
"systems": [
|
||||
"strongs"
|
||||
],
|
||||
"embedded": true,
|
||||
"package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl"
|
||||
},
|
||||
{
|
||||
"id": "usfm-source",
|
||||
"type": "source_format",
|
||||
"label": "USFM source",
|
||||
"format": "usfm",
|
||||
"embedded": false
|
||||
}
|
||||
],
|
||||
"attachments": {
|
||||
"included": [
|
||||
{
|
||||
"id": "kjv-eng-kjv2006-strongs-links",
|
||||
"resource_type": "concordance_links",
|
||||
"label": "Strong's links",
|
||||
"relationship": "word-to-strongs",
|
||||
"anchor_types": [
|
||||
"verse",
|
||||
"word",
|
||||
"strongs_number"
|
||||
],
|
||||
"languages": [
|
||||
"hebrew",
|
||||
"aramaic",
|
||||
"greek"
|
||||
],
|
||||
"systems": [
|
||||
"strongs"
|
||||
],
|
||||
"source": "Embedded in the eBible USFM package.",
|
||||
"package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl"
|
||||
}
|
||||
],
|
||||
"supported_future_types": [
|
||||
"study_notes",
|
||||
"commentary",
|
||||
"cross_references",
|
||||
"morphology",
|
||||
"lemma_links",
|
||||
"lexicon",
|
||||
"dictionary",
|
||||
"maps",
|
||||
"timeline",
|
||||
"media"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"provider": "eBible.org",
|
||||
"url": "https://ebible.org/find/show.php?id=eng-kjv2006",
|
||||
"download_url": "https://ebible.org/Scriptures/eng-kjv2006_usfm.zip",
|
||||
"format": "usfm-zip",
|
||||
"upstream_id": "eng-kjv2006",
|
||||
"upstream_last_updated": "2026-05-16",
|
||||
"available_formats": [
|
||||
"browser",
|
||||
"mobile-html",
|
||||
"epub",
|
||||
"pdf",
|
||||
"sword",
|
||||
"plain-text",
|
||||
"vpl-sql",
|
||||
"browser-bible",
|
||||
"usfx",
|
||||
"usfm",
|
||||
"xetex"
|
||||
]
|
||||
},
|
||||
"license": {
|
||||
"name": "Public Domain",
|
||||
"redistribution": true,
|
||||
"jurisdiction_notes": "eBible states this work is firmly public domain outside the United Kingdom; UK printing/import may be restricted by Crown letters patent.",
|
||||
"source_license_url": "https://ebible.org/find/show.php?id=eng-kjv2006",
|
||||
"attribution": "This free text is provided courtesy of CrossWire Bible Society and eBible.org.",
|
||||
"public_domain_outside": [
|
||||
"United Kingdom"
|
||||
],
|
||||
"restricted_notes": "Printing this translation in the United Kingdom or importing printed copies into the UK may require permission from the Crown patent holders."
|
||||
},
|
||||
"catalog_display": {
|
||||
"primary_features": [
|
||||
"Bible text",
|
||||
"Strong's-linked words",
|
||||
"USFM source"
|
||||
],
|
||||
"summary": "Public-domain KJV package based on the 1769 standardized text, with Strong's numbers embedded in the source USFM."
|
||||
},
|
||||
"package_path": "packages/json/kjv-eng-kjv2006/catalog.json",
|
||||
"source_manifest_path": "sources/kjv-eng-kjv2006.json",
|
||||
"detail_doc_path": "docs/resources/kjv-eng-kjv2006.md",
|
||||
"counts": {
|
||||
"books": 66,
|
||||
"verses": 31102,
|
||||
"strongs_links": 348884
|
||||
},
|
||||
"files": {
|
||||
"verses_jsonl": {
|
||||
"path": "verses.jsonl",
|
||||
"bytes": 8700726,
|
||||
"sha256": "e3102f854a99c4788ed259ec61cb93fea830845c0788c8c0929bc77e9db6ca10"
|
||||
},
|
||||
"strongs_jsonl": {
|
||||
"path": "strongs-links.jsonl",
|
||||
"bytes": 62690394,
|
||||
"sha256": "fa9702224776509275ea17fb245cb72150f1c262c4fbe44c7161e8e83866c779"
|
||||
}
|
||||
},
|
||||
"checks": {
|
||||
"expected_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d",
|
||||
"last_checked_at": "2026-07-12T02:18:30Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"schema_version": "librebible.resource-catalog.v1",
|
||||
"project": "LibreBible",
|
||||
"id": "kjv-eng-kjv2006",
|
||||
"resource_type": "translation",
|
||||
"title": "King James (Authorized) Version",
|
||||
"short_title": "King James Version",
|
||||
"abbreviation": "KJV",
|
||||
"alternate_ids": [
|
||||
"ENGKJV",
|
||||
"eng-kjv2006"
|
||||
],
|
||||
"language": {
|
||||
"code": "eng",
|
||||
"name": "English",
|
||||
"dialect": "archaic British"
|
||||
},
|
||||
"script": "Latn",
|
||||
"canon": {
|
||||
"scope": "protocanon",
|
||||
"notes": "eBible describes this package as protocanon only."
|
||||
},
|
||||
"translation": {
|
||||
"base_title": "King James Version",
|
||||
"edition": "1769 standardized text with Strong's numbers added",
|
||||
"translation_year": 1611,
|
||||
"edition_year": 1769,
|
||||
"source_text_basis": "Authorized Version / King James Version standardized text of 1769",
|
||||
"tradition": "Protestant",
|
||||
"public_description": "The King James Version or Authorized Version of the Holy Bible, using the standardized text of 1769, protocanon only, with Strong's numbers added."
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "King James Version translators",
|
||||
"role": "translation"
|
||||
},
|
||||
{
|
||||
"name": "CrossWire Bible Society",
|
||||
"role": "source text provider"
|
||||
},
|
||||
{
|
||||
"name": "eBible.org",
|
||||
"role": "publisher and package provider"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "bible-text",
|
||||
"type": "translation_text",
|
||||
"label": "Bible text",
|
||||
"languages": [
|
||||
"eng"
|
||||
],
|
||||
"embedded": true
|
||||
},
|
||||
{
|
||||
"id": "strongs-links",
|
||||
"type": "concordance_links",
|
||||
"label": "Strong's-linked words",
|
||||
"languages": [
|
||||
"hebrew",
|
||||
"aramaic",
|
||||
"greek"
|
||||
],
|
||||
"systems": [
|
||||
"strongs"
|
||||
],
|
||||
"embedded": true,
|
||||
"package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl"
|
||||
},
|
||||
{
|
||||
"id": "usfm-source",
|
||||
"type": "source_format",
|
||||
"label": "USFM source",
|
||||
"format": "usfm",
|
||||
"embedded": false
|
||||
}
|
||||
],
|
||||
"attachments": {
|
||||
"included": [
|
||||
{
|
||||
"id": "kjv-eng-kjv2006-strongs-links",
|
||||
"resource_type": "concordance_links",
|
||||
"label": "Strong's links",
|
||||
"relationship": "word-to-strongs",
|
||||
"anchor_types": [
|
||||
"verse",
|
||||
"word",
|
||||
"strongs_number"
|
||||
],
|
||||
"languages": [
|
||||
"hebrew",
|
||||
"aramaic",
|
||||
"greek"
|
||||
],
|
||||
"systems": [
|
||||
"strongs"
|
||||
],
|
||||
"source": "Embedded in the eBible USFM package.",
|
||||
"package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl"
|
||||
}
|
||||
],
|
||||
"supported_future_types": [
|
||||
"study_notes",
|
||||
"commentary",
|
||||
"cross_references",
|
||||
"morphology",
|
||||
"lemma_links",
|
||||
"lexicon",
|
||||
"dictionary",
|
||||
"maps",
|
||||
"timeline",
|
||||
"media"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"provider": "eBible.org",
|
||||
"url": "https://ebible.org/find/show.php?id=eng-kjv2006",
|
||||
"download_url": "https://ebible.org/Scriptures/eng-kjv2006_usfm.zip",
|
||||
"format": "usfm-zip",
|
||||
"upstream_id": "eng-kjv2006",
|
||||
"upstream_last_updated": "2026-05-16",
|
||||
"available_formats": [
|
||||
"browser",
|
||||
"mobile-html",
|
||||
"epub",
|
||||
"pdf",
|
||||
"sword",
|
||||
"plain-text",
|
||||
"vpl-sql",
|
||||
"browser-bible",
|
||||
"usfx",
|
||||
"usfm",
|
||||
"xetex"
|
||||
]
|
||||
},
|
||||
"license": {
|
||||
"name": "Public Domain",
|
||||
"redistribution": true,
|
||||
"jurisdiction_notes": "eBible states this work is firmly public domain outside the United Kingdom; UK printing/import may be restricted by Crown letters patent.",
|
||||
"source_license_url": "https://ebible.org/find/show.php?id=eng-kjv2006",
|
||||
"attribution": "This free text is provided courtesy of CrossWire Bible Society and eBible.org.",
|
||||
"public_domain_outside": [
|
||||
"United Kingdom"
|
||||
],
|
||||
"restricted_notes": "Printing this translation in the United Kingdom or importing printed copies into the UK may require permission from the Crown patent holders."
|
||||
},
|
||||
"catalog_display": {
|
||||
"primary_features": [
|
||||
"Bible text",
|
||||
"Strong's-linked words",
|
||||
"USFM source"
|
||||
],
|
||||
"summary": "Public-domain KJV package based on the 1769 standardized text, with Strong's numbers embedded in the source USFM."
|
||||
},
|
||||
"importer": {
|
||||
"name": "scripts/import-usfm.js",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"generated_at": "2026-07-12T03:10:02.881Z",
|
||||
"source_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d",
|
||||
"checks": {
|
||||
"expected_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d",
|
||||
"last_checked_at": "2026-07-12T02:18:30Z"
|
||||
},
|
||||
"counts": {
|
||||
"books": 66,
|
||||
"verses": 31102,
|
||||
"strongs_links": 348884
|
||||
},
|
||||
"files": {
|
||||
"verses_jsonl": {
|
||||
"path": "verses.jsonl",
|
||||
"bytes": 8700726,
|
||||
"sha256": "e3102f854a99c4788ed259ec61cb93fea830845c0788c8c0929bc77e9db6ca10"
|
||||
},
|
||||
"strongs_jsonl": {
|
||||
"path": "strongs-links.jsonl",
|
||||
"bytes": 62690394,
|
||||
"sha256": "fa9702224776509275ea17fb245cb72150f1c262c4fbe44c7161e8e83866c779"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LibreBible Catalog | Christ IT</title>
|
||||
<meta name="description" content="Public catalog of free Bible translation resources prepared for Libre Study and other Christ IT tools.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='12' fill='%23111827'/%3E%3Crect x='29' y='10' width='8' height='44' rx='3' fill='%23f8fafc'/%3E%3Crect x='16' y='25' width='34' height='8' rx='3' fill='%23f97316'/%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Oswald:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #fbfaf7;
|
||||
--surface: #ffffff;
|
||||
--surface-soft: #eef5f2;
|
||||
--ink: #151d2f;
|
||||
--body: #526071;
|
||||
--muted: #7b8794;
|
||||
--line: #dce4e7;
|
||||
--blue: #1265b3;
|
||||
--green: #1e7a5f;
|
||||
--orange: #d66b1f;
|
||||
--red: #a43e3e;
|
||||
--shadow: 0 14px 38px rgba(21, 29, 47, 0.10);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--body);
|
||||
font-family: "Inter", Arial, sans-serif;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
a { color: inherit; text-decoration: none; }
|
||||
.container { width: min(1120px, calc(100% - 40px)); margin: 0 auto; }
|
||||
|
||||
nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
background: rgba(251, 250, 247, 0.94);
|
||||
border-bottom: 1px solid var(--line);
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
.nav-inner {
|
||||
min-height: 74px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--ink);
|
||||
font-family: "Oswald", Impact, sans-serif;
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.brand-cross { position: relative; width: 26px; height: 32px; flex: 0 0 auto; }
|
||||
.brand-cross::before,
|
||||
.brand-cross::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-radius: 4px;
|
||||
background: var(--blue);
|
||||
}
|
||||
.brand-cross::before { width: 10px; height: 32px; left: 8px; top: 0; }
|
||||
.brand-cross::after { width: 26px; height: 10px; left: 0; top: 10px; }
|
||||
|
||||
.nav-links { display: flex; align-items: center; gap: 18px; font-size: 0.94rem; font-weight: 700; color: var(--body); }
|
||||
.nav-links a:hover { color: var(--blue); }
|
||||
|
||||
.hero {
|
||||
padding: 62px 0 42px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background:
|
||||
linear-gradient(135deg, rgba(18, 101, 179, 0.08), transparent 36%),
|
||||
linear-gradient(315deg, rgba(30, 122, 95, 0.11), transparent 34%);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
color: var(--green);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 0;
|
||||
color: var(--ink);
|
||||
font-family: "Oswald", Impact, sans-serif;
|
||||
line-height: 1.05;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1 {
|
||||
max-width: 860px;
|
||||
margin-top: 18px;
|
||||
font-size: clamp(3rem, 7vw, 5.8rem);
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
max-width: 760px;
|
||||
margin: 22px 0 0;
|
||||
padding-left: 22px;
|
||||
border-left: 5px solid var(--orange);
|
||||
font-size: clamp(1.04rem, 2vw, 1.22rem);
|
||||
}
|
||||
|
||||
.button-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
min-height: 46px;
|
||||
padding: 12px 18px;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 6px;
|
||||
background: var(--blue);
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
}
|
||||
.button.secondary {
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-color: var(--line);
|
||||
}
|
||||
|
||||
.section { padding: 54px 0; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.stat, .resource-card, .notice {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.stat { padding: 18px; }
|
||||
.stat span {
|
||||
display: block;
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.07em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.stat strong {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
color: var(--ink);
|
||||
font-size: 1.55rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
margin: 0 0 18px;
|
||||
}
|
||||
.toolbar h2 { font-size: clamp(2rem, 4.5vw, 3.2rem); }
|
||||
.status { color: var(--muted); font-weight: 700; }
|
||||
|
||||
.resource-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.resource-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.resource-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
.resource-card h3 { font-size: 1.55rem; }
|
||||
.resource-id {
|
||||
color: var(--muted);
|
||||
font-family: Consolas, "Liberation Mono", monospace;
|
||||
font-size: 0.84rem;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.badge-row, .feature-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.badge, .feature {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
min-height: 30px;
|
||||
padding: 5px 9px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface-soft);
|
||||
color: var(--ink);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
.feature { border-radius: 6px; background: #fff; }
|
||||
|
||||
.detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.detail {
|
||||
border-top: 1px solid var(--line);
|
||||
padding-top: 12px;
|
||||
}
|
||||
.detail span {
|
||||
display: block;
|
||||
color: var(--muted);
|
||||
font-size: 0.77rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.detail strong { color: var(--ink); font-size: 0.96rem; }
|
||||
|
||||
.notice {
|
||||
padding: 18px;
|
||||
color: var(--body);
|
||||
}
|
||||
.notice strong { color: var(--ink); }
|
||||
|
||||
footer {
|
||||
padding: 30px 0;
|
||||
border-top: 1px solid var(--line);
|
||||
color: var(--muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.nav-links { display: none; }
|
||||
.summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.detail-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.container { width: min(100% - 28px, 1120px); }
|
||||
.summary-grid { grid-template-columns: 1fr; }
|
||||
.resource-head { flex-direction: column; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<div class="container nav-inner">
|
||||
<a href="../index.html" class="brand-logo" aria-label="Christ IT home">
|
||||
<span class="brand-cross" aria-hidden="true"></span>
|
||||
<span>Christ IT</span>
|
||||
</a>
|
||||
<div class="nav-links" aria-label="Primary navigation">
|
||||
<a href="../index.html#projects">Projects</a>
|
||||
<a href="https://git.christit.com/libre-study/libre-bible-data">LibreBible Git</a>
|
||||
<a href="https://git.christit.com/libre-study/libre-study">Libre Study</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header class="hero">
|
||||
<div class="container">
|
||||
<span class="eyebrow"><i class="fa-solid fa-book-bible"></i> Public Bible resource catalog</span>
|
||||
<h1>LibreBible</h1>
|
||||
<p class="hero-copy">A growing catalog of free-to-use Bible translations and attached study resources prepared for Libre Study, GracePress, and future Christ IT tools.</p>
|
||||
<div class="button-row">
|
||||
<a class="button" href="https://git.christit.com/libre-study/libre-bible-data"><i class="fa-solid fa-code-branch"></i> Source Repository</a>
|
||||
<a class="button secondary" href="catalog/catalog.json"><i class="fa-solid fa-database"></i> Catalog JSON</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="section">
|
||||
<div class="container">
|
||||
<div class="summary-grid" id="summary" aria-live="polite">
|
||||
<div class="stat"><span>Resources</span><strong id="resource-count">-</strong></div>
|
||||
<div class="stat"><span>Translations</span><strong id="translation-count">-</strong></div>
|
||||
<div class="stat"><span>Verses</span><strong id="verse-count">-</strong></div>
|
||||
<div class="stat"><span>Strong's Links</span><strong id="strongs-count">-</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<h2>Available Resources</h2>
|
||||
<div class="status" id="catalog-status">Loading catalog...</div>
|
||||
</div>
|
||||
|
||||
<div class="resource-list" id="resource-list"></div>
|
||||
|
||||
<noscript>
|
||||
<div class="notice"><strong>JavaScript is required.</strong> This catalog page reads generated JSON metadata and renders the resource list in the browser.</div>
|
||||
</noscript>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container">All Glory to Jesus Christ. LibreBible catalog metadata is generated from the public LibreBible data repository.</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const catalogUrl = "catalog/catalog.json";
|
||||
const formatter = new Intl.NumberFormat("en-US");
|
||||
|
||||
function text(value, fallback = "Unknown") {
|
||||
return value === undefined || value === null || value === "" ? fallback : String(value);
|
||||
}
|
||||
|
||||
function number(value) {
|
||||
return Number.isFinite(value) ? formatter.format(value) : "-";
|
||||
}
|
||||
|
||||
function makeBadge(icon, label) {
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "badge";
|
||||
badge.innerHTML = `<i class="${icon}" aria-hidden="true"></i><span></span>`;
|
||||
badge.querySelector("span").textContent = label;
|
||||
return badge;
|
||||
}
|
||||
|
||||
function makeFeature(label) {
|
||||
const feature = document.createElement("span");
|
||||
feature.className = "feature";
|
||||
feature.textContent = label;
|
||||
return feature;
|
||||
}
|
||||
|
||||
function makeDetail(label, value) {
|
||||
const detail = document.createElement("div");
|
||||
detail.className = "detail";
|
||||
const caption = document.createElement("span");
|
||||
caption.textContent = label;
|
||||
const body = document.createElement("strong");
|
||||
body.textContent = value;
|
||||
detail.append(caption, body);
|
||||
return detail;
|
||||
}
|
||||
|
||||
function renderResource(resource) {
|
||||
const card = document.createElement("article");
|
||||
card.className = "resource-card";
|
||||
|
||||
const head = document.createElement("div");
|
||||
head.className = "resource-head";
|
||||
const titleBlock = document.createElement("div");
|
||||
const title = document.createElement("h3");
|
||||
title.textContent = text(resource.title, resource.id);
|
||||
const id = document.createElement("div");
|
||||
id.className = "resource-id";
|
||||
id.textContent = resource.id;
|
||||
titleBlock.append(title, id);
|
||||
|
||||
const repoLink = document.createElement("a");
|
||||
repoLink.className = "button secondary";
|
||||
const detailPath = resource.detail_doc_path || resource.package_path || "";
|
||||
repoLink.href = "https://git.christit.com/libre-study/libre-bible-data/src/branch/main/" +
|
||||
detailPath.split("/").map(encodeURIComponent).join("/");
|
||||
repoLink.textContent = "Details";
|
||||
head.append(titleBlock, repoLink);
|
||||
|
||||
const summary = document.createElement("p");
|
||||
summary.textContent = text(resource.catalog_display && resource.catalog_display.summary, resource.translation && resource.translation.public_description);
|
||||
|
||||
const badges = document.createElement("div");
|
||||
badges.className = "badge-row";
|
||||
badges.append(
|
||||
makeBadge("fa-solid fa-language", `${text(resource.language && resource.language.name)}${resource.language && resource.language.dialect ? " / " + resource.language.dialect : ""}`),
|
||||
makeBadge("fa-solid fa-scale-balanced", text(resource.license && resource.license.name)),
|
||||
makeBadge("fa-solid fa-book-open", text(resource.canon && resource.canon.scope))
|
||||
);
|
||||
|
||||
const features = document.createElement("div");
|
||||
features.className = "feature-row";
|
||||
const featureLabels = (resource.catalog_display && resource.catalog_display.primary_features) || (resource.features || []).map((feature) => feature.label);
|
||||
featureLabels.slice(0, 8).forEach((label) => features.append(makeFeature(label)));
|
||||
|
||||
const details = document.createElement("div");
|
||||
details.className = "detail-grid";
|
||||
details.append(
|
||||
makeDetail("Translation", `${text(resource.translation && resource.translation.base_title)} (${text(resource.translation && resource.translation.translation_year)})`),
|
||||
makeDetail("Edition", `${text(resource.translation && resource.translation.edition)}${resource.translation && resource.translation.edition_year ? " / " + resource.translation.edition_year : ""}`),
|
||||
makeDetail("Source", `${text(resource.source && resource.source.provider)} / ${text(resource.source && resource.source.upstream_id)}`),
|
||||
makeDetail("Counts", `${number(resource.counts && resource.counts.verses)} verses, ${number(resource.counts && resource.counts.strongs_links)} Strong's links`)
|
||||
);
|
||||
|
||||
card.append(head, summary, badges, features, details);
|
||||
return card;
|
||||
}
|
||||
|
||||
function renderCatalog(catalog) {
|
||||
const resources = Array.isArray(catalog.resources) ? catalog.resources : [];
|
||||
const translations = resources.filter((resource) => resource.resource_type === "translation");
|
||||
const verseTotal = resources.reduce((sum, resource) => sum + (resource.counts && Number(resource.counts.verses) || 0), 0);
|
||||
const strongsTotal = resources.reduce((sum, resource) => sum + (resource.counts && Number(resource.counts.strongs_links) || 0), 0);
|
||||
|
||||
document.getElementById("resource-count").textContent = number(resources.length);
|
||||
document.getElementById("translation-count").textContent = number(translations.length);
|
||||
document.getElementById("verse-count").textContent = number(verseTotal);
|
||||
document.getElementById("strongs-count").textContent = number(strongsTotal);
|
||||
document.getElementById("catalog-status").textContent = `Generated ${text(catalog.generated_at)}`;
|
||||
|
||||
const list = document.getElementById("resource-list");
|
||||
list.replaceChildren(...resources.map(renderResource));
|
||||
|
||||
if (!resources.length) {
|
||||
const empty = document.createElement("div");
|
||||
empty.className = "notice";
|
||||
empty.innerHTML = "<strong>No resources found.</strong> The catalog loaded, but did not include any resource entries.";
|
||||
list.append(empty);
|
||||
}
|
||||
}
|
||||
|
||||
fetch(catalogUrl, { cache: "no-cache" })
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Catalog request failed: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(renderCatalog)
|
||||
.catch((error) => {
|
||||
document.getElementById("catalog-status").textContent = "Catalog unavailable";
|
||||
const list = document.getElementById("resource-list");
|
||||
const notice = document.createElement("div");
|
||||
notice.className = "notice";
|
||||
notice.innerHTML = `<strong>Catalog could not be loaded.</strong> ${error.message}`;
|
||||
list.replaceChildren(notice);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user