Add floating navigation sidebar with contextual drill-down

Create elegant fixed-position sidebar showing:
- Current reading location (Book → Chapter → Verse)
- Complete book list organized by Testament (Old/New)
- Quick links to homepage, resources, and tools
- Highlighted current location in navigation

Features:
- Sticky positioning (stays visible while scrolling)
- Gradient background with subtle shadow
- Organized sections: Navigation, Old Testament, New Testament, Resources
- Current book/chapter/verse highlighted with bold font and left border
- Context path box showing hierarchical location
- Custom scrollbar styling for elegance
- Responsive: hides on screens under 1400px width
- Adjusts article width to accommodate sidebar on large screens

Remove quick verse lookup feature:
- Remove verse lookup HTML form and styling
- Remove JavaScript verse parsing and navigation
- Simplify base template structure

Update server routes to pass context:
- Add current_book to book pages
- Add current_book and current_chapter to chapter pages
- Add current_book, current_chapter, and current_verse to verse pages

The sidebar provides intuitive navigation through the entire Bible
while showing users exactly where they are in their study.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-20 18:06:08 -05:00
parent 19bed79836
commit b967912dda
2 changed files with 184 additions and 117 deletions
+8 -2
View File
@@ -2022,6 +2022,7 @@ def read_book(request: Request, book: str):
"chapter_popularity": chapter_popularity,
"chapter_explanations": chapter_explanations,
"breadcrumbs": breadcrumbs,
"current_book": book,
**commentary_data
},
)
@@ -2124,7 +2125,9 @@ def read_chapter(request: Request, book: str, chapter: int):
"chapters": chapters,
"commentaries": commentaries,
"chapter_overview": chapter_overview,
"breadcrumbs": breadcrumbs
"breadcrumbs": breadcrumbs,
"current_book": book,
"current_chapter": chapter
}
)
@@ -2190,7 +2193,10 @@ def read_verse(request: Request, book: str, chapter: int, verse_num: int):
"total_verses": len(verses),
"books": books,
"chapters": chapters,
"breadcrumbs": breadcrumbs
"breadcrumbs": breadcrumbs,
"current_book": book,
"current_chapter": chapter,
"current_verse": verse_num
}
)
+176 -115
View File
@@ -80,51 +80,6 @@
color: #999;
}
/* Elegant verse lookup */
.verse-lookup {
margin: 1.5rem 0 3rem 0;
padding: 1.5rem;
background: linear-gradient(to bottom, #fafafa 0%, #f5f5f5 100%);
border: 1px solid #e5e5e5;
border-radius: 2px;
width: 55%;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.02);
}
.verse-lookup-input {
width: 100%;
padding: 0.75rem 1rem;
font-size: 1.1rem;
border: 1px solid #d0d0d0;
border-radius: 2px;
font-family: et-book, Palatino, "Palatino Linotype", Georgia, serif;
background: white;
transition: all 0.2s;
}
.verse-lookup-input:focus {
outline: none;
border-color: #888;
box-shadow: 0 0 0 3px rgba(0,0,0,0.05);
}
.verse-lookup-label {
display: block;
margin-bottom: 0.75rem;
font-size: 0.95rem;
color: #555;
font-style: italic;
letter-spacing: 0.02em;
}
.verse-lookup-error {
display: none;
margin-top: 0.75rem;
color: #a33;
font-size: 0.9rem;
font-style: italic;
}
/* Enhanced link styling */
a {
color: #333;
@@ -156,21 +111,129 @@
font-size: 1.5rem;
letter-spacing: 1rem;
}
/* Floating Navigation Sidebar */
.nav-sidebar {
position: fixed;
top: 2rem;
right: 2rem;
width: 280px;
max-height: calc(100vh - 4rem);
overflow-y: auto;
background: linear-gradient(to bottom, #fafafa 0%, #f8f8f8 100%);
border: 1px solid #ddd;
border-radius: 2px;
padding: 1.5rem;
font-size: 0.85rem;
line-height: 1.6;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.nav-sidebar::-webkit-scrollbar {
width: 6px;
}
.nav-sidebar::-webkit-scrollbar-track {
background: #f0f0f0;
}
.nav-sidebar::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
.nav-sidebar h3 {
font-size: 0.9rem;
font-weight: 600;
font-style: italic;
margin: 0 0 0.75rem 0;
padding-bottom: 0.5rem;
border-bottom: 1px solid #ddd;
color: #333;
}
.nav-sidebar ul {
list-style: none;
padding: 0;
margin: 0 0 1.5rem 0;
}
.nav-sidebar li {
margin: 0.35rem 0;
}
.nav-sidebar a {
color: #555;
text-decoration: none;
border-bottom: none;
display: block;
padding: 0.25rem 0.5rem;
border-radius: 2px;
transition: all 0.2s;
}
.nav-sidebar a:hover {
color: #000;
background: rgba(0,0,0,0.05);
}
.nav-sidebar a.current {
color: #000;
background: rgba(0,0,0,0.08);
font-weight: 600;
border-left: 3px solid #333;
padding-left: 0.75rem;
}
.nav-sidebar .testament-section {
margin-bottom: 1.5rem;
}
.nav-sidebar .testament-title {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: #888;
margin-bottom: 0.5rem;
font-weight: 600;
}
.nav-sidebar .book-list {
font-size: 0.8rem;
}
.nav-sidebar .context-path {
background: #f0f0f0;
padding: 0.75rem;
margin-bottom: 1rem;
border-left: 3px solid #666;
font-size: 0.8rem;
line-height: 1.8;
color: #555;
}
.nav-sidebar .context-path strong {
color: #000;
font-weight: 600;
}
/* Hide sidebar on smaller screens */
@media (max-width: 1400px) {
.nav-sidebar {
display: none;
}
}
/* Adjust article width when sidebar is present */
@media (min-width: 1401px) {
article {
max-width: calc(100% - 320px);
}
}
</style>
</head>
<body>
<article>
<div class="verse-lookup">
<label class="verse-lookup-label" for="verse-search">Quick Verse Lookup</label>
<input
type="text"
id="verse-search"
class="verse-lookup-input"
placeholder="e.g., John 3:16 or Genesis 1:1"
autocomplete="off"
/>
<div id="verse-lookup-error" class="verse-lookup-error"></div>
</div>
{% if breadcrumbs %}
<nav class="breadcrumb">
{% for crumb in breadcrumbs %}
@@ -187,66 +250,64 @@
{% block content %}{% endblock %}
</article>
<!-- Floating Navigation Sidebar -->
<nav class="nav-sidebar">
<h3>Navigation</h3>
{% if current_book or current_chapter or current_verse %}
<div class="context-path">
{% if current_book %}
<strong>{{ current_book }}</strong>
{% if current_chapter %}
<br>Chapter {{ current_chapter }}
{% if current_verse %}
<br>Verse {{ current_verse }}
{% endif %}
{% endif %}
{% endif %}
</div>
{% endif %}
<ul>
<li><a href="/" {% if request.url.path == "/" %}class="current"{% endif %}>Home</a></li>
<li><a href="/verse-of-the-day">Verse of the Day</a></li>
<li><a href="/search">Search</a></li>
</ul>
{% if books %}
<div class="testament-section">
<div class="testament-title">Old Testament</div>
<ul class="book-list">
{% for book in ['Genesis', 'Exodus', 'Leviticus', 'Numbers', 'Deuteronomy', 'Joshua', 'Judges', 'Ruth', '1 Samuel', '2 Samuel', '1 Kings', '2 Kings', '1 Chronicles', '2 Chronicles', 'Ezra', 'Nehemiah', 'Esther', 'Job', 'Psalms', 'Proverbs', 'Ecclesiastes', 'Song of Solomon', 'Isaiah', 'Jeremiah', 'Lamentations', 'Ezekiel', 'Daniel', 'Hosea', 'Joel', 'Amos', 'Obadiah', 'Jonah', 'Micah', 'Nahum', 'Habakkuk', 'Zephaniah', 'Haggai', 'Zechariah', 'Malachi'] %}
{% if book in books %}
<li><a href="/book/{{ book }}" {% if current_book == book %}class="current"{% endif %}>{{ book }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
<div class="testament-section">
<div class="testament-title">New Testament</div>
<ul class="book-list">
{% for book in ['Matthew', 'Mark', 'Luke', 'John', 'Acts', 'Romans', '1 Corinthians', '2 Corinthians', 'Galatians', 'Ephesians', 'Philippians', 'Colossians', '1 Thessalonians', '2 Thessalonians', '1 Timothy', '2 Timothy', 'Titus', 'Philemon', 'Hebrews', 'James', '1 Peter', '2 Peter', '1 John', '2 John', '3 John', 'Jude', 'Revelation'] %}
{% if book in books %}
<li><a href="/book/{{ book }}" {% if current_book == book %}class="current"{% endif %}>{{ book }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
<h3>Resources</h3>
<ul>
<li><a href="/biblical-maps">Biblical Geography</a></li>
<li><a href="/family-tree">Genealogies</a></li>
<li><a href="/biblical-timeline">Timeline</a></li>
<li><a href="/study-guides">Study Guides</a></li>
</ul>
</nav>
<script type="text/javascript">
// Quick verse lookup functionality
(function() {
var input = document.getElementById('verse-search');
var errorDiv = document.getElementById('verse-lookup-error');
function parseVerseReference(text) {
// Match patterns like "John 3:16" or "1 John 3:16" or "Genesis 1:1"
var pattern = /^(\d?\s*[a-z]+)\s+(\d+):(\d+)$/i;
var match = text.trim().match(pattern);
if (!match) {
return null;
}
var book = match[1].trim();
var chapter = match[2];
var verse = match[3];
// Capitalize book name properly
book = book.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ');
return {
book: book,
chapter: chapter,
verse: verse
};
}
function showError(message) {
errorDiv.textContent = message;
errorDiv.style.display = 'block';
}
function hideError() {
errorDiv.style.display = 'none';
}
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
hideError();
var ref = parseVerseReference(input.value);
if (ref) {
// Navigate to the verse
window.location.href = '/book/' + ref.book + '/chapter/' + ref.chapter + '/verse/' + ref.verse;
} else {
showError('Invalid format. Please use format like "John 3:16" or "Genesis 1:1"');
}
}
});
// Hide error when user starts typing
input.addEventListener('input', hideError);
})();
// Gauges analytics
var _gauges = _gauges || [];
(function() {