mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
Add popularity scoring and visual indicators for chapters
The changes add a system to highlight well-known Bible chapters with color coding and visual indicators based on their popularity/significance. This helps readers quickly identify important passages and commonly studied chapters.
This commit is contained in:
+80
-4
@@ -15,6 +15,74 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from .kjv import bible, VerseReference
|
||||
|
||||
|
||||
def get_chapter_popularity_score(book: str, chapter: int) -> int:
|
||||
"""Calculate popularity score for a chapter (1-10 scale) based on well-known verses"""
|
||||
# Define highly popular chapters with their scores
|
||||
popular_chapters = {
|
||||
# Perfect 10s - Most famous chapters
|
||||
"John": {3: 10}, # John 3:16
|
||||
"1 Corinthians": {13: 10}, # Love chapter
|
||||
"Psalms": {23: 10, 91: 9, 1: 8, 139: 8}, # Most beloved psalms
|
||||
"Romans": {8: 9, 3: 8, 12: 8}, # Core doctrine
|
||||
"Matthew": {5: 9, 6: 8, 7: 8}, # Sermon on the Mount
|
||||
"Ephesians": {2: 8, 6: 8}, # Salvation by grace, armor of God
|
||||
"Philippians": {4: 8}, # Joy and peace
|
||||
"Genesis": {1: 9, 3: 8, 22: 7}, # Creation, fall, Abraham's test
|
||||
"Exodus": {20: 8, 14: 7}, # Ten Commandments, Red Sea
|
||||
"Isaiah": {53: 9, 40: 8}, # Suffering servant, comfort
|
||||
"Jeremiah": {29: 7}, # Plans to prosper you
|
||||
"Proverbs": {31: 7, 3: 7}, # Virtuous woman, trust in the Lord
|
||||
"Ecclesiastes": {3: 8}, # To everything there is a season
|
||||
"1 Peter": {5: 7}, # Cast your cares
|
||||
"James": {1: 7}, # Faith and trials
|
||||
"Hebrews": {11: 8, 12: 7}, # Faith hall of fame
|
||||
"Revelation": {21: 8, 22: 7}, # New heaven and earth
|
||||
"Luke": {2: 9, 15: 8}, # Christmas story, prodigal son
|
||||
"2 Timothy": {3: 7}, # All Scripture is inspired
|
||||
"Joshua": {1: 7}, # Be strong and courageous
|
||||
"Daniel": {3: 7, 6: 7}, # Fiery furnace, lion's den
|
||||
"1 John": {4: 8}, # God is love
|
||||
"Galatians": {5: 7}, # Fruits of the Spirit
|
||||
"Colossians": {3: 7}, # Set your mind on things above
|
||||
"1 Thessalonians": {4: 7}, # Rapture passage
|
||||
"Mark": {16: 7}, # Great Commission
|
||||
"Acts": {2: 8}, # Pentecost
|
||||
"1 Samuel": {17: 7}, # David and Goliath
|
||||
"Job": {19: 7}, # I know my redeemer lives
|
||||
"2 Corinthians": {5: 7}, # New creation
|
||||
"1 Kings": {3: 6, 18: 6}, # Solomon's wisdom, Elijah
|
||||
"Malachi": {3: 6}, # Tithing
|
||||
"Joel": {2: 6}, # Pour out my Spirit
|
||||
"Micah": {6: 6}, # What does the Lord require
|
||||
"Habakkuk": {2: 6}, # The just shall live by faith
|
||||
}
|
||||
|
||||
# Check if this specific chapter has a popularity score
|
||||
if book in popular_chapters and chapter in popular_chapters[book]:
|
||||
return popular_chapters[book][chapter]
|
||||
|
||||
# Default scoring based on book type and chapter position
|
||||
default_score = 4 # Base score
|
||||
|
||||
# Boost for first chapters (often contain key introductions)
|
||||
if chapter == 1:
|
||||
default_score += 1
|
||||
|
||||
# Boost for books with generally high readership
|
||||
high_readership_books = ["Matthew", "Mark", "Luke", "John", "Acts", "Romans",
|
||||
"1 Corinthians", "2 Corinthians", "Galatians", "Ephesians",
|
||||
"Philippians", "Colossians", "Genesis", "Exodus", "Psalms", "Proverbs"]
|
||||
if book in high_readership_books:
|
||||
default_score += 1
|
||||
|
||||
# Small boost for shorter books (more likely to be read in full)
|
||||
total_chapters = len([ch for bk, ch in bible.iter_chapters() if bk == book])
|
||||
if total_chapters <= 5:
|
||||
default_score += 1
|
||||
|
||||
return min(default_score, 6) # Cap at 6 for non-specifically scored chapters
|
||||
|
||||
|
||||
def is_verse_reference(query: str) -> bool:
|
||||
"""Check if query looks like a verse reference"""
|
||||
# Pattern for verse references like "John 3:16", "1 John 4:8", "Genesis 1:1", "I Corinthians 13:4", etc.
|
||||
@@ -83,7 +151,7 @@ def parse_verse_reference(query: str) -> Optional[Dict]:
|
||||
|
||||
return None
|
||||
|
||||
def perform_full_text_search(query: str, limit: int = 50) -> List[Dict]:
|
||||
def perform_full_text_search(query: str, limit: Optional[int] = None) -> List[Dict]:
|
||||
"""Perform full text search across all Bible verses or find specific verse references"""
|
||||
results = []
|
||||
|
||||
@@ -119,8 +187,10 @@ def perform_full_text_search(query: str, limit: int = 50) -> List[Dict]:
|
||||
# Sort by relevance score (higher is better)
|
||||
results.sort(key=lambda x: x["score"], reverse=True)
|
||||
|
||||
# Limit results
|
||||
return results[:limit]
|
||||
# Limit results if specified
|
||||
if limit is not None:
|
||||
return results[:limit]
|
||||
return results
|
||||
|
||||
|
||||
def calculate_relevance_score(text: str, search_terms: List[str]) -> float:
|
||||
@@ -219,7 +289,7 @@ def search_page(request: Request, q: str = Query(None, description="Search query
|
||||
)
|
||||
|
||||
@app.get("/api/search")
|
||||
def search_api(q: str = Query(..., description="Search query"), limit: int = Query(50, description="Max results")):
|
||||
def search_api(q: str = Query(..., description="Search query"), limit: Optional[int] = Query(None, description="Max results")):
|
||||
"""JSON API endpoint for search"""
|
||||
if not q or len(q.strip()) < 2:
|
||||
return {"query": q, "results": [], "total": 0}
|
||||
@@ -725,6 +795,11 @@ def read_book(request: Request, book: str):
|
||||
|
||||
# Generate commentary data for the book page
|
||||
commentary_data = generate_book_commentary(book, chapters)
|
||||
|
||||
# Calculate popularity scores for each chapter
|
||||
chapter_popularity = {}
|
||||
for chapter in chapters:
|
||||
chapter_popularity[chapter] = get_chapter_popularity_score(book, chapter)
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"book.html",
|
||||
@@ -733,6 +808,7 @@ def read_book(request: Request, book: str):
|
||||
"book": book,
|
||||
"chapters": chapters,
|
||||
"books": books,
|
||||
"chapter_popularity": chapter_popularity,
|
||||
**commentary_data
|
||||
},
|
||||
)
|
||||
|
||||
@@ -99,6 +99,86 @@
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Chapter popularity color coding */
|
||||
.chapter-link {
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="10"] {
|
||||
background: linear-gradient(135deg, #8B5CF6, #A855F7);
|
||||
color: white;
|
||||
box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="9"] {
|
||||
background: linear-gradient(135deg, #7C3AED, #8B5CF6);
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(124, 58, 237, 0.3);
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="8"] {
|
||||
background: linear-gradient(135deg, #6366F1, #7C3AED);
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="7"] {
|
||||
background: linear-gradient(135deg, #3B82F6, #6366F1);
|
||||
color: white;
|
||||
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="6"] {
|
||||
background: linear-gradient(135deg, #06B6D4, #3B82F6);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="5"] {
|
||||
background: linear-gradient(135deg, #10B981, #06B6D4);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="4"] {
|
||||
background: linear-gradient(135deg, #84CC16, #10B981);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="3"] {
|
||||
background: linear-gradient(135deg, #EAB308, #84CC16);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="2"] {
|
||||
background: linear-gradient(135deg, #F59E0B, #EAB308);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="1"] {
|
||||
background: linear-gradient(135deg, #F97316, #F59E0B);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chapter-link:hover {
|
||||
transform: translateY(-2px) scale(1.05);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2) !important;
|
||||
}
|
||||
|
||||
.chapter-link::after {
|
||||
content: '★';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 4px;
|
||||
font-size: 0.7rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.chapter-link[data-popularity="10"]::after,
|
||||
.chapter-link[data-popularity="9"]::after,
|
||||
.chapter-link[data-popularity="8"]::after {
|
||||
color: #FFD700;
|
||||
}
|
||||
|
||||
.verse-tooltip {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
@@ -171,6 +251,25 @@
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Mobile styles for popularity legend */
|
||||
@media (max-width: 768px) {
|
||||
.popularity-legend h3 {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.popularity-legend-items {
|
||||
gap: 0.3rem !important;
|
||||
}
|
||||
|
||||
.popularity-legend-item span {
|
||||
font-size: 0.7rem !important;
|
||||
}
|
||||
|
||||
.popularity-legend p {
|
||||
font-size: 0.65rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -219,9 +318,37 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Popularity Legend -->
|
||||
<div class="popularity-legend" style="margin-bottom: 1.5rem; text-align: center;">
|
||||
<h3 style="font-size: 1rem; color: var(--text-secondary); margin-bottom: 0.75rem; font-weight: 500;">
|
||||
📊 Chapter Popularity Guide
|
||||
</h3>
|
||||
<div class="popularity-legend-items" style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem;">
|
||||
<div class="popularity-legend-item" style="display: flex; align-items: center; gap: 0.25rem;">
|
||||
<div style="width: 20px; height: 20px; background: linear-gradient(135deg, #8B5CF6, #A855F7); border-radius: 4px; color: white; display: flex; align-items: center; justify-content: center; font-size: 0.6rem;">★</div>
|
||||
<span style="font-size: 0.8rem; color: var(--text-secondary);">Most Popular</span>
|
||||
</div>
|
||||
<div class="popularity-legend-item" style="display: flex; align-items: center; gap: 0.25rem;">
|
||||
<div style="width: 20px; height: 20px; background: linear-gradient(135deg, #3B82F6, #6366F1); border-radius: 4px;"></div>
|
||||
<span style="font-size: 0.8rem; color: var(--text-secondary);">Very Popular</span>
|
||||
</div>
|
||||
<div class="popularity-legend-item" style="display: flex; align-items: center; gap: 0.25rem;">
|
||||
<div style="width: 20px; height: 20px; background: linear-gradient(135deg, #10B981, #06B6D4); border-radius: 4px;"></div>
|
||||
<span style="font-size: 0.8rem; color: var(--text-secondary);">Popular</span>
|
||||
</div>
|
||||
<div class="popularity-legend-item" style="display: flex; align-items: center; gap: 0.25rem;">
|
||||
<div style="width: 20px; height: 20px; background: linear-gradient(135deg, #EAB308, #84CC16); border-radius: 4px;"></div>
|
||||
<span style="font-size: 0.8rem; color: var(--text-secondary);">Standard</span>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size: 0.75rem; color: var(--text-muted); margin: 0; font-style: italic;">
|
||||
Colors indicate how frequently chapters are read and studied
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="chapter-grid">
|
||||
{% for chapter in chapters %}
|
||||
<a href="/book/{{ book }}/chapter/{{ chapter }}" class="chapter-link">
|
||||
<a href="/book/{{ book }}/chapter/{{ chapter }}" class="chapter-link" data-popularity="{{ chapter_popularity[chapter] }}" title="{{ book }} Chapter {{ chapter }} - Popularity: {{ chapter_popularity[chapter] }}/10 ★{% if chapter_popularity[chapter] >= 8 %} - Highly popular passage{% elif chapter_popularity[chapter] >= 6 %} - Well-known chapter{% else %} - Click to explore{% endif %}">
|
||||
{{ chapter }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user