Include sidenotes as footnotes in chapter PDF exports

Cross-references and word studies now appear as proper footnotes
in PDF exports using WeasyPrint's CSS footnote support.

Features:
- Cross-references grouped by description (e.g., "References God")
- Word studies with Greek/Hebrew terms and meanings
- Automatic footnote numbering
- Footnote markers (* and †) in verse text
- Clean footnote formatting at bottom of pages

PDF now includes all the study content from the web view in a
print-friendly format.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-28 16:25:00 -05:00
parent 3ac3498d33
commit b1dff9f2fb
2 changed files with 61 additions and 2 deletions
+26
View File
@@ -2226,11 +2226,37 @@ async def chapter_pdf(request: Request, book: str, chapter: int):
detail=f"Chapter {chapter} of {book} was not found. This book has {len(chapters)} chapters."
)
# Generate commentaries with cross-references and word studies for PDF
commentaries = {}
shown_words = set()
for verse in verses:
commentary = generate_commentary(book, chapter, verse)
# Add word study sidenotes (avoiding repetition within chapter)
word_studies = generate_word_study_sidenotes(verse.text, book, chapter, verse.verse, shown_words)
commentary['word_studies'] = word_studies
for study in word_studies:
shown_words.add(study['word'].lower())
# Add cross-references grouped by description
from collections import defaultdict
cross_refs = get_cross_references(book, chapter, verse.verse)
grouped_refs = defaultdict(list)
for ref in cross_refs:
description = ref['note'] if ref['note'] else 'Related'
grouped_refs[description].append(ref['ref'])
commentary['cross_reference_groups'] = [
{'description': desc, 'refs': refs}
for desc, refs in grouped_refs.items()
]
commentaries[verse.verse] = commentary
html_content = templates.get_template("chapter_pdf.html").render(
book=book,
chapter=chapter,
verses=verses,
verse_count=len(verses),
commentaries=commentaries,
)
pdf_buffer = await render_html_to_pdf_async(html_content)
+35 -2
View File
@@ -13,6 +13,11 @@
font-size: 10pt;
color: #666;
}
@footnote {
border-top: 0.5pt solid #666;
padding-top: 6pt;
margin-top: 12pt;
}
}
body {
@@ -66,6 +71,31 @@
text-align: justify;
}
/* Footnote markers and content */
.footnote {
float: footnote;
font-size: 9pt;
line-height: 1.4;
}
.footnote-marker {
vertical-align: super;
font-size: 8pt;
color: #666;
}
::footnote-marker {
font-size: 8pt;
color: #666;
}
::footnote-call {
content: counter(footnote);
font-size: 8pt;
vertical-align: super;
color: #666;
}
.footer {
margin-top: 0.4in;
font-size: 9pt;
@@ -77,13 +107,16 @@
<body>
<h1>{{ book }} {{ chapter }}</h1>
<p class="subtitle">Authorized King James Version (KJV)</p>
<p class="chapter-meta">{{ verse_count }} verses &middot; Suitable for study, teaching, or printing.</p>
<p class="chapter-meta">{{ verse_count }} verses &middot; Cross-references and word studies included as footnotes.</p>
<div class="verses">
{% for verse in verses %}
{% set commentary = commentaries[verse.verse] if commentaries and verse.verse in commentaries else none %}
<div class="verse">
<span class="verse-number">{{ verse.verse }}</span>
<span class="verse-text">{{ verse.text }}</span>
<span class="verse-text">
{{ verse.text }}{% if commentary %}{% if commentary.cross_reference_groups %}<span class="footnote-marker">*</span>{% for group in commentary.cross_reference_groups %}<span class="footnote"><strong>{{ group.description }}:</strong> {% for ref in group.refs %}{{ ref }}{% if not loop.last %}; {% endif %}{% endfor %}.</span>{% endfor %}{% endif %}{% if commentary.word_studies %}{% for study in commentary.word_studies %}<span class="footnote-marker"></span><span class="footnote"><strong>{{ study.word }}:</strong> {{ study.term }} ({{ study.translit }}) — {{ study.meaning }}.</span>{% endfor %}{% endif %}{% endif %}
</span>
</div>
{% endfor %}
</div>