mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
3336863a4d
- Add KJVNav.initGridNav for standardized 2D grid navigation - Migrate books.html, topics.html, resources.html to use initGridNav - Add sidebarActive check to all templates with custom keyboard handlers - Add [ and ] shortcuts for prev/next chapter on chapter pages - Add [ and ] shortcuts for prev/next book on book pages - Update accessibility page with comprehensive keyboard shortcut docs - Add honest note about keyboard navigation complexity - Fix sidebar nav conflicting with main content selection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
375 lines
12 KiB
HTML
375 lines
12 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Bible Reading Plans - KJV Study{% endblock %}
|
|
{% block description %}Structured Bible reading schedules for systematic Scripture study{% endblock %}
|
|
|
|
{% block head %}
|
|
<style>
|
|
.plan-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 1.5rem;
|
|
max-width: 90%;
|
|
margin: 2rem 0;
|
|
}
|
|
|
|
.plan-card {
|
|
display: block;
|
|
padding: 1.5rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 4px;
|
|
transition: all 0.2s;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.plan-card:hover {
|
|
border-color: var(--border-color-darker);
|
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.plan-name {
|
|
font-size: 1.4rem;
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
color: var(--link-color);
|
|
}
|
|
|
|
.plan-card:hover .plan-name {
|
|
color: var(--link-hover);
|
|
}
|
|
|
|
.plan-description {
|
|
font-size: 1rem;
|
|
color: var(--text-secondary);
|
|
line-height: 1.6;
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
.plan-duration {
|
|
font-size: 0.9rem;
|
|
color: var(--text-tertiary);
|
|
font-style: italic;
|
|
margin-top: 0.75rem;
|
|
}
|
|
|
|
.plan-progress {
|
|
margin-top: 0.75rem;
|
|
display: none;
|
|
}
|
|
|
|
.plan-progress.has-progress {
|
|
display: block;
|
|
}
|
|
|
|
.plan-progress-bar {
|
|
height: 6px;
|
|
background: var(--border-color);
|
|
border-radius: 3px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.plan-progress-fill {
|
|
height: 100%;
|
|
background: #4a7c59;
|
|
transition: width 0.3s;
|
|
}
|
|
|
|
.plan-progress-text {
|
|
font-size: 0.8rem;
|
|
color: #4a7c59;
|
|
margin-top: 0.3rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.your-plans {
|
|
display: none;
|
|
}
|
|
|
|
.your-plans.has-plans {
|
|
display: block;
|
|
}
|
|
|
|
.your-plans-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 1rem 0;
|
|
max-width: 60%;
|
|
}
|
|
|
|
.your-plans-list li {
|
|
padding: 0.75rem 1rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 4px;
|
|
margin-bottom: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
background: linear-gradient(to right, rgba(74, 124, 89, 0.15) var(--progress, 0%), var(--code-bg) var(--progress, 0%));
|
|
position: relative;
|
|
}
|
|
|
|
.your-plans-list li:hover {
|
|
border-color: #4a7c59;
|
|
}
|
|
|
|
.your-plan-link {
|
|
font-weight: 600;
|
|
color: var(--link-color);
|
|
text-decoration: none;
|
|
border-bottom: none;
|
|
}
|
|
|
|
.your-plan-link:hover {
|
|
color: #4a7c59;
|
|
}
|
|
|
|
.your-plan-next {
|
|
color: var(--text-secondary);
|
|
font-size: 0.9rem;
|
|
margin-left: auto;
|
|
}
|
|
|
|
.your-plan-progress {
|
|
font-size: 0.85rem;
|
|
color: #4a7c59;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.your-plan-completed {
|
|
color: #4a7c59;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.intro-text {
|
|
max-width: 60%;
|
|
font-size: 1.2rem;
|
|
line-height: 1.9;
|
|
margin: 1rem 0;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<h1>Bible Reading Plans</h1>
|
|
<p class="subtitle">Structured Schedules for Systematic Scripture Study</p>
|
|
|
|
<section>
|
|
<p class="intro-text"><span class="newthought">Systematic Bible reading</span> provides structure for comprehensive Scripture engagement. These curated plans offer various approaches—chronological progression, thematic focus, or testament-specific study—each designed to facilitate sustained interaction with God's Word.</p>
|
|
|
|
<p class="intro-text">Whether pursuing canonical familiarity through complete Bible reading or concentrating on specific portions, these schedules provide daily guidance for disciplined Scripture intake. Select a plan suited to your current season and study objectives.</p>
|
|
</section>
|
|
|
|
<section id="your-reading-plans" class="your-plans">
|
|
<h2 id="your-plans-heading">Your Reading Plans</h2>
|
|
<ul class="your-plans-list" id="your-plans-list"></ul>
|
|
</section>
|
|
|
|
<section id="available-reading-plans">
|
|
<h2>Available Reading Plans</h2>
|
|
|
|
<div class="plan-grid">
|
|
{% for plan in plans %}
|
|
<a href="/reading-plans/{{ plan.id }}" class="plan-card" data-plan-id="{{ plan.id }}" data-total-days="{{ plan.days }}">
|
|
<div class="plan-name">{{ plan.name }}</div>
|
|
<div class="plan-description">{{ plan.description }}</div>
|
|
<div class="plan-duration">{{ plan.days }} days</div>
|
|
<div class="plan-progress">
|
|
<div class="plan-progress-bar">
|
|
<div class="plan-progress-fill" style="width: 0%"></div>
|
|
</div>
|
|
<div class="plan-progress-text"></div>
|
|
</div>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
|
|
<section id="using-reading-plans">
|
|
<h2>Using Reading Plans</h2>
|
|
<p class="intro-text">Select a plan above to view its complete schedule. Each plan provides daily readings with thematic notes. Consider marking your progress and maintaining consistency—even brief daily reading surpasses sporadic lengthy sessions in forming lasting Scripture engagement habits.</p>
|
|
</section>
|
|
|
|
<script>
|
|
(function() {
|
|
// Load and display progress for each plan
|
|
const cards = Array.from(document.querySelectorAll('.plan-card'));
|
|
var yourPlansSection = document.getElementById('your-plans');
|
|
var yourPlansList = document.getElementById('your-plans-list');
|
|
var plansWithProgress = [];
|
|
|
|
cards.forEach(function(card) {
|
|
var planId = card.dataset.planId;
|
|
var totalDays = parseInt(card.dataset.totalDays);
|
|
var storageKey = 'reading-plan-' + planId;
|
|
var saved = localStorage.getItem(storageKey);
|
|
|
|
if (saved) {
|
|
try {
|
|
var data = JSON.parse(saved);
|
|
var completed = data.completed ? data.completed.length : 0;
|
|
if (completed > 0) {
|
|
var percent = Math.round((completed / totalDays) * 100);
|
|
var progressEl = card.querySelector('.plan-progress');
|
|
var fillEl = card.querySelector('.plan-progress-fill');
|
|
var textEl = card.querySelector('.plan-progress-text');
|
|
|
|
progressEl.classList.add('has-progress');
|
|
fillEl.style.width = percent + '%';
|
|
|
|
if (completed === totalDays) {
|
|
textEl.textContent = 'Completed!';
|
|
} else {
|
|
textEl.textContent = completed + '/' + totalDays + ' days (' + percent + '%)';
|
|
}
|
|
|
|
// Add to your plans list
|
|
var planName = card.querySelector('.plan-name').textContent;
|
|
var nextDay = completed + 1;
|
|
var isComplete = completed >= totalDays;
|
|
|
|
plansWithProgress.push({
|
|
id: planId,
|
|
name: planName,
|
|
completed: completed,
|
|
totalDays: totalDays,
|
|
nextDay: nextDay,
|
|
isComplete: isComplete,
|
|
percent: percent
|
|
});
|
|
}
|
|
} catch(e) {}
|
|
}
|
|
});
|
|
|
|
// Populate "Your Reading Plans" section
|
|
if (plansWithProgress.length > 0) {
|
|
yourPlansSection.classList.add('has-plans');
|
|
var heading = document.getElementById('your-plans-heading');
|
|
if (plansWithProgress.length === 1) {
|
|
heading.textContent = 'Your Reading Plan';
|
|
}
|
|
plansWithProgress.forEach(function(plan) {
|
|
var li = document.createElement('li');
|
|
var statusText;
|
|
if (plan.isComplete) {
|
|
statusText = '<span class="your-plan-completed">Completed!</span>';
|
|
} else {
|
|
statusText = '<span class="your-plan-next">Up next: Day ' + plan.nextDay + '</span>';
|
|
}
|
|
li.style.setProperty('--progress', plan.percent + '%');
|
|
li.innerHTML = '<a href="/reading-plans/' + plan.id + '" class="your-plan-link">' + plan.name + '</a>' +
|
|
'<span class="your-plan-progress">' + plan.percent + '%</span>' +
|
|
statusText;
|
|
yourPlansList.appendChild(li);
|
|
});
|
|
}
|
|
|
|
// Keyboard navigation - combine your plans list items + grid cards
|
|
var yourPlanItems = Array.from(document.querySelectorAll('.your-plans-list li'));
|
|
var allNavItems = yourPlanItems.concat(Array.from(cards));
|
|
|
|
if (allNavItems.length === 0) return;
|
|
|
|
var selectedIndex = -1;
|
|
var yourPlansCount = yourPlanItems.length;
|
|
|
|
function getGridColumns() {
|
|
if (window.innerWidth <= 768) return 1;
|
|
const grid = document.querySelector('.plan-grid');
|
|
if (!grid) return 1;
|
|
const style = getComputedStyle(grid);
|
|
const cols = style.gridTemplateColumns.split(' ').length;
|
|
return cols || 1;
|
|
}
|
|
|
|
function clearSelection() {
|
|
if (selectedIndex >= 0 && selectedIndex < allNavItems.length) {
|
|
allNavItems[selectedIndex].style.outline = '';
|
|
allNavItems[selectedIndex].style.outlineOffset = '';
|
|
allNavItems[selectedIndex].classList.remove('selected');
|
|
}
|
|
}
|
|
|
|
function selectItem(index) {
|
|
clearSelection();
|
|
selectedIndex = Math.max(0, Math.min(index, allNavItems.length - 1));
|
|
allNavItems[selectedIndex].style.outline = '2px solid #4a7c59';
|
|
allNavItems[selectedIndex].style.outlineOffset = '2px';
|
|
allNavItems[selectedIndex].classList.add('selected');
|
|
allNavItems[selectedIndex].scrollIntoView({ behavior: 'auto', block: 'center' });
|
|
}
|
|
|
|
function getItemLink(item) {
|
|
// For li items, find the link inside; for cards, the item IS the link
|
|
if (item.tagName === 'LI') {
|
|
var link = item.querySelector('a');
|
|
return link ? link.href : null;
|
|
}
|
|
return item.href;
|
|
}
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
|
if (KJVNav.sidebarActive) return;
|
|
|
|
var cols = getGridColumns();
|
|
var inYourPlans = selectedIndex >= 0 && selectedIndex < yourPlansCount;
|
|
var inGrid = selectedIndex >= yourPlansCount;
|
|
|
|
if (e.key === 'ArrowDown' || e.key === 'j') {
|
|
e.preventDefault();
|
|
if (selectedIndex < 0) {
|
|
selectItem(0);
|
|
} else if (inYourPlans) {
|
|
// Move down in your plans list, or to grid
|
|
if (selectedIndex + 1 < yourPlansCount) {
|
|
selectItem(selectedIndex + 1);
|
|
} else {
|
|
selectItem(yourPlansCount); // First grid item
|
|
}
|
|
} else {
|
|
// In grid, move down by columns
|
|
selectItem(selectedIndex + cols);
|
|
}
|
|
} else if (e.key === 'ArrowUp' || e.key === 'k') {
|
|
e.preventDefault();
|
|
if (selectedIndex < 0) {
|
|
selectItem(0);
|
|
} else if (inYourPlans) {
|
|
if (selectedIndex > 0) selectItem(selectedIndex - 1);
|
|
} else {
|
|
// In grid
|
|
var newIndex = selectedIndex - cols;
|
|
if (newIndex >= yourPlansCount) {
|
|
selectItem(newIndex);
|
|
} else if (yourPlansCount > 0) {
|
|
// Jump to last your-plan item
|
|
selectItem(yourPlansCount - 1);
|
|
}
|
|
}
|
|
} else if (e.key === 'ArrowRight' || e.key === 'l') {
|
|
e.preventDefault();
|
|
if (selectedIndex < 0) selectItem(0);
|
|
else if (inGrid) selectItem(selectedIndex + 1);
|
|
} else if (e.key === 'ArrowLeft' || e.key === 'h') {
|
|
e.preventDefault();
|
|
if (selectedIndex <= 0) history.back();
|
|
else if (inGrid && selectedIndex > yourPlansCount) selectItem(selectedIndex - 1);
|
|
else if (inYourPlans) history.back();
|
|
} else if (e.key === 'Enter' && selectedIndex >= 0) {
|
|
e.preventDefault();
|
|
var href = getItemLink(allNavItems[selectedIndex]);
|
|
if (href) window.location.href = href;
|
|
} else if (e.key === 'Escape') {
|
|
e.preventDefault();
|
|
clearSelection();
|
|
selectedIndex = -1;
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|