Phase 5 publish LibreBible catalog page
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.0 - 2026-07-12
|
||||
|
||||
- Phase 5 ChristIT.com catalog: added a public `/librebible/` page that reads a generated LibreBible catalog JSON snapshot and displays available Bible resources.
|
||||
- Added a catalog sync script for copying generated LibreBible metadata from the sibling `libre-bible-data` workspace.
|
||||
- Added LibreBible to the Christ IT homepage project directory.
|
||||
@@ -9,7 +9,13 @@ This repo tracks the public site files for `https://christit.com`. Runtime or ge
|
||||
- Use Git for normal rollback and history.
|
||||
- Keep generated catalogs, service data, and private backend surfaces out of this repo.
|
||||
- If a risky manual edit needs a temporary snapshot, place it in an external archive safe outside the repo after the matching Git commit is pushed.
|
||||
- Public static catalog snapshots may be committed when they are intentionally part of the public site surface.
|
||||
- LibreBible catalog metadata is synced from the sibling `libre-bible-data` workspace with `scripts/sync-librebible-catalog.ps1`.
|
||||
- The public LibreBible page reads `librebible/catalog/catalog.json`; do not hand-edit that JSON except for emergency repair.
|
||||
- Phase-level site work should update `VERSION`, `CHANGELOG.md`, commit locally, and push to Gitea.
|
||||
|
||||
## Current Direction
|
||||
|
||||
The homepage should stay small, fast, and static. It should introduce Christ IT as technical service for the kingdom of Jesus Christ and link to active public projects such as Technical Services Exchange, GracePress, the public Git platform, ChristP2P, and Jason Eugene Garrison's resume site.
|
||||
|
||||
`/librebible/` is the public catalog page for free Bible translation and study-resource metadata prepared by the LibreBible data repository.
|
||||
|
||||
@@ -398,6 +398,7 @@
|
||||
<div class="nav-actions">
|
||||
<div class="nav-links" aria-label="Primary navigation">
|
||||
<a href="#projects">Projects</a>
|
||||
<a href="librebible/">LibreBible</a>
|
||||
<a href="#mission">Mission</a>
|
||||
</div>
|
||||
<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Toggle dark mode"></button>
|
||||
@@ -452,6 +453,14 @@
|
||||
</div>
|
||||
<span class="project-link">View repos <i class="fa-solid fa-arrow-right"></i></span>
|
||||
</a>
|
||||
<a class="project-card" href="librebible/">
|
||||
<div class="project-top">
|
||||
<div class="project-icon"><i class="fa-solid fa-book-bible"></i></div>
|
||||
<h3>LibreBible</h3>
|
||||
<p>Public catalog of free Bible translations and study-resource metadata for Libre Study and future tools.</p>
|
||||
</div>
|
||||
<span class="project-link">Open catalog <i class="fa-solid fa-arrow-right"></i></span>
|
||||
</a>
|
||||
<a class="project-card" href="https://git.christit.com">
|
||||
<div class="project-top">
|
||||
<div class="project-icon"><i class="fa-solid fa-code-branch"></i></div>
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,25 @@
|
||||
param(
|
||||
[string] $LibreBibleDataRoot = (Resolve-Path "$PSScriptRoot\..\..\..\libre-bible-data").Path,
|
||||
[string] $SiteRoot = (Resolve-Path "$PSScriptRoot\..").Path
|
||||
)
|
||||
|
||||
$sourceCatalogRoot = Join-Path $LibreBibleDataRoot "packages\json"
|
||||
$targetCatalogRoot = Join-Path $SiteRoot "librebible\catalog"
|
||||
|
||||
if (-not (Test-Path (Join-Path $sourceCatalogRoot "catalog.json"))) {
|
||||
throw "LibreBible catalog not found at $sourceCatalogRoot"
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $targetCatalogRoot | Out-Null
|
||||
Copy-Item -LiteralPath (Join-Path $sourceCatalogRoot "catalog.json") -Destination (Join-Path $targetCatalogRoot "catalog.json") -Force
|
||||
|
||||
Get-ChildItem -LiteralPath $sourceCatalogRoot -Directory | ForEach-Object {
|
||||
$resourceCatalog = Join-Path $_.FullName "catalog.json"
|
||||
if (Test-Path $resourceCatalog) {
|
||||
$targetResourceDir = Join-Path $targetCatalogRoot $_.Name
|
||||
New-Item -ItemType Directory -Force -Path $targetResourceDir | Out-Null
|
||||
Copy-Item -LiteralPath $resourceCatalog -Destination (Join-Path $targetResourceDir "catalog.json") -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Synced LibreBible catalog metadata to $targetCatalogRoot"
|
||||
Reference in New Issue
Block a user