Files
kjvstudy.org/kjvstudy_org/templates/base.html
T
kennethreitz d1df9b9b84 Fix verse range extraction for tooltips
Fixed the tooltip JavaScript to properly extract verse ranges from chapter pages.

Issue:
- Verse range tooltips were showing "Verse range not found"
- The selector was looking for .verse-text elements that don't exist on chapter pages

Solution:
- Updated verse extraction to query by #verse-{number} paragraph IDs
- Clone the verse paragraph and remove:
  * Verse number links (.verse-number-link)
  * Sidenotes and marginnotes
  * Margin toggle elements
- Extract clean text content from each verse in the range
- Join multiple verses with spaces

Now verse ranges like "1 Corinthians 15:19-20" will properly fetch
and display the text of both verses in the tooltip.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 21:34:38 -05:00

1531 lines
46 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>{% block title %}Authorized King James Version Bible{% endblock %}</title>
<meta name="description" content="{% block description %}Study the Authorized King James Version Bible{% endblock %}"/>
<!-- Canonical URL -->
<link rel="canonical" href="https://kjvstudy.org{% block canonical_path %}{{ request.url.path }}{% endblock %}"/>
<!-- Open Graph / Facebook -->
<meta property="og:type" content="{% block og_type %}website{% endblock %}"/>
<meta property="og:url" content="https://kjvstudy.org{{ request.url.path }}"/>
<meta property="og:title" content="{% block og_title %}{% block title_text %}Authorized King James Version Bible{% endblock %}{% endblock %}"/>
<meta property="og:description" content="{% block og_description %}{% block description_text %}Study the Authorized King James Version Bible{% endblock %}{% endblock %}"/>
<meta property="og:site_name" content="KJV Study"/>
<!-- Twitter Card -->
<meta name="twitter:card" content="summary"/>
<meta name="twitter:url" content="https://kjvstudy.org{{ request.url.path }}"/>
<meta name="twitter:title" content="{% block twitter_title %}{% block title_plain %}Authorized King James Version Bible{% endblock %}{% endblock %}"/>
<meta name="twitter:description" content="{% block twitter_description %}{% block description_plain %}Study the Authorized King James Version Bible{% endblock %}{% endblock %}"/>
<link rel="stylesheet" href="/static/tufte.css"/>
{% block head %}{% endblock %}
<!-- Structured Data (Schema.org) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "KJV Study",
"url": "https://kjvstudy.org",
"description": "Study the Authorized King James Version Bible with commentary, study guides, and biblical resources",
"potentialAction": {
"@type": "SearchAction",
"target": "https://kjvstudy.org/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
{% block structured_data %}{% endblock %}
<style>
/* Color scheme variables */
:root {
--bg-color: #fffff8;
--text-color: #111;
--text-secondary: #666;
--text-tertiary: #888;
--text-quaternary: #999;
--border-color: #eee;
--border-color-dark: #ddd;
--border-color-darker: #ccc;
--link-color: #333;
--link-hover: #000;
--code-bg: #f5f5f5;
}
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #e0e0e0;
--text-secondary: #b0b0b0;
--text-tertiary: #909090;
--text-quaternary: #707070;
--border-color: #333;
--border-color-dark: #444;
--border-color-darker: #555;
--link-color: #d0d0d0;
--link-hover: #fff;
--code-bg: #2a2a2a;
}
/* Override Tufte CSS sidenote constraints */
.sidenote,
.marginnote {
max-height: none !important;
}
label.sidenote-number {
max-height: none !important;
}
/* Verse tooltip styles */
.verse-tooltip {
position: absolute;
background: var(--bg-color);
border: 2px solid var(--border-color-darker);
border-radius: 6px;
padding: 1rem;
max-width: 400px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 9999;
font-size: 0.95rem;
line-height: 1.6;
color: var(--text-color);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
.verse-tooltip.show {
opacity: 1;
}
.verse-tooltip-reference {
font-weight: 600;
color: var(--link-color);
margin-bottom: 0.5rem;
display: block;
}
.verse-tooltip-text {
font-style: italic;
color: var(--text-secondary);
}
.verse-tooltip-loading {
color: var(--text-tertiary);
}
[data-theme="dark"] .verse-tooltip {
background: #2a2a2a;
border-color: #555;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
@media (prefers-color-scheme: dark) {
.verse-tooltip:not([data-theme]) {
background: #2a2a2a;
border-color: #555;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
}
/* Enhanced typography and spacing */
body {
counter-reset: sidenote-counter;
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
article {
padding: 2rem 5%;
}
h1, h2, h3 {
font-weight: 400;
font-style: normal;
}
h1 {
font-size: 2.8rem;
line-height: 1.2;
margin-top: 3rem;
margin-bottom: 1.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2rem;
line-height: 1.3;
margin-top: 3rem;
margin-bottom: 1rem;
font-style: italic;
}
p {
font-size: 1.4rem;
line-height: 2;
margin-top: 1.4rem;
}
/* Drop cap for opening paragraphs */
.newthought {
font-variant: small-caps;
letter-spacing: 0.05em;
}
/* Refined breadcrumb navigation */
.breadcrumb {
margin: 2rem 0 3rem 0;
font-size: 0.95rem;
color: var(--text-secondary);
font-style: italic;
border-bottom: 1px solid var(--border-color);
padding-bottom: 1rem;
}
.breadcrumb a {
color: var(--link-color);
text-decoration: none;
transition: color 0.2s;
}
.breadcrumb a:hover {
color: var(--link-hover);
}
.breadcrumb-separator {
margin: 0 0.75rem;
color: var(--text-quaternary);
}
/* Enhanced link styling */
a {
color: var(--link-color);
text-decoration: none;
border-bottom: 1px solid var(--border-color-dark);
transition: all 0.2s;
}
a:hover {
color: var(--link-hover);
border-bottom-color: var(--link-hover);
}
/* Section dividers */
section {
margin-top: 3rem;
padding-top: 2rem;
}
/* Ornamental breaks */
.ornament {
text-align: center;
margin: 3rem 0;
color: var(--text-quaternary);
font-size: 1.5rem;
letter-spacing: 1rem;
}
/* Floating Navigation Sidebar */
.nav-sidebar {
position: fixed;
top: 0;
left: 0;
width: 140px;
height: 100vh;
overflow-y: auto;
background: var(--bg-color);
padding: 1.5rem 0.75rem 1rem 0.75rem;
font-size: 0.7rem;
line-height: 1.3;
z-index: 100;
border-right: 1px solid var(--border-color);
direction: rtl;
}
.nav-sidebar > * {
direction: ltr;
}
.nav-sidebar::-webkit-scrollbar {
width: 4px;
}
.nav-sidebar::-webkit-scrollbar-track {
background: transparent;
}
.nav-sidebar::-webkit-scrollbar-thumb {
background: #ddd;
border-radius: 2px;
}
.nav-sidebar h3 {
font-size: 0.65rem;
font-weight: 600;
font-style: italic;
margin: 0 0 0.3rem 0;
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--border-color);
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.nav-sidebar ul {
list-style: none;
padding: 0;
margin: 0 0 0.75rem 0;
}
.nav-sidebar li {
margin: 0.15rem 0;
}
.nav-sidebar a {
color: var(--text-secondary);
text-decoration: none;
border-bottom: none;
display: block;
padding: 0.1rem 0;
transition: color 0.2s;
font-size: 0.7rem;
}
.nav-sidebar a:hover {
color: var(--link-hover);
}
.nav-sidebar a.current {
color: var(--link-hover);
font-weight: 600;
}
.nav-sidebar .testament-section {
margin-bottom: 0.75rem;
}
.nav-sidebar .testament-title {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-tertiary);
margin-bottom: 0.3rem;
font-weight: 600;
}
.nav-sidebar details {
margin-bottom: 0.75rem;
}
.nav-sidebar summary {
cursor: pointer;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-tertiary);
margin-bottom: 0.3rem;
font-weight: 600;
list-style: none;
user-select: none;
transition: color 0.2s;
}
.nav-sidebar summary:hover {
color: var(--text-secondary);
}
.nav-sidebar summary::-webkit-details-marker {
display: none;
}
.nav-sidebar summary::before {
content: '▸ ';
display: inline-block;
transition: transform 0.2s ease;
margin-right: 0.2rem;
}
.nav-sidebar details[open] summary::before {
transform: rotate(90deg);
}
/* Smooth expand/collapse animation */
.nav-sidebar details > ul {
animation: slideDown 0.2s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Smooth scrolling */
.nav-sidebar {
scroll-behavior: smooth;
}
.nav-sidebar .book-list {
font-size: 0.7rem;
}
/* Sidebar search box */
.sidebar-search {
margin-bottom: 0.75rem;
position: relative;
}
.sidebar-search input {
width: 90%;
padding: 0.4rem 0.5rem;
border: 1px solid var(--border-color-dark);
border-radius: 3px;
font-size: 0.75rem;
background: var(--bg-color);
color: var(--text-color);
transition: border-color 0.2s;
box-sizing: border-box;
}
.sidebar-search input:focus {
outline: none;
border-color: var(--text-tertiary);
}
/* Resource grouping */
.resource-group {
margin-bottom: 1.5rem;
}
.resource-group summary {
cursor: pointer;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-tertiary);
font-weight: 600;
margin: 1rem 0 0.5rem 0;
padding-top: 0.5rem;
border-top: 1px solid var(--border-color);
user-select: none;
}
.resource-group:first-of-type summary {
border-top: none;
margin-top: 0;
padding-top: 0;
}
.resource-group summary:hover {
color: var(--text-color);
}
/* Sidebar flourish */
.sidebar-flourish {
text-align: center;
margin: 2rem 0 1rem 0;
padding-top: 1.5rem;
border-top: 1px solid var(--border-color);
color: var(--text-tertiary);
font-size: 1rem;
letter-spacing: 0.5em;
opacity: 0.6;
}
/* Sidebar collapse functionality */
#sidebar-toggle {
display: none;
}
.sidebar-toggle-container {
position: fixed;
top: 1rem;
left: 0.75rem;
z-index: 101;
margin: 0;
padding: 0;
}
.sidebar-toggle-btn {
width: auto;
min-width: 20px;
height: 20px;
padding: 0 0.4rem;
cursor: pointer;
background: var(--bg-color);
border: 1px solid var(--border-color-darker);
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
color: var(--text-secondary);
transition: all 0.2s;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.sidebar-toggle-btn:hover {
border-color: var(--text-tertiary);
color: var(--link-hover);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
/* Dark mode toggle */
.dark-mode-toggle {
position: fixed;
top: 2rem;
right: 2rem;
z-index: 101;
margin: -25px 0 0 0;
padding: 0;
}
.dark-mode-btn {
width: 24px;
height: 24px;
cursor: pointer;
background: transparent;
border: 1px solid var(--border-color-darker);
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
color: var(--text-secondary);
transition: all 0.3s;
}
.dark-mode-btn:hover {
border-color: var(--text-tertiary);
color: var(--link-hover);
}
.dark-mode-btn::before {
content: '☀';
}
[data-theme="dark"] .dark-mode-btn::before {
content: '☾';
}
.nav-sidebar {
transform: translateX(-100%);
opacity: 0;
pointer-events: none;
}
.sidebar-toggle-container {
left: 0.75rem;
}
.sidebar-toggle-btn::before {
content: 'Menu';
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.03em;
text-transform: uppercase;
}
#sidebar-toggle:checked ~ .nav-sidebar {
transform: translateX(0);
opacity: 1;
pointer-events: auto;
}
#sidebar-toggle:checked ~ .sidebar-toggle-container {
left: 0.75rem;
}
#sidebar-toggle:checked ~ .sidebar-toggle-container .sidebar-toggle-btn::before {
content: '×';
font-size: 1.2rem;
font-weight: 400;
}
/* Responsive design for tablets and mobile */
@media (max-width: 1200px) {
.nav-sidebar {
width: 140px;
left: -140px;
top: 0;
bottom: 0;
max-height: 100vh;
border-radius: 0;
border-left: none;
padding-top: 4rem;
}
#sidebar-toggle:checked ~ .nav-sidebar {
left: 0;
}
.sidebar-toggle-container {
display: block;
top: 1rem;
left: 1rem;
}
.sidebar-toggle-btn {
width: 36px;
height: 36px;
font-size: 1.2rem;
background: var(--bg-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
@media (max-width: 768px) {
/* iOS-specific optimizations */
body {
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}
/* Keep dark mode toggle on mobile, just reposition */
.dark-mode-toggle {
top: 1rem;
right: 1rem;
margin: 0;
min-width: 44px;
min-height: 44px;
}
/* Adjust article width for mobile */
article {
width: 95%;
padding: 1rem;
}
/* Optimize typography for mobile with better contrast */
body {
font-size: 16px;
}
h1 {
font-size: 2.2rem;
line-height: 2.4rem;
font-weight: 800;
color: #000;
letter-spacing: -0.02em;
}
[data-theme="dark"] h1 {
color: #fff;
}
h2 {
font-size: 1.65rem;
line-height: 1.85rem;
font-weight: 700;
color: #000;
font-style: normal;
}
[data-theme="dark"] h2 {
color: #fff;
}
h3 {
font-size: 1.3rem;
font-weight: 700;
color: #000;
}
[data-theme="dark"] h3 {
color: #fff;
}
p {
font-size: 1rem;
line-height: 1.8;
color: var(--text-color);
}
/* Enhanced link visibility for mobile - strong contrast */
a {
border-bottom: 2px solid #999;
padding-bottom: 1px;
color: #000;
font-weight: 500;
}
[data-theme="dark"] a {
border-bottom-color: #666;
color: #e0e0e0;
}
a:hover, a:active {
border-bottom-color: #333;
}
[data-theme="dark"] a:hover,
[data-theme="dark"] a:active {
border-bottom-color: #999;
}
/* Touch target sizing only for interactive elements, not inline text links */
button, .btn, input[type="submit"], .quick-link-btn {
min-height: 44px;
min-width: 44px;
}
/* Make max-width sections full width on mobile */
section p[style*="max-width"],
section div[style*="max-width"],
.intro-text,
.plan-overview,
.topic-overview,
.verse-lookup,
.share-container,
.sample-days,
.subtopics-container,
.plan-stats {
max-width: 100% !important;
}
/* Optimize sidenotes for mobile with strong contrast */
.sidenote,
.marginnote {
display: block;
float: none;
width: 100%;
margin: 1rem 0 1rem 1.5rem;
padding: 0.75rem 0 0.75rem 1rem;
border-left: 4px solid #999;
font-size: 0.95rem;
line-height: 1.6;
color: #444 !important;
background-color: transparent !important;
font-weight: 400;
}
[data-theme="dark"] .sidenote,
[data-theme="dark"] .marginnote {
border-left-color: #666;
color: #aaa !important;
background-color: #151515 !important;
}
@media (prefers-color-scheme: dark) {
.sidenote:not([data-theme]),
.marginnote:not([data-theme]) {
color: #aaa !important;
background-color: #151515 !important;
}
}
.sidenote-number,
.margin-toggle {
display: inline;
}
/* Stack plan stats vertically */
.plan-stats {
flex-direction: column;
gap: 1rem;
}
/* Optimize grids for mobile */
.book-grid,
.plan-grid,
.topic-grid {
grid-template-columns: 1fr !important;
gap: 1rem;
max-width: 100% !important;
}
/* Optimize verse lookup form */
.lookup-form {
flex-direction: column;
}
.lookup-input,
.lookup-btn {
width: 100%;
}
/* Optimize share buttons */
.share-buttons {
flex-direction: column;
}
.share-btn {
width: 100%;
justify-content: center;
}
/* Optimize breadcrumbs with strong contrast */
.breadcrumb {
font-size: 0.95rem;
flex-wrap: wrap;
border-bottom: 3px solid #999;
padding-bottom: 0.75rem;
}
[data-theme="dark"] .breadcrumb {
border-bottom-color: #666;
}
.breadcrumb a {
font-weight: 600;
border-bottom: 2px solid #999;
color: #000;
}
[data-theme="dark"] .breadcrumb a {
border-bottom-color: #666;
color: #e0e0e0;
}
/* Improve button visibility on mobile with strong contrast */
button, .btn, input[type="submit"] {
min-height: 44px;
min-width: 44px;
padding: 0.75rem 1.25rem;
font-size: 1rem;
font-weight: 700;
border: 3px solid #111;
background: #111;
color: #fff;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] button,
[data-theme="dark"] .btn,
[data-theme="dark"] input[type="submit"] {
border-color: #ddd;
background: #ddd;
color: #111;
}
/* Improve section dividers with strong contrast */
/* Optimize verse text */
.verse-text {
font-size: 1.4rem;
line-height: 2rem;
}
/* Make tables responsive */
table {
display: block;
overflow-x: auto;
white-space: nowrap;
}
/* Optimize epigraph */
.epigraph {
margin: 2rem 0;
}
.epigraph blockquote {
padding: 1rem;
font-size: 1.1rem;
}
}
/* Extra small screens (phones in portrait) */
@media (max-width: 480px) {
article {
width: 100%;
padding: 0.5rem;
transition: transform 0.3s ease;
}
#sidebar-toggle:checked ~ article {
transform: translateX(140px);
}
h1 {
font-size: 1.75rem;
}
h2 {
font-size: 1.3rem;
}
.verse-text {
font-size: 1.2rem;
line-height: 1.8rem;
}
.dark-mode-toggle,
.sidebar-toggle-container {
top: 0.5rem;
}
.dark-mode-toggle {
right: 0.5rem;
}
#sidebar-toggle:checked ~ .dark-mode-toggle {
transform: translateX(140px);
}
}
/* Print styles for beautiful printed pages */
@media print {
/* Use light colors for print */
:root {
--bg-color: white;
--text-color: black;
--text-secondary: #333;
--border-color: #ccc;
}
body {
background: white;
color: black;
font-size: 12pt;
line-height: 1.6;
}
/* Hide navigation elements */
.nav-sidebar,
.sidebar-toggle-container,
.dark-mode-toggle,
.breadcrumb {
display: none !important;
}
/* Expand article to full width */
article {
width: 100% !important;
max-width: 100% !important;
padding: 0;
margin: 0;
}
/* Optimize typography for print */
h1 {
font-size: 24pt;
margin-top: 0;
page-break-after: avoid;
}
h2 {
font-size: 18pt;
page-break-after: avoid;
}
h3 {
font-size: 14pt;
page-break-after: avoid;
}
p {
font-size: 12pt;
orphans: 3;
widows: 3;
}
/* Avoid breaking inside elements */
section,
.verse-item,
.angel-entry,
.prophet-entry,
.name-entry,
.parable-entry,
.covenant-entry,
.apostle-entry,
.woman-entry,
.festival-entry {
page-break-inside: avoid;
}
/* Make sidenotes visible in print */
.sidenote,
.marginnote {
display: block !important;
float: none !important;
width: 100% !important;
margin: 0.5rem 0 0.5rem 2rem !important;
padding: 0.5rem;
border-left: 2px solid #ccc;
font-size: 10pt;
color: #333;
}
/* Hide sidenote toggles */
.margin-toggle {
display: none !important;
}
/* Show URLs for links */
a[href^="http"]:after {
content: " (" attr(href) ")";
font-size: 10pt;
color: #666;
}
/* Don't show URLs for internal links */
a[href^="/"]:after {
content: "";
}
/* Optimize verse display */
.verse-item {
margin: 0.5rem 0;
padding-left: 1rem;
}
.verse-ref {
font-weight: bold;
}
.verse-text {
max-width: 100%;
}
/* Remove link underlines for cleaner print */
a {
color: black;
text-decoration: none;
border-bottom: none;
}
/* Page breaks */
h1, h2 {
page-break-before: auto;
}
/* Add chapter/verse numbers in margin for reference */
@page {
margin: 2cm;
}
}
</style>
</head>
<body>
<input type="checkbox" id="sidebar-toggle">
<p class="sidebar-toggle-container">
<label for="sidebar-toggle" class="sidebar-toggle-btn" title="Toggle sidebar"></label>
</p>
<p class="dark-mode-toggle">
<button class="dark-mode-btn" title="Toggle dark mode" onclick="toggleDarkMode()"></button>
</p>
<article>
{% if breadcrumbs %}
<nav class="breadcrumb">
{% for crumb in breadcrumbs %}
{% if not loop.last %}
<a href="{{ crumb.url }}">{{ crumb.text }}</a>
<span class="breadcrumb-separator">&gt;</span>
{% else %}
<span>{{ crumb.text }}</span>
{% endif %}
{% endfor %}
</nav>
{% endif %}
{% block content %}{% endblock %}
</article>
<!-- Floating Navigation Sidebar -->
<nav class="nav-sidebar">
<!-- Search Box -->
<div class="sidebar-search">
<input type="text" id="sidebar-search-input" placeholder="Search..." autocomplete="off">
</div>
<!-- Navigation -->
<h3>Navigation</h3>
<ul>
<li><a href="/" {% if request.url.path == "/" %}class="current"{% endif %}>Home</a></li>
<li><a href="/books">Books</a></li>
<li><a href="/resources">Resources</a></li>
<li><a href="/verse-of-the-day">Verse of the Day</a></li>
<li><a href="/random-verse">Random Verse</a></li>
<li><a href="/reading-plans">Reading Plans</a></li>
<li><a href="/topics">Topics</a></li>
<li><a href="/concordance">Concordance</a></li>
<li><a href="/interlinear">Interlinear</a></li>
<li><a href="/search">Search</a></li>
</ul>
<!-- Bible Books -->
{% if books %}
<h3>Books</h3>
<details id="old-testament">
<summary>Old Testament</summary>
<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>
</details>
<details id="new-testament">
<summary>New Testament</summary>
<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>
</details>
{% endif %}
<!-- Resources organized by category -->
<details class="resource-group">
<summary>People</summary>
<ul>
<li><a href="/biblical-prophets">Biblical Prophets</a></li>
<li><a href="/the-twelve-apostles">The Twelve Apostles</a></li>
<li><a href="/women-of-the-bible">Women of the Bible</a></li>
<li><a href="/family-tree">Genealogies</a></li>
</ul>
</details>
<details class="resource-group">
<summary>Theology</summary>
<ul>
<li><a href="/biblical-angels">Biblical Angels</a></li>
<li><a href="/tetragrammaton">The Tetragrammaton</a></li>
<li><a href="/names-of-god">Names of God</a></li>
<li><a href="/parables">Parables of Jesus</a></li>
<li><a href="/biblical-covenants">Biblical Covenants</a></li>
<li><a href="/fruits-of-the-spirit">Fruits of the Spirit</a></li>
</ul>
</details>
<details class="resource-group">
<summary>History & Culture</summary>
<ul>
<li><a href="/biblical-festivals">Biblical Festivals</a></li>
<li><a href="/biblical-maps">Biblical Geography</a></li>
<li><a href="/biblical-timeline">Timeline</a></li>
</ul>
</details>
<details class="resource-group">
<summary>Study Tools</summary>
<ul>
<li><a href="/study-guides">Study Guides</a></li>
<li><a href="/topics/Parenting">Parenting</a></li>
</ul>
</details>
<!-- Source Code -->
<div style="margin-top: 2rem; padding-top: 1rem; border-top: 1px solid var(--border-color);">
<p style="font-size: 0.85rem; color: var(--text-tertiary); text-align: center;">
<a href="https://github.com/kennethreitz/kjvstudy.org" target="_blank" rel="noopener" style="color: var(--text-tertiary); text-decoration: none; border-bottom: 1px dotted var(--border-color-dark);">View Source Code</a>
</p>
</div>
<!-- Flourish -->
<div class="sidebar-flourish"></div>
</nav>
<script type="text/javascript">
// Dark mode functionality
(function() {
// Check for saved theme preference or default to light mode
const currentTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', currentTheme);
})();
function toggleDarkMode() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
// Sidebar collapse state persistence
(function() {
var toggle = document.getElementById('sidebar-toggle');
var expanded = localStorage.getItem('sidebarExpanded') === 'true';
if (expanded) {
toggle.checked = true;
}
toggle.addEventListener('change', function() {
localStorage.setItem('sidebarExpanded', toggle.checked);
});
})();
// Sidebar search functionality
(function() {
var searchInput = document.getElementById('sidebar-search-input');
if (!searchInput) return;
var oldTestament = document.getElementById('old-testament');
var newTestament = document.getElementById('new-testament');
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && this.value.trim()) {
window.location.href = '/search?q=' + encodeURIComponent(this.value.trim());
}
});
// Filter sidebar items as user types
searchInput.addEventListener('input', function() {
var query = this.value.toLowerCase();
var sidebar = document.querySelector('.nav-sidebar');
var links = sidebar.querySelectorAll('a');
// Auto-expand Bible book sections when searching
if (query !== '') {
if (oldTestament) oldTestament.open = true;
if (newTestament) newTestament.open = true;
} else {
// Collapse when search is cleared
if (oldTestament) oldTestament.open = false;
if (newTestament) newTestament.open = false;
}
links.forEach(function(link) {
var text = link.textContent.toLowerCase();
var listItem = link.closest('li');
if (listItem) {
if (query === '' || text.includes(query)) {
listItem.style.display = '';
} else {
listItem.style.display = 'none';
}
}
});
});
})();
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
// Don't trigger if user is typing in an input field
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
// Allow Escape to clear focus
if (e.key === 'Escape') {
e.target.blur();
}
return;
}
// Cmd/Ctrl + D: Toggle dark mode
if ((e.metaKey || e.ctrlKey) && e.key === 'd') {
e.preventDefault();
toggleDarkMode();
}
// Cmd/Ctrl + B: Toggle sidebar
if ((e.metaKey || e.ctrlKey) && e.key === 'b') {
e.preventDefault();
var toggle = document.getElementById('sidebar-toggle');
if (toggle) {
toggle.checked = !toggle.checked;
toggle.dispatchEvent(new Event('change'));
}
}
// Cmd/Ctrl + K or /: Focus search
if (((e.metaKey || e.ctrlKey) && e.key === 'k') || e.key === '/') {
e.preventDefault();
window.location.href = '/search';
}
// g: Quick verse lookup
if (e.key === 'g') {
e.preventDefault();
showVerseLookup();
}
// r: Random verse
if (e.key === 'r') {
e.preventDefault();
window.location.href = '/random-verse';
}
// ?: Show keyboard shortcuts help
if (e.key === '?' && !e.shiftKey) {
showKeyboardHelp();
}
});
// Quick verse lookup
function showVerseLookup() {
var reference = prompt('Enter verse reference (e.g., John 3:16, Psalm 23, Genesis 1):');
if (!reference) return;
reference = reference.trim();
// Try to match: Book Chapter:Verse
var match = reference.match(/^(.+?)\s+(\d+):(\d+)$/i);
if (match) {
var book = match[1].trim();
var chapter = match[2];
var verse = match[3];
window.location.href = '/book/' + encodeURIComponent(book) + '/chapter/' + chapter + '/verse/' + verse;
return;
}
// Try to match: Book Chapter
match = reference.match(/^(.+?)\s+(\d+)$/i);
if (match) {
var book = match[1].trim();
var chapter = match[2];
window.location.href = '/book/' + encodeURIComponent(book) + '/chapter/' + chapter;
return;
}
// Try to match: Book
match = reference.match(/^(.+)$/i);
if (match) {
var book = match[1].trim();
window.location.href = '/book/' + encodeURIComponent(book);
return;
}
}
// Keyboard shortcuts help modal
function showKeyboardHelp() {
var helpText = 'Keyboard Shortcuts:\\n\\n' +
'g - Quick verse lookup\\n' +
'r - Random verse\\n' +
'Cmd/Ctrl + D - Toggle dark mode\\n' +
'Cmd/Ctrl + B - Toggle sidebar\\n' +
'Cmd/Ctrl + K - Go to search\\n' +
'/ - Go to search\\n' +
'? - Show this help\\n' +
'Esc - Clear focus';
alert(helpText);
}
// Verse tooltip functionality
(function() {
// Create tooltip element
var tooltip = document.createElement('div');
tooltip.className = 'verse-tooltip';
document.body.appendChild(tooltip);
// Cache for fetched verses
var verseCache = {};
// Parse verse URL to extract book, chapter, and verse
function parseVerseUrl(url) {
// Try to match single verse URL: /book/John/chapter/3/verse/16
var match = url.match(/\/book\/([^\/]+)\/chapter\/(\d+)\/verse\/(\d+)/);
if (match) {
return {
book: decodeURIComponent(match[1]),
chapter: match[2],
verse: match[3],
verseEnd: null,
cacheKey: match[1] + '_' + match[2] + '_' + match[3],
isRange: false
};
}
// Try to match verse range URL: /book/Proverbs/chapter/31#verse-26-28
match = url.match(/\/book\/([^\/]+)\/chapter\/(\d+)#verse-(\d+)-(\d+)/);
if (match) {
return {
book: decodeURIComponent(match[1]),
chapter: match[2],
verse: match[3],
verseEnd: match[4],
cacheKey: match[1] + '_' + match[2] + '_' + match[3] + '-' + match[4],
isRange: true
};
}
return null;
}
// Fetch verse text from server
async function fetchVerseText(book, chapter, verse, verseEnd, cacheKey) {
// Check cache first
if (verseCache[cacheKey]) {
return verseCache[cacheKey];
}
try {
var url, reference;
if (verseEnd) {
// Fetch chapter page for verse range
url = '/book/' + encodeURIComponent(book) + '/chapter/' + chapter;
reference = book + ' ' + chapter + ':' + verse + '-' + verseEnd;
} else {
// Fetch single verse page
url = '/book/' + encodeURIComponent(book) + '/chapter/' + chapter + '/verse/' + verse;
reference = book + ' ' + chapter + ':' + verse;
}
var response = await fetch(url);
if (!response.ok) throw new Error('Failed to fetch verse');
var html = await response.text();
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var verseText;
if (verseEnd) {
// Extract verse range from chapter page
var verses = [];
var verseStart = parseInt(verse);
var verseEndNum = parseInt(verseEnd);
for (var i = verseStart; i <= verseEndNum; i++) {
var verseP = doc.querySelector('#verse-' + i);
if (verseP) {
// Clone the element to avoid modifying the original
var clone = verseP.cloneNode(true);
// Remove verse number link
var verseLink = clone.querySelector('.verse-number-link');
if (verseLink) verseLink.remove();
// Remove sidenotes and marginnotes
var notes = clone.querySelectorAll('.sidenote, .marginnote, .margin-toggle, label.margin-toggle');
notes.forEach(function(note) { note.remove(); });
var text = clone.textContent.trim();
if (text) {
verses.push(text);
}
}
}
verseText = verses.length > 0 ? verses.join(' ') : 'Verse range not found';
} else {
// Extract single verse text from verse page
var verseElement = doc.querySelector('.verse-text');
if (!verseElement) {
// Try alternative selectors
verseElement = doc.querySelector('[class*="verse"]');
}
verseText = verseElement ? verseElement.textContent.trim() : 'Verse text not found';
}
// Cache the result
verseCache[cacheKey] = {
reference: reference,
text: verseText
};
return verseCache[cacheKey];
} catch (error) {
console.error('Error fetching verse:', error);
return {
reference: verseEnd ? book + ' ' + chapter + ':' + verse + '-' + verseEnd : book + ' ' + chapter + ':' + verse,
text: 'Error loading verse'
};
}
}
// Show tooltip
function showTooltip(verseData, mouseX, mouseY) {
tooltip.innerHTML =
'<span class="verse-tooltip-reference">' + verseData.reference + '</span>' +
'<span class="verse-tooltip-text">' + verseData.text + '</span>';
// Position tooltip
var tooltipRect = tooltip.getBoundingClientRect();
var x = mouseX + 15;
var y = mouseY + 15;
// Adjust if tooltip goes off right edge
if (x + tooltipRect.width > window.innerWidth) {
x = mouseX - tooltipRect.width - 15;
}
// Adjust if tooltip goes off bottom edge
if (y + tooltipRect.height > window.innerHeight) {
y = mouseY - tooltipRect.height - 15;
}
tooltip.style.left = x + 'px';
tooltip.style.top = y + 'px';
tooltip.classList.add('show');
}
// Hide tooltip
function hideTooltip() {
tooltip.classList.remove('show');
}
// Event delegation for verse links
document.addEventListener('mouseover', function(e) {
var target = e.target;
// Check if target is a link or inside a link
if (target.tagName !== 'A') {
target = target.closest('a');
}
if (!target || !target.href) return;
var verseInfo = parseVerseUrl(target.href);
if (!verseInfo) return;
// Show loading state
tooltip.innerHTML = '<span class="verse-tooltip-loading">Loading...</span>';
tooltip.style.left = (e.pageX + 15) + 'px';
tooltip.style.top = (e.pageY + 15) + 'px';
tooltip.classList.add('show');
// Fetch and display verse
fetchVerseText(verseInfo.book, verseInfo.chapter, verseInfo.verse, verseInfo.verseEnd, verseInfo.cacheKey)
.then(function(verseData) {
// Only show if still hovering
if (target.matches(':hover')) {
showTooltip(verseData, e.pageX, e.pageY);
}
});
// Track mouse movement for tooltip positioning
var mouseMoveHandler = function(e) {
if (tooltip.classList.contains('show')) {
var x = e.pageX + 15;
var y = e.pageY + 15;
tooltip.style.left = x + 'px';
tooltip.style.top = y + 'px';
}
};
target.addEventListener('mousemove', mouseMoveHandler);
// Hide tooltip on mouse leave
target.addEventListener('mouseleave', function() {
hideTooltip();
target.removeEventListener('mousemove', mouseMoveHandler);
}, { once: true });
});
})();
// Gauges analytics
var _gauges = _gauges || [];
(function() {
var t = document.createElement('script');
t.type = 'text/javascript';
t.async = true;
t.id = 'gauges-tracker';
t.setAttribute('data-site-id', '6834bd650d851064ae28dc13');
t.setAttribute('data-track-path', 'https://track.gaug.es/track.gif');
t.src = 'https://d2fuc4clr7gvcn.cloudfront.net/track.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(t, s);
})();
</script>
</body>
</html>