Add global resource and reading plan PDF exports

This commit is contained in:
2025-11-26 01:38:55 -05:00
parent 87b31f7b6a
commit 776e39370e
16 changed files with 1161 additions and 28 deletions
+339
View File
@@ -147,6 +147,30 @@ def _resource_detail_pdf_response(
)
def _resource_index_pdf_response(resource_data: dict, page_title: str, page_subtitle: str, page_description: str):
"""Generate PDF for resource index-style pages."""
if not WEASYPRINT_AVAILABLE:
raise HTTPException(
status_code=503,
detail="PDF generation is not available. WeasyPrint system libraries are not installed."
)
html_content = templates.get_template("resource_index_pdf.html").render(
resource_data=resource_data,
page_title=page_title,
page_subtitle=page_subtitle,
page_description=page_description,
)
pdf_buffer = render_html_to_pdf(html_content)
filename = f"{create_slug(page_title)}.pdf"
return StreamingResponse(
pdf_buffer,
media_type="application/pdf",
headers={"Content-Disposition": f"attachment; filename={filename}"}
)
# ============================================================================
# BIBLICAL MAPS
# ============================================================================
@@ -180,6 +204,7 @@ def biblical_angels_page(request: Request):
{
"books": get_books(),
"angels_data": ANGELS_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -189,6 +214,16 @@ def biblical_angels_page(request: Request):
)
@router.get("/biblical-angels/pdf")
def biblical_angels_page_pdf():
return _resource_index_pdf_response(
ANGELS_DATA,
page_title="Biblical Angels",
page_subtitle="Heavenly messengers throughout Scripture",
page_description="Explore angels and angelic beings mentioned in the King James Bible, including Michael, Gabriel, and the heavenly host."
)
@router.get("/biblical-angels/{angel_slug}", response_class=HTMLResponse)
def angel_detail(request: Request, angel_slug: str):
"""Individual biblical angels detail page."""
@@ -226,6 +261,7 @@ def biblical_prophets_page(request: Request):
{
"books": get_books(),
"prophets_data": PROPHETS_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -235,6 +271,25 @@ def biblical_prophets_page(request: Request):
)
@router.get("/biblical-prophets/pdf")
def biblical_prophets_pdf():
"""PDF export for the prophets index."""
if not WEASYPRINT_AVAILABLE:
raise HTTPException(
status_code=503,
detail="PDF generation is not available. WeasyPrint system libraries are not installed."
)
html_content = templates.get_template("biblical_prophets_pdf.html").render(prophets_data=PROPHETS_DATA)
pdf_buffer = render_html_to_pdf(html_content)
return StreamingResponse(
pdf_buffer,
media_type="application/pdf",
headers={"Content-Disposition": "attachment; filename=biblical-prophets.pdf"}
)
@router.get("/biblical-prophets/{prophet_slug}", response_class=HTMLResponse)
def prophet_detail(request: Request, prophet_slug: str):
"""Individual biblical prophets detail page."""
@@ -272,6 +327,7 @@ def names_of_god_page(request: Request):
{
"books": get_books(),
"names_data": NAMES_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -281,6 +337,16 @@ def names_of_god_page(request: Request):
)
@router.get("/names-of-god/pdf")
def names_of_god_page_pdf():
return _resource_index_pdf_response(
NAMES_DATA,
page_title="Names of God",
page_subtitle="Divine titles revealed in Scripture",
page_description="Explore the revelation of God's names throughout Scripture and their meanings."
)
@router.get("/names-of-god/{name_slug}", response_class=HTMLResponse)
def name_of_god_detail(request: Request, name_slug: str):
"""Individual name of God detail page."""
@@ -384,6 +450,7 @@ def biblical_covenants_page(request: Request):
{
"books": get_books(),
"covenants_data": COVENANTS_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -393,6 +460,16 @@ def biblical_covenants_page(request: Request):
)
@router.get("/biblical-covenants/pdf")
def biblical_covenants_page_pdf():
return _resource_index_pdf_response(
COVENANTS_DATA,
page_title="Biblical Covenants",
page_subtitle="Divine promises across redemptive history",
page_description="Survey the major covenants established between God and His people throughout Scripture."
)
@router.get("/biblical-covenants/{covenant_slug}", response_class=HTMLResponse)
def covenant_detail(request: Request, covenant_slug: str):
"""Individual covenant detail page."""
@@ -430,6 +507,7 @@ def apostles_page(request: Request):
{
"books": get_books(),
"apostles_data": APOSTLES_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -439,6 +517,25 @@ def apostles_page(request: Request):
)
@router.get("/the-twelve-apostles/pdf")
def apostles_page_pdf():
"""PDF export for the apostles index."""
if not WEASYPRINT_AVAILABLE:
raise HTTPException(
status_code=503,
detail="PDF generation is not available. WeasyPrint system libraries are not installed."
)
html_content = templates.get_template("twelve_apostles_pdf.html").render(apostles_data=APOSTLES_DATA)
pdf_buffer = render_html_to_pdf(html_content)
return StreamingResponse(
pdf_buffer,
media_type="application/pdf",
headers={"Content-Disposition": "attachment; filename=twelve-apostles.pdf"}
)
@router.get("/the-twelve-apostles/{apostle_slug}", response_class=HTMLResponse)
def apostle_detail(request: Request, apostle_slug: str):
"""Individual apostle detail page."""
@@ -476,6 +573,7 @@ def women_of_the_bible_page(request: Request):
{
"books": get_books(),
"women_data": WOMEN_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -485,6 +583,16 @@ def women_of_the_bible_page(request: Request):
)
@router.get("/women-of-the-bible/pdf")
def women_of_the_bible_page_pdf():
return _resource_index_pdf_response(
WOMEN_DATA,
page_title="Women of the Bible",
page_subtitle="Faithful witnesses throughout redemptive history",
page_description="Explore the lives, faith, and legacies of notable women throughout Scripture."
)
@router.get("/women-of-the-bible/{woman_slug}", response_class=HTMLResponse)
def woman_detail(request: Request, woman_slug: str):
"""Individual woman of the Bible detail page."""
@@ -522,6 +630,7 @@ def biblical_festivals_page(request: Request):
{
"books": get_books(),
"festivals_data": FESTIVALS_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -531,6 +640,16 @@ def biblical_festivals_page(request: Request):
)
@router.get("/biblical-festivals/pdf")
def biblical_festivals_page_pdf():
return _resource_index_pdf_response(
FESTIVALS_DATA,
page_title="Biblical Festivals",
page_subtitle="Appointed feasts of the Lord",
page_description="Learn about the appointed feasts and holy days ordained in the Law of Moses."
)
@router.get("/biblical-festivals/{festival_slug}", response_class=HTMLResponse)
def festival_detail(request: Request, festival_slug: str):
"""Individual biblical festival detail page."""
@@ -568,6 +687,7 @@ def fruits_of_the_spirit_page(request: Request):
{
"books": get_books(),
"fruits_data": FRUITS_DATA,
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -577,6 +697,16 @@ def fruits_of_the_spirit_page(request: Request):
)
@router.get("/fruits-of-the-spirit/pdf")
def fruits_of_the_spirit_page_pdf():
return _resource_index_pdf_response(
FRUITS_DATA,
page_title="Fruits of the Spirit",
page_subtitle="Developing Christian character",
page_description="Meditate on the Spirit-produced virtues described in Galatians 5."
)
@router.get("/fruits-of-the-spirit/{fruit_slug}", response_class=HTMLResponse)
def fruit_detail(request: Request, fruit_slug: str):
"""Individual fruit of the Spirit detail page."""
@@ -681,6 +811,7 @@ def miracles_page(request: Request):
"page_subtitle": "Signs and Wonders Manifesting Divine Authority",
"page_description": "Explore the miracles of Jesus Christ recorded in the Gospels - healings, nature miracles, exorcisms, and raisings from the dead.",
"base_url": "/miracles-of-jesus",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -690,6 +821,16 @@ def miracles_page(request: Request):
)
@router.get("/miracles-of-jesus/pdf")
def miracles_page_pdf():
return _resource_index_pdf_response(
MIRACLES_DATA,
page_title="Miracles of Jesus",
page_subtitle="Signs and Wonders Manifesting Divine Authority",
page_description="Explore the miracles of Jesus Christ recorded in the Gospels - healings, nature miracles, exorcisms, and raisings from the dead."
)
@router.get("/miracles-of-jesus/{miracle_slug}", response_class=HTMLResponse)
def miracle_detail(request: Request, miracle_slug: str):
"""Individual miracle detail page."""
@@ -731,6 +872,7 @@ def prayers_page(request: Request):
"page_subtitle": "Sacred Conversations with the Almighty",
"page_description": "Explore the prayers recorded in Scripture - from the Psalms to the prayers of Jesus, Paul, and the early church.",
"base_url": "/prayers-of-the-bible",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -740,6 +882,16 @@ def prayers_page(request: Request):
)
@router.get("/prayers-of-the-bible/pdf")
def prayers_page_pdf():
return _resource_index_pdf_response(
PRAYERS_DATA,
page_title="Prayers of the Bible",
page_subtitle="Sacred Conversations with the Almighty",
page_description="Explore the prayers recorded in Scripture - from the Psalms to the prayers of Jesus, Paul, and the early church."
)
@router.get("/prayers-of-the-bible/{prayer_slug}", response_class=HTMLResponse)
def prayer_detail(request: Request, prayer_slug: str):
"""Individual prayer detail page."""
@@ -781,6 +933,7 @@ def beatitudes_page(request: Request):
"page_subtitle": "The Blessings of the Kingdom",
"page_description": "Explore the Beatitudes from Jesus's Sermon on the Mount - the foundational blessings that describe the character of kingdom citizens.",
"base_url": "/beatitudes",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -790,6 +943,16 @@ def beatitudes_page(request: Request):
)
@router.get("/beatitudes/pdf")
def beatitudes_page_pdf():
return _resource_index_pdf_response(
BEATITUDES_DATA,
page_title="The Beatitudes",
page_subtitle="The Blessings of the Kingdom",
page_description="Explore the Beatitudes from Jesus's Sermon on the Mount - the foundational blessings that describe the character of kingdom citizens."
)
@router.get("/beatitudes/{beatitude_slug}", response_class=HTMLResponse)
def beatitude_detail(request: Request, beatitude_slug: str):
"""Individual beatitude detail page."""
@@ -831,6 +994,7 @@ def ten_commandments_page(request: Request):
"page_subtitle": "The Moral Law of God",
"page_description": "Study the Ten Commandments given by God to Moses on Mount Sinai - the foundation of biblical morality and divine law.",
"base_url": "/ten-commandments",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -840,6 +1004,16 @@ def ten_commandments_page(request: Request):
)
@router.get("/ten-commandments/pdf")
def ten_commandments_page_pdf():
return _resource_index_pdf_response(
TEN_COMMANDMENTS_DATA,
page_title="The Ten Commandments",
page_subtitle="The Moral Law of God",
page_description="Study the Ten Commandments given by God to Moses on Mount Sinai - the foundation of biblical morality and divine law."
)
@router.get("/ten-commandments/{commandment_slug}", response_class=HTMLResponse)
def commandment_detail(request: Request, commandment_slug: str):
"""Individual commandment detail page."""
@@ -881,6 +1055,7 @@ def armor_of_god_page(request: Request):
"page_subtitle": "Divine Equipment for Spiritual Warfare",
"page_description": "Study the Armor of God from Ephesians 6 - the spiritual equipment believers need to stand against the wiles of the devil.",
"base_url": "/armor-of-god",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -890,6 +1065,16 @@ def armor_of_god_page(request: Request):
)
@router.get("/armor-of-god/pdf")
def armor_of_god_page_pdf():
return _resource_index_pdf_response(
ARMOR_OF_GOD_DATA,
page_title="The Armor of God",
page_subtitle="Divine Equipment for Spiritual Warfare",
page_description="Study the Armor of God from Ephesians 6 - the spiritual equipment believers need to stand against the wiles of the devil."
)
@router.get("/armor-of-god/{armor_slug}", response_class=HTMLResponse)
def armor_detail(request: Request, armor_slug: str):
"""Individual armor piece detail page."""
@@ -931,6 +1116,7 @@ def i_am_statements_page(request: Request):
"page_subtitle": "Divine Self-Revelations in the Gospel of John",
"page_description": "Explore the seven 'I Am' statements of Jesus in John's Gospel - profound declarations of His divine nature and mission.",
"base_url": "/i-am-statements",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -940,6 +1126,16 @@ def i_am_statements_page(request: Request):
)
@router.get("/i-am-statements/pdf")
def i_am_statements_page_pdf():
return _resource_index_pdf_response(
I_AM_STATEMENTS_DATA,
page_title="I Am Statements of Jesus",
page_subtitle="Divine Self-Revelations in the Gospel of John",
page_description="Explore the seven 'I Am' statements of Jesus in John's Gospel - profound declarations of His divine nature and mission."
)
@router.get("/i-am-statements/{statement_slug}", response_class=HTMLResponse)
def i_am_statement_detail(request: Request, statement_slug: str):
"""Individual I Am statement detail page."""
@@ -981,6 +1177,7 @@ def trinity_page(request: Request):
"page_subtitle": "The Doctrine of One God in Three Persons",
"page_description": "An expansive theological study of the Trinity - the doctrine that God eternally exists as Father, Son, and Holy Spirit, three distinct Persons sharing one divine essence.",
"base_url": "/trinity",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -990,6 +1187,16 @@ def trinity_page(request: Request):
)
@router.get("/trinity/pdf")
def trinity_page_pdf():
return _resource_index_pdf_response(
TRINITY_DATA,
page_title="The Trinity",
page_subtitle="The Doctrine of One God in Three Persons",
page_description="An expansive theological study of the Trinity - the doctrine that God eternally exists as Father, Son, and Holy Spirit, three distinct Persons sharing one divine essence."
)
@router.get("/trinity/{item_slug}", response_class=HTMLResponse)
def trinity_detail(request: Request, item_slug: str):
"""Individual Trinity topic detail page."""
@@ -1031,6 +1238,7 @@ def christology_page(request: Request):
"page_subtitle": "The Doctrine of the Person and Work of Christ",
"page_description": "An expansive theological study of Christology - the doctrine concerning Jesus Christ, His divine-human nature, His offices, and His saving work.",
"base_url": "/christology",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1040,6 +1248,16 @@ def christology_page(request: Request):
)
@router.get("/christology/pdf")
def christology_page_pdf():
return _resource_index_pdf_response(
CHRISTOLOGY_DATA,
page_title="Christology",
page_subtitle="The Doctrine of the Person and Work of Christ",
page_description="An expansive theological study of Christology - the doctrine concerning Jesus Christ, His divine-human nature, His offices, and His saving work."
)
@router.get("/christology/{item_slug}", response_class=HTMLResponse)
def christology_detail(request: Request, item_slug: str):
"""Individual Christology topic detail page."""
@@ -1081,6 +1299,7 @@ def soteriology_page(request: Request):
"page_subtitle": "The Doctrine of Salvation",
"page_description": "An expansive theological study of Soteriology - the doctrine of salvation, covering election, atonement, regeneration, justification, sanctification, and glorification.",
"base_url": "/soteriology",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1090,6 +1309,16 @@ def soteriology_page(request: Request):
)
@router.get("/soteriology/pdf")
def soteriology_page_pdf():
return _resource_index_pdf_response(
SOTERIOLOGY_DATA,
page_title="Soteriology",
page_subtitle="The Doctrine of Salvation",
page_description="An expansive theological study of Soteriology - the doctrine of salvation, covering election, atonement, regeneration, justification, sanctification, and glorification."
)
@router.get("/soteriology/{item_slug}", response_class=HTMLResponse)
def soteriology_detail(request: Request, item_slug: str):
"""Individual Soteriology topic detail page."""
@@ -1131,6 +1360,7 @@ def pneumatology_page(request: Request):
"page_subtitle": "The Doctrine of the Holy Spirit",
"page_description": "An expansive theological study of Pneumatology - the doctrine of the Holy Spirit, His person, deity, work in salvation, and ministry to believers.",
"base_url": "/pneumatology",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1140,6 +1370,16 @@ def pneumatology_page(request: Request):
)
@router.get("/pneumatology/pdf")
def pneumatology_page_pdf():
return _resource_index_pdf_response(
PNEUMATOLOGY_DATA,
page_title="Pneumatology",
page_subtitle="The Doctrine of the Holy Spirit",
page_description="An expansive theological study of Pneumatology - the doctrine of the Holy Spirit, His person, deity, work in salvation, and ministry to believers."
)
@router.get("/pneumatology/{item_slug}", response_class=HTMLResponse)
def pneumatology_detail(request: Request, item_slug: str):
"""Individual Pneumatology topic detail page."""
@@ -1181,6 +1421,7 @@ def eschatology_page(request: Request):
"page_subtitle": "The Doctrine of Last Things",
"page_description": "An expansive theological study of Eschatology - the doctrine of death, resurrection, the second coming of Christ, final judgment, and eternal destinies.",
"base_url": "/eschatology",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1190,6 +1431,16 @@ def eschatology_page(request: Request):
)
@router.get("/eschatology/pdf")
def eschatology_page_pdf():
return _resource_index_pdf_response(
ESCHATOLOGY_DATA,
page_title="Eschatology",
page_subtitle="The Doctrine of Last Things",
page_description="An expansive theological study of Eschatology - the doctrine of death, resurrection, the second coming of Christ, final judgment, and eternal destinies."
)
@router.get("/eschatology/{item_slug}", response_class=HTMLResponse)
def eschatology_detail(request: Request, item_slug: str):
"""Individual Eschatology topic detail page."""
@@ -1231,6 +1482,7 @@ def ecclesiology_page(request: Request):
"page_subtitle": "The Doctrine of the Church",
"page_description": "An expansive theological study of Ecclesiology - the doctrine of the church, its nature, marks, government, mission, and ordinances.",
"base_url": "/ecclesiology",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1240,6 +1492,16 @@ def ecclesiology_page(request: Request):
)
@router.get("/ecclesiology/pdf")
def ecclesiology_page_pdf():
return _resource_index_pdf_response(
ECCLESIOLOGY_DATA,
page_title="Ecclesiology",
page_subtitle="The Doctrine of the Church",
page_description="An expansive theological study of Ecclesiology - the doctrine of the church, its nature, marks, government, mission, and ordinances."
)
@router.get("/ecclesiology/{item_slug}", response_class=HTMLResponse)
def ecclesiology_detail(request: Request, item_slug: str):
"""Individual Ecclesiology topic detail page."""
@@ -1281,6 +1543,7 @@ def types_and_shadows_page(request: Request):
"page_subtitle": "Old Testament Figures Fulfilled in Christ",
"page_description": "An expansive study of Old Testament types and shadows pointing to Christ - persons, events, and institutions that prefigure and find their fulfillment in Jesus.",
"base_url": "/types-and-shadows",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1290,6 +1553,16 @@ def types_and_shadows_page(request: Request):
)
@router.get("/types-and-shadows/pdf")
def types_and_shadows_page_pdf():
return _resource_index_pdf_response(
TYPES_AND_SHADOWS_DATA,
page_title="Types and Shadows of Christ",
page_subtitle="Old Testament Figures Fulfilled in Christ",
page_description="An expansive study of Old Testament types and shadows pointing to Christ - persons, events, and institutions that prefigure and find their fulfillment in Jesus."
)
@router.get("/types-and-shadows/{item_slug}", response_class=HTMLResponse)
def types_and_shadows_detail(request: Request, item_slug: str):
"""Individual Types and Shadows topic detail page."""
@@ -1331,6 +1604,7 @@ def messianic_prophecies_page(request: Request):
"page_subtitle": "Old Testament Predictions Fulfilled in Christ",
"page_description": "An expansive study of Messianic prophecies - Old Testament predictions concerning the Messiah's coming, ministry, suffering, and triumph, all fulfilled in Jesus Christ.",
"base_url": "/messianic-prophecies",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1340,6 +1614,16 @@ def messianic_prophecies_page(request: Request):
)
@router.get("/messianic-prophecies/pdf")
def messianic_prophecies_page_pdf():
return _resource_index_pdf_response(
MESSIANIC_PROPHECIES_DATA,
page_title="Messianic Prophecies",
page_subtitle="Old Testament Predictions Fulfilled in Christ",
page_description="An expansive study of Messianic prophecies - Old Testament predictions concerning the Messiah's coming, ministry, suffering, and triumph, all fulfilled in Jesus Christ."
)
@router.get("/messianic-prophecies/{item_slug}", response_class=HTMLResponse)
def messianic_prophecies_detail(request: Request, item_slug: str):
"""Individual Messianic Prophecy topic detail page."""
@@ -1381,6 +1665,7 @@ def blood_in_scripture_page(request: Request):
"page_subtitle": "The Theology of Redemption Through Blood",
"page_description": "An expansive study of the blood in Scripture - its significance, Old Testament foundations, and ultimate fulfillment in the blood of Christ for redemption, justification, and cleansing.",
"base_url": "/blood-in-scripture",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1390,6 +1675,16 @@ def blood_in_scripture_page(request: Request):
)
@router.get("/blood-in-scripture/pdf")
def blood_in_scripture_page_pdf():
return _resource_index_pdf_response(
BLOOD_IN_SCRIPTURE_DATA,
page_title="The Blood in Scripture",
page_subtitle="The Theology of Redemption Through Blood",
page_description="An expansive study of the blood in Scripture - its significance, Old Testament foundations, and ultimate fulfillment in the blood of Christ for redemption, justification, and cleansing."
)
@router.get("/blood-in-scripture/{item_slug}", response_class=HTMLResponse)
def blood_in_scripture_detail(request: Request, item_slug: str):
"""Individual Blood in Scripture topic detail page."""
@@ -1431,6 +1726,7 @@ def kingdom_of_god_page(request: Request):
"page_subtitle": "The Reign of God Through Christ",
"page_description": "An expansive study of the Kingdom of God - its nature, King, entrance requirements, growth, and ultimate consummation at Christ's return.",
"base_url": "/kingdom-of-god",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1440,6 +1736,16 @@ def kingdom_of_god_page(request: Request):
)
@router.get("/kingdom-of-god/pdf")
def kingdom_of_god_page_pdf():
return _resource_index_pdf_response(
KINGDOM_OF_GOD_DATA,
page_title="The Kingdom of God",
page_subtitle="The Reign of God Through Christ",
page_description="An expansive study of the Kingdom of God - its nature, King, entrance requirements, growth, and ultimate consummation at Christ's return."
)
@router.get("/kingdom-of-god/{item_slug}", response_class=HTMLResponse)
def kingdom_of_god_detail(request: Request, item_slug: str):
"""Individual Kingdom of God topic detail page."""
@@ -1481,6 +1787,7 @@ def names_of_christ_page(request: Request):
"page_subtitle": "The Glorious Designations of Our Lord",
"page_description": "An expansive study of the names and titles of Jesus Christ - divine names, messianic titles, redemptive designations, and relational names revealing His person and work.",
"base_url": "/names-of-christ",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1490,6 +1797,16 @@ def names_of_christ_page(request: Request):
)
@router.get("/names-of-christ/pdf")
def names_of_christ_page_pdf():
return _resource_index_pdf_response(
NAMES_OF_CHRIST_DATA,
page_title="Names and Titles of Christ",
page_subtitle="The Glorious Designations of Our Lord",
page_description="An expansive study of the names and titles of Jesus Christ - divine names, messianic titles, redemptive designations, and relational names revealing His person and work."
)
@router.get("/names-of-christ/{item_slug}", response_class=HTMLResponse)
def names_of_christ_detail(request: Request, item_slug: str):
"""Individual Names of Christ topic detail page."""
@@ -1531,6 +1848,7 @@ def spirits_and_demons_page(request: Request):
"page_subtitle": "Biblical Demonology and Spiritual Warfare",
"page_description": "A comprehensive study of demons, Satan, evil spirits, and spiritual warfare in Scripture—from Legion to the Lake of Fire.",
"base_url": "/spirits-and-demons",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1540,6 +1858,16 @@ def spirits_and_demons_page(request: Request):
)
@router.get("/spirits-and-demons/pdf")
def spirits_and_demons_page_pdf():
return _resource_index_pdf_response(
SPIRITS_AND_DEMONS_DATA,
page_title="Spirits & Demons",
page_subtitle="Biblical Demonology and Spiritual Warfare",
page_description="A comprehensive study of demons, Satan, evil spirits, and spiritual warfare in Scripture—from Legion to the Lake of Fire."
)
@router.get("/spirits-and-demons/{item_slug}", response_class=HTMLResponse)
def spirits_and_demons_detail(request: Request, item_slug: str):
"""Individual Spirits and Demons topic detail page."""
@@ -1581,6 +1909,7 @@ def personifications_page(request: Request):
"page_subtitle": "Abstract Concepts Given Human Form",
"page_description": "A study of biblical personifications—Wisdom, Folly, Death, Sin, and other abstract concepts portrayed as persons throughout Scripture.",
"base_url": "/personifications",
"pdf_available": WEASYPRINT_AVAILABLE,
"breadcrumbs": [
{"text": "Home", "url": "/"},
{"text": "Resources", "url": "/resources"},
@@ -1590,6 +1919,16 @@ def personifications_page(request: Request):
)
@router.get("/personifications/pdf")
def personifications_page_pdf():
return _resource_index_pdf_response(
PERSONIFICATIONS_DATA,
page_title="Personifications in Scripture",
page_subtitle="Abstract Concepts Given Human Form",
page_description="A study of biblical personifications—Wisdom, Folly, Death, Sin, and other abstract concepts portrayed as persons throughout Scripture."
)
@router.get("/personifications/{item_slug}", response_class=HTMLResponse)
def personifications_detail(request: Request, item_slug: str):
"""Individual Personification topic detail page."""
+27 -1
View File
@@ -1732,11 +1732,37 @@ def reading_plan_detail(request: Request, plan_id: str):
"plan": plan,
"plan_id": plan_id,
"books": books,
"breadcrumbs": breadcrumbs
"breadcrumbs": breadcrumbs,
"pdf_available": WEASYPRINT_AVAILABLE,
"pdf_url": f"/reading-plans/{plan_id}/pdf" if WEASYPRINT_AVAILABLE else None
}
)
@app.get("/reading-plans/{plan_id}/pdf")
def reading_plan_pdf(plan_id: str):
"""Generate a PDF export for a reading plan."""
if not WEASYPRINT_AVAILABLE:
raise HTTPException(
status_code=503,
detail="PDF generation is not available. WeasyPrint system libraries are not installed."
)
plan = get_plan(plan_id)
if not plan:
raise HTTPException(status_code=404, detail="Reading plan not found")
html_content = templates.get_template("reading_plan_pdf.html").render(plan=plan)
pdf_buffer = render_html_to_pdf(html_content)
filename = f"reading-plan-{plan_id}.pdf"
return StreamingResponse(
pdf_buffer,
media_type="application/pdf",
headers={"Content-Disposition": f"attachment; filename={filename}"}
)
@app.get("/topics", response_class=HTMLResponse)
def topics_page(request: Request):
"""Browse topical index of Bible themes"""
@@ -80,6 +80,35 @@
line-height: 1.8;
}
.angels-actions {
margin: 1rem 0 1.5rem;
}
.angels-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.angels-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.angels-download-btn svg {
width: 14px;
height: 14px;
}
.intro-text {
max-width: 60%;
font-size: 1.2rem;
@@ -134,6 +163,17 @@
<h1>Biblical Angels</h1>
<p class="subtitle">Angelic Beings in Holy Scripture</p>
{% if pdf_available %}
<div class="angels-actions">
<a class="angels-download-btn" href="/biblical-angels/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Angels (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
@@ -80,6 +80,35 @@
line-height: 1.8;
}
.covenants-actions {
margin: 1rem 0 1.5rem;
}
.covenants-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.covenants-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.covenants-download-btn svg {
width: 14px;
height: 14px;
}
.intro-text {
max-width: 60%;
font-size: 1.2rem;
@@ -134,6 +163,17 @@
<h1>Biblical Covenants</h1>
<p class="subtitle">God's Covenantal Framework Throughout Redemptive History</p>
{% if pdf_available %}
<div class="covenants-actions">
<a class="covenants-download-btn" href="/biblical-covenants/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Covenants (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
+43 -3
View File
@@ -75,9 +75,38 @@
.verse-text {
max-width: 60%;
font-style: italic;
color: #444;
line-height: 1.8;
font-style: italic;
color: #444;
line-height: 1.8;
}
.festivals-actions {
margin: 1rem 0 1.5rem;
}
.festivals-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.festivals-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.festivals-download-btn svg {
width: 14px;
height: 14px;
}
.intro-text {
@@ -134,6 +163,17 @@
<h1>Biblical Festivals</h1>
<p class="subtitle">The Sacred Feasts of Israel and Their Prophetic Significance</p>
{% if pdf_available %}
<div class="festivals-actions">
<a class="festivals-download-btn" href="/biblical-festivals/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Festivals (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
+13 -13
View File
@@ -41,8 +41,8 @@
margin-bottom: 1rem;
}
.prophet-actions {
margin: 0.5rem 0 1rem;
.prophets-actions {
margin: 1rem 0 1.5rem;
}
.prophet-download-btn {
@@ -163,6 +163,17 @@
<h1>Biblical Prophets</h1>
<p class="subtitle">Messengers of the Most High</p>
{% if resource_pdf_available %}
<div class="prophets-actions">
<a class="prophet-download-btn" href="/biblical-prophets/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Prophets (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
@@ -189,17 +200,6 @@
</h3>
<p class="prophet-title">{{ prophet.title }}</p>
{% if resource_pdf_available %}
<div class="prophet-actions">
<a class="prophet-download-btn" href="/biblical-prophets/{{ prophet_name|slugify }}/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download PDF
</a>
</div>
{% endif %}
<div class="prophet-description">
{{ prophet.description | safe }}
</div>
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Biblical Prophets (KJV)</title>
<style>
@page {
size: letter;
margin: 0.85in;
@bottom-center {
content: counter(page);
font-family: "et-book", Georgia, serif;
font-size: 10pt;
color: #666;
}
}
body {
font-family: "et-book", Georgia, "Times New Roman", serif;
font-size: 11pt;
line-height: 1.6;
color: #111;
}
h1 {
font-size: 24pt;
font-weight: normal;
margin: 0 0 0.2in 0;
}
h2 {
font-size: 16pt;
font-weight: normal;
margin-top: 0.35in;
}
h3 {
font-size: 13pt;
font-weight: normal;
margin-bottom: 0.05in;
}
.subtitle {
font-style: italic;
color: #666;
margin-bottom: 0.3in;
}
.prophet-description {
margin-bottom: 0.15in;
}
.verses {
margin: 0.15in 0;
}
.verse-item {
margin-bottom: 0.1in;
padding-left: 0.25in;
border-left: 2px solid #ddd;
}
.verse-ref {
font-weight: 600;
color: #444;
}
.verse-text {
font-style: italic;
color: #555;
}
.footer {
margin-top: 0.4in;
font-size: 9pt;
color: #888;
text-align: center;
}
</style>
</head>
<body>
<h1>Biblical Prophets</h1>
<p class="subtitle">Messengers of the Most High</p>
{% for category, prophets in prophets_data.items() %}
<section>
<h2>{{ category }}</h2>
{% for name, prophet in prophets.items() %}
<article>
<h3>{{ name }} — {{ prophet.title }}</h3>
<div class="prophet-description">{{ prophet.description | safe }}</div>
{% if prophet.verses %}
<div class="verses">
{% for verse in prophet.verses %}
<div class="verse-item">
<div class="verse-ref">{{ verse.reference }}</div>
<div class="verse-text">{{ verse.text | link_names | safe }}</div>
</div>
{% endfor %}
</div>
{% endif %}
</article>
{% endfor %}
</section>
{% endfor %}
<div class="footer">From KJV Study &bull; kjvstudy.org</div>
</body>
</html>
@@ -80,6 +80,35 @@
line-height: 1.8;
}
.fruits-actions {
margin: 1rem 0 1.5rem;
}
.fruits-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.fruits-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.fruits-download-btn svg {
width: 14px;
height: 14px;
}
.intro-text {
max-width: 60%;
font-size: 1.2rem;
@@ -134,6 +163,17 @@
<h1>Fruits of the Spirit</h1>
<p class="subtitle">The Nine Graces of Galatians 5:22-23</p>
{% if pdf_available %}
<div class="fruits-actions">
<a class="fruits-download-btn" href="/fruits-of-the-spirit/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Studies (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
+40
View File
@@ -80,6 +80,35 @@
line-height: 1.8;
}
.names-actions {
margin: 1rem 0 1.5rem;
}
.names-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.names-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.names-download-btn svg {
width: 14px;
height: 14px;
}
.intro-text {
max-width: 60%;
font-size: 1.2rem;
@@ -134,6 +163,17 @@
<h1>Names of God</h1>
<p class="subtitle">The Divine Names Revealed in Holy Scripture</p>
{% if pdf_available %}
<div class="names-actions">
<a class="names-download-btn" href="/names-of-god/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Names (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
@@ -85,6 +85,43 @@
line-height: 1.9;
margin: 1rem 0;
}
.plan-actions {
margin: 1rem 0 1.5rem;
}
.print-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.45rem 0.9rem;
font-size: 0.9rem;
color: var(--text-secondary);
background: var(--code-bg);
border: 1px solid var(--border-color);
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
text-decoration: none;
}
.print-btn:hover {
background: var(--bg-color);
border-color: var(--link-color);
color: var(--link-color);
}
.print-btn svg {
width: 16px;
height: 16px;
}
@media print {
.plan-actions,
.print-btn {
display: none;
}
}
</style>
{% endblock %}
@@ -92,6 +129,17 @@
<h1>{{ plan.name }}</h1>
<p class="subtitle">{{ plan.description }}</p>
{% if pdf_available and pdf_url %}
<div class="plan-actions">
<a href="{{ pdf_url }}" class="print-btn">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download Plan (PDF)
</a>
</div>
{% endif %}
<section>
<div class="plan-stats">
<div class="stat-item">
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ plan.name }} - Reading Plan</title>
<style>
@page {
size: letter;
margin: 0.75in;
@bottom-center {
content: counter(page);
font-family: "et-book", Georgia, serif;
font-size: 10pt;
color: #666;
}
}
body {
font-family: "et-book", Georgia, "Times New Roman", serif;
font-size: 11pt;
line-height: 1.55;
color: #111;
}
h1 {
font-size: 24pt;
font-weight: normal;
margin: 0 0 0.15in 0;
}
.subtitle {
font-style: italic;
color: #666;
margin-bottom: 0.25in;
}
.overview {
margin-bottom: 0.35in;
padding-left: 0.25in;
border-left: 3px solid #ddd;
}
.day-entry {
margin-bottom: 0.2in;
padding-bottom: 0.15in;
border-bottom: 1px solid #eee;
}
.day-number {
font-weight: 600;
color: #444;
}
.day-readings {
margin: 0.05in 0;
}
.reading-ref {
display: inline-block;
margin: 0.03in 0.1in 0 0;
padding: 0.02in 0.1in;
background: #f5f5f5;
border-radius: 3px;
font-size: 10pt;
}
.day-theme {
font-style: italic;
color: #666;
}
.footer {
margin-top: 0.4in;
font-size: 9pt;
color: #888;
text-align: center;
}
</style>
</head>
<body>
<h1>{{ plan.name }}</h1>
<p class="subtitle">{{ plan.description }}</p>
<div class="overview">{{ plan.overview | safe }}</div>
{% set all_days = plan.days if plan.days else plan.sample_days %}
{% for day in all_days %}
<div class="day-entry">
<div class="day-number">Day {{ day.day }}</div>
<div class="day-readings">
{% for reading in day.readings %}
<span class="reading-ref">{{ reading }}</span>
{% endfor %}
</div>
<div class="day-theme">Theme: {{ day.theme }}</div>
</div>
{% endfor %}
<div class="footer">From KJV Study &bull; kjvstudy.org</div>
</body>
</html>
+15 -11
View File
@@ -77,6 +77,10 @@
margin: 1.5rem 0;
}
.resource-index-actions {
margin: 1rem 0 1.5rem;
}
.verse-list {
margin: 1.5rem 0 0 0;
}
@@ -172,6 +176,17 @@
<h1>{{ page_title }}</h1>
<p class="subtitle">{{ page_subtitle }}</p>
{% if pdf_available %}
<div class="resource-index-actions">
<a class="resource-download-btn" href="{{ base_url }}/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
@@ -194,17 +209,6 @@
<h3 class="resource-name"><a href="{{ base_url }}/{{ item_name|slugify }}">{{ item_name }}</a></h3>
<p class="resource-item-title">{{ item.title }}</p>
{% if resource_pdf_available %}
<div class="resource-entry-actions">
<a class="resource-download-btn" href="{{ base_url }}/{{ item_name|slugify }}/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download
</a>
</div>
{% endif %}
<div class="resource-item-description">
{{ item.description | link_names | link_verses | safe }}
</div>
@@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ page_title }}</title>
<style>
@page {
size: letter;
margin: 0.85in;
@bottom-center {
content: counter(page);
font-family: "et-book", Georgia, serif;
font-size: 10pt;
color: #666;
}
}
body {
font-family: "et-book", Georgia, "Times New Roman", serif;
font-size: 11pt;
line-height: 1.6;
color: #111;
}
h1 {
font-size: 24pt;
font-weight: normal;
margin: 0 0 0.2in 0;
}
h2 {
font-size: 16pt;
font-weight: normal;
margin-top: 0.35in;
}
h3 {
font-size: 13pt;
font-weight: normal;
margin-bottom: 0.05in;
}
.subtitle {
font-style: italic;
color: #666;
margin-bottom: 0.2in;
}
.entry-description {
margin-bottom: 0.1in;
}
.verses {
margin: 0.15in 0;
}
.verse-item {
margin-bottom: 0.1in;
padding-left: 0.25in;
border-left: 2px solid #ddd;
}
.verse-ref {
font-weight: 600;
color: #444;
}
.verse-text {
font-style: italic;
color: #555;
}
.footer {
margin-top: 0.4in;
font-size: 9pt;
color: #888;
text-align: center;
}
</style>
</head>
<body>
<h1>{{ page_title }}</h1>
<p class="subtitle">{{ page_subtitle }}</p>
<p>{{ page_description }}</p>
{% for category, entries in resource_data.items() %}
<section>
<h2>{{ category }}</h2>
{% for name, entry in entries.items() %}
<article>
<h3>{{ name }}{% if entry.title %} — {{ entry.title }}{% endif %}</h3>
{% if entry.description %}
<div class="entry-description">{{ entry.description | safe }}</div>
{% endif %}
{% if entry.verses %}
<div class="verses">
{% for verse in entry.verses %}
<div class="verse-item">
<div class="verse-ref">{{ verse.reference if verse.reference else verse }}</div>
{% if verse.text %}
<div class="verse-text">{{ verse.text | link_names | safe }}</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
</article>
{% endfor %}
</section>
{% endfor %}
<div class="footer">From KJV Study &bull; kjvstudy.org</div>
</body>
</html>
@@ -18,6 +18,35 @@
margin: 1.5rem 0 2rem 0;
}
.apostles-actions {
margin: 1rem 0 1.5rem;
}
.apostle-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.apostle-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.apostle-download-btn svg {
width: 14px;
height: 14px;
}
.apostle-name {
font-size: 1.8rem;
font-weight: 400;
@@ -134,6 +163,17 @@
<h1>The Twelve Apostles</h1>
<p class="subtitle">Those Whom He Chose to Be With Him</p>
{% if pdf_available %}
<div class="apostles-actions">
<a class="apostle-download-btn" href="/the-twelve-apostles/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Apostles (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>The Twelve Apostles (KJV)</title>
<style>
@page {
size: letter;
margin: 0.85in;
@bottom-center {
content: counter(page);
font-family: "et-book", Georgia, serif;
font-size: 10pt;
color: #666;
}
}
body {
font-family: "et-book", Georgia, "Times New Roman", serif;
font-size: 11pt;
line-height: 1.6;
color: #111;
}
h1 {
font-size: 24pt;
font-weight: normal;
margin: 0 0 0.2in 0;
}
h2 {
font-size: 16pt;
font-weight: normal;
margin-top: 0.35in;
}
h3 {
font-size: 13pt;
font-weight: normal;
margin-bottom: 0.05in;
}
.subtitle {
font-style: italic;
color: #666;
margin-bottom: 0.3in;
}
.apostle-description {
margin-bottom: 0.15in;
}
.verses {
margin: 0.15in 0;
}
.verse-item {
margin-bottom: 0.1in;
padding-left: 0.25in;
border-left: 2px solid #ddd;
}
.verse-ref {
font-weight: 600;
color: #444;
}
.verse-text {
font-style: italic;
color: #555;
}
.footer {
margin-top: 0.4in;
font-size: 9pt;
color: #888;
text-align: center;
}
</style>
</head>
<body>
<h1>The Twelve Apostles</h1>
<p class="subtitle">Those whom He chose to be with Him</p>
{% for category, apostles in apostles_data.items() %}
<section>
<h2>{{ category }}</h2>
{% for name, apostle in apostles.items() %}
<article>
<h3>{{ name }} — {{ apostle.title }}</h3>
<div class="apostle-description">{{ apostle.description | safe }}</div>
{% if apostle.verses %}
<div class="verses">
{% for verse in apostle.verses %}
<div class="verse-item">
<div class="verse-ref">{{ verse.reference }}</div>
<div class="verse-text">{{ verse.text | link_names | safe }}</div>
</div>
{% endfor %}
</div>
{% endif %}
</article>
{% endfor %}
</section>
{% endfor %}
<div class="footer">From KJV Study &bull; kjvstudy.org</div>
</body>
</html>
@@ -127,6 +127,35 @@
padding-left: 1.5rem;
font-size: 0.95rem;
}
.women-actions {
margin: 1rem 0 1.5rem;
}
.women-download-btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
color: var(--text-secondary, #666);
background: var(--code-bg, #f8f8f8);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.women-download-btn:hover {
background: var(--bg-color, #fff);
border-color: var(--link-color);
color: var(--link-color);
}
.women-download-btn svg {
width: 14px;
height: 14px;
}
</style>
{% endblock %}
@@ -134,6 +163,17 @@
<h1>Women of the Bible</h1>
<p class="subtitle">Faithful Witnesses Throughout Redemptive History</p>
{% if pdf_available %}
<div class="women-actions">
<a class="women-download-btn" href="/women-of-the-bible/pdf">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Download All Women (PDF)
</a>
</div>
{% endif %}
<nav class="toc" id="toc">
<h2>Contents</h2>
<ul id="toc-list"></ul>