Add comprehensive Bible concordance feature

Concordance System:
- Complete word occurrence index for entire KJV Bible
- Shows all instances of any searched word with full context
- Case-insensitive exact word matching with word boundaries
- Results organized by biblical book for easy navigation
- Each occurrence links directly to the verse

Features:
- Search any word to find all occurrences (e.g., "love" appears ~300 times)
- Highlighted word in context for quick identification
- Statistics showing total occurrences and books containing the word
- Popular word suggestions (love, faith, LORD, God, Jesus, grace, etc.)
- Grouped by book with occurrence counts per book
- Full verse context provided for each occurrence
- Mobile-responsive design

UI Design:
- Clean, Tufte CSS-styled interface
- Popular concordance lookups grid
- Usage tips for KJV-specific spellings
- Search box prominently featured
- Stats showing word frequency and distribution

Implementation:
- Route: /concordance with ?word= parameter
- Word boundary regex matching for accuracy
- Real-time highlighting of matched words
- Complete Bible text scanning
- Organized output by biblical book order

Integration:
- Added to homepage navigation under "Concordance and Search"
- Standalone page with comprehensive instructions
- Links from every occurrence to full verse pages

Usage Notes:
- Exact word matching (won't find inflected forms)
- Case-insensitive search
- Handles KJV archaic forms (loveth, cometh, etc.)
- Proper nouns supported (Jesus, Moses, David)
- Theological terms supported (justification, redemption)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-22 08:21:39 -05:00
parent e7c9689bea
commit e25bf08720
3 changed files with 382 additions and 1 deletions
+75
View File
@@ -493,6 +493,81 @@ def search_api(q: str = Query(..., description="Search query"), limit: Optional[
"is_direct_verse": is_direct_verse
}
@app.get("/concordance", response_class=HTMLResponse)
def concordance_page(request: Request, word: str = Query(None, description="Word to look up")):
"""Concordance page showing all occurrences of a word"""
books = list(bible.iter_books())
if not word or len(word.strip()) < 2:
return templates.TemplateResponse(
"concordance.html",
{
"request": request,
"books": books,
"word": word or "",
"total_occurrences": 0,
"occurrences_by_book": {},
"books_with_word": []
}
)
search_word = word.strip()
occurrences = []
occurrences_by_book = {}
books_with_word = set()
# Search through all verses
import re
# Create a word boundary pattern for exact word matching
# This handles punctuation and word boundaries properly
pattern = re.compile(r'\b' + re.escape(search_word) + r'\b', re.IGNORECASE)
for book in bible.iter_books():
book_name = book.name
book_occurrences = []
for chapter_num in range(1, book.num_chapters + 1):
chapter = book.chapter(chapter_num)
for verse in chapter.verses:
# Check if the word appears in this verse
if pattern.search(verse.text):
# Highlight the word in the text
highlighted_text = pattern.sub(
lambda m: f'<span class="highlight">{m.group()}</span>',
verse.text
)
occurrence = {
'book': book_name,
'chapter': chapter_num,
'verse': verse.verse,
'text': verse.text,
'highlighted_text': highlighted_text
}
occurrences.append(occurrence)
book_occurrences.append(occurrence)
books_with_word.add(book_name)
# Only add to occurrences_by_book if there are occurrences in this book
if book_occurrences:
occurrences_by_book[book_name] = book_occurrences
return templates.TemplateResponse(
"concordance.html",
{
"request": request,
"books": books,
"word": search_word,
"total_occurrences": len(occurrences),
"occurrences_by_book": occurrences_by_book,
"books_with_word": sorted(books_with_word)
}
)
def parse_verse_reference(reference: str):
"""Parse a verse reference and return a URL for it.
+306
View File
@@ -0,0 +1,306 @@
{% extends "base.html" %}
{% block title %}{% if word %}Concordance: "{{ word }}" - {{ total_occurrences }} occurrences{% else %}Bible Concordance{% endif %} - KJV Study{% endblock %}
{% block description %}{% if word %}Complete concordance showing all {{ total_occurrences }} occurrences of "{{ word }}" in the King James Bible with context.{% else %}Search the complete KJV Bible concordance to find every occurrence of any word.{% endif %}{% endblock %}
{% block head %}
<style>
.concordance-search {
max-width: 55%;
margin: 2rem 0;
}
.concordance-input {
width: 100%;
padding: 0.75rem;
font-size: 1.1rem;
border: 1px solid #ccc;
border-radius: 4px;
font-family: inherit;
}
.concordance-input:focus {
outline: none;
border-color: #111;
}
.concordance-button {
margin-top: 1rem;
padding: 0.75rem 1.5rem;
background: #111;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
}
.concordance-button:hover {
background: #333;
}
.concordance-stats {
max-width: 55%;
margin: 2rem 0;
padding: 1rem 0;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.concordance-stats .stat-number {
font-family: et-book-roman-old-style;
font-weight: 600;
font-size: 1.2rem;
}
.occurrence-list {
max-width: 55%;
margin: 2rem 0;
}
.occurrence {
margin: 1.5rem 0;
padding-bottom: 1.5rem;
border-bottom: 1px solid #eee;
}
.occurrence:last-child {
border-bottom: none;
}
.occurrence-reference {
font-weight: 600;
margin-bottom: 0.5rem;
font-size: 1.1rem;
}
.occurrence-reference a {
text-decoration: none;
color: #111;
}
.occurrence-reference a:hover {
text-decoration: underline;
}
.occurrence-text {
line-height: 1.8;
color: #333;
}
.occurrence-text .highlight {
background: #fffacd;
padding: 0.1rem 0.2rem;
font-weight: 600;
color: #111;
}
.book-group {
margin: 2.5rem 0;
}
.book-group h3 {
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid #111;
}
.book-count {
color: #666;
font-weight: normal;
font-size: 0.9rem;
}
.concordance-tips {
max-width: 55%;
margin: 2rem 0;
padding: 1.5rem;
background: #f9f9f9;
border-left: 3px solid #111;
}
.concordance-tips h3 {
margin-top: 0;
}
.concordance-tips ul {
line-height: 1.8;
}
.popular-words {
max-width: 55%;
margin: 2rem 0;
}
.word-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 1rem;
margin: 1rem 0;
}
.word-link {
padding: 0.5rem;
background: #f5f5f5;
border-radius: 4px;
text-align: center;
text-decoration: none;
color: #111;
}
.word-link:hover {
background: #e5e5e5;
}
.word-link-word {
font-weight: 600;
display: block;
}
.word-link-count {
font-size: 0.85rem;
color: #666;
}
@media (max-width: 760px) {
.concordance-search,
.concordance-stats,
.occurrence-list,
.concordance-tips,
.popular-words {
max-width: 100%;
}
.word-list {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
}
</style>
{% endblock %}
{% block content %}
<h1>Bible Concordance</h1>
<p class="subtitle">Find every occurrence of any word in the King James Bible</p>
<section>
<form class="concordance-search" method="get" action="/concordance">
<input
type="text"
name="word"
value="{{ word }}"
placeholder="Enter a word to find all occurrences..."
class="concordance-input"
autofocus
>
<button type="submit" class="concordance-button">Search Concordance</button>
</form>
{% if word %}
{% if total_occurrences > 0 %}
<div class="concordance-stats">
<p>The word <strong>"{{ word }}"</strong> appears <span class="stat-number">{{ total_occurrences }}</span> time{{ 's' if total_occurrences != 1 else '' }} in the King James Bible</p>
{% if books_with_word %}
<p style="margin-top: 0.5rem; color: #666;">Found in {{ books_with_word|length }} book{{ 's' if books_with_word|length != 1 else '' }}: {{ books_with_word|join(', ') }}</p>
{% endif %}
</div>
{% if occurrences_by_book %}
{% for book_name, book_occurrences in occurrences_by_book.items() %}
<div class="book-group">
<h3>{{ book_name }} <span class="book-count">({{ book_occurrences|length }} occurrence{{ 's' if book_occurrences|length != 1 else '' }})</span></h3>
<div class="occurrence-list">
{% for occurrence in book_occurrences %}
<div class="occurrence">
<div class="occurrence-reference">
<a href="/book/{{ occurrence.book }}/chapter/{{ occurrence.chapter }}/verse/{{ occurrence.verse }}">
{{ occurrence.book }} {{ occurrence.chapter }}:{{ occurrence.verse }}
</a>
</div>
<div class="occurrence-text">{{ occurrence.highlighted_text | safe }}</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
{% endif %}
{% else %}
<div class="concordance-stats">
<p><strong>No occurrences found</strong> for "{{ word }}". Try a different word or check your spelling.</p>
<p style="margin-top: 0.5rem; color: #666;">Note: The KJV uses older English spellings. Try words like "loveth" instead of "loves", "cometh" instead of "comes".</p>
</div>
{% endif %}
{% endif %}
{% if not word or total_occurrences == 0 %}
<div class="popular-words">
<h2>Popular Concordance Lookups</h2>
<p>Browse frequently searched words:</p>
<div class="word-list">
<a href="/concordance?word=love" class="word-link">
<span class="word-link-word">love</span>
<span class="word-link-count">~300 times</span>
</a>
<a href="/concordance?word=faith" class="word-link">
<span class="word-link-word">faith</span>
<span class="word-link-count">~250 times</span>
</a>
<a href="/concordance?word=LORD" class="word-link">
<span class="word-link-word">LORD</span>
<span class="word-link-count">~7000 times</span>
</a>
<a href="/concordance?word=God" class="word-link">
<span class="word-link-word">God</span>
<span class="word-link-count">~4000 times</span>
</a>
<a href="/concordance?word=Jesus" class="word-link">
<span class="word-link-word">Jesus</span>
<span class="word-link-count">~900 times</span>
</a>
<a href="/concordance?word=grace" class="word-link">
<span class="word-link-word">grace</span>
<span class="word-link-count">~170 times</span>
</a>
<a href="/concordance?word=peace" class="word-link">
<span class="word-link-word">peace</span>
<span class="word-link-count">~400 times</span>
</a>
<a href="/concordance?word=salvation" class="word-link">
<span class="word-link-word">salvation</span>
<span class="word-link-count">~160 times</span>
</a>
<a href="/concordance?word=righteousness" class="word-link">
<span class="word-link-word">righteousness</span>
<span class="word-link-count">~300 times</span>
</a>
<a href="/concordance?word=mercy" class="word-link">
<span class="word-link-word">mercy</span>
<span class="word-link-count">~340 times</span>
</a>
<a href="/concordance?word=truth" class="word-link">
<span class="word-link-word">truth</span>
<span class="word-link-count">~230 times</span>
</a>
<a href="/concordance?word=blessed" class="word-link">
<span class="word-link-word">blessed</span>
<span class="word-link-count">~300 times</span>
</a>
</div>
</div>
<div class="concordance-tips">
<h3>Using the Concordance</h3>
<ul>
<li><strong>Case-insensitive</strong> - Search for "Love", "love", or "LOVE" - all work the same</li>
<li><strong>Exact matches only</strong> - Searches for the exact word form (e.g., "love" won't find "loved" or "loveth")</li>
<li><strong>Old English forms</strong> - The KJV uses archaic verb forms like "cometh", "goeth", "loveth"</li>
<li><strong>Proper nouns</strong> - Search for names like "Jesus", "Moses", "David" to track their appearances</li>
<li><strong>Theological terms</strong> - Look up "justification", "sanctification", "redemption", etc.</li>
<li><strong>Context provided</strong> - Each occurrence shows the full verse for context</li>
<li><strong>Organized by book</strong> - Results grouped by biblical book for easy navigation</li>
</ul>
</div>
{% endif %}
</section>
{% endblock %}
+1 -1
View File
@@ -522,7 +522,7 @@ document.addEventListener('keydown', function(e) {
<p><span class="newthought">Reading Plans</span> — Structured <a href="/reading-plans">Bible reading schedules</a> for systematic Scripture study, including chronological, thematic, and testament-specific plans to guide sustained engagement with God's Word.</p>
<p><span class="newthought">Concordance and Search</span> — A comprehensive <a href="/search">search facility</a> allowing the reader to trace any word or phrase throughout the entire corpus of Scripture, after the manner of Cruden's Complete Concordance.</p>
<p><span class="newthought">Concordance and Search</span> — A comprehensive <a href="/concordance">concordance</a> showing every occurrence of any word in Scripture, and a <a href="/search">search facility</a> allowing the reader to trace any word or phrase throughout the entire corpus of Scripture, after the manner of Cruden's Complete Concordance.</p>
<p><span class="newthought">Biblical Geography</span><a href="/biblical-maps">Maps and descriptions</a> of those places mentioned in Holy Writ, from the rivers of Babylon to the shores of Galilee, illuminating the geographical context of sacred history.</p>