mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
Add keyboard navigation to commentary and stories pages
- commentary.html: verse card navigation with up/down, enter to view - stories_index.html: 2D grid navigation for story cards - stories_kids_index.html: 2D grid navigation for kids story cards 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -496,19 +496,56 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
target.style.transition = 'background-color 1s';
|
||||
target.style.backgroundColor = 'rgba(255, 235, 59, 0.5)';
|
||||
|
||||
|
||||
// Get verse number to show in toast
|
||||
const verseMatch = window.location.hash.match(/verse-(\d+)/);
|
||||
if (verseMatch && verseMatch[1]) {
|
||||
showToast('Navigated to Verse ' + verseMatch[1]);
|
||||
}
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
target.style.backgroundColor = '';
|
||||
}, 2000);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Keyboard navigation for verse cards
|
||||
const verseCards = Array.from(document.querySelectorAll('.verse-card[id^="verse-"]'));
|
||||
if (verseCards.length === 0) return;
|
||||
|
||||
let selectedIndex = -1;
|
||||
|
||||
function selectCard(index) {
|
||||
if (selectedIndex >= 0 && selectedIndex < verseCards.length) {
|
||||
verseCards[selectedIndex].style.outline = '';
|
||||
verseCards[selectedIndex].style.outlineOffset = '';
|
||||
}
|
||||
selectedIndex = Math.max(0, Math.min(index, verseCards.length - 1));
|
||||
verseCards[selectedIndex].style.outline = '2px solid #4a7c59';
|
||||
verseCards[selectedIndex].style.outlineOffset = '4px';
|
||||
verseCards[selectedIndex].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
||||
|
||||
if (e.key === 'ArrowDown' || e.key === 'j') {
|
||||
e.preventDefault();
|
||||
selectCard(selectedIndex < 0 ? 0 : selectedIndex + 1);
|
||||
} else if (e.key === 'ArrowUp' || e.key === 'k') {
|
||||
e.preventDefault();
|
||||
if (selectedIndex <= 0) selectCard(0);
|
||||
else selectCard(selectedIndex - 1);
|
||||
} else if (e.key === 'ArrowLeft' || e.key === 'h') {
|
||||
e.preventDefault();
|
||||
history.back();
|
||||
} else if (e.key === 'Enter' && selectedIndex >= 0) {
|
||||
e.preventDefault();
|
||||
const verseLink = verseCards[selectedIndex].querySelector('.verse-action[href*="/book/"]');
|
||||
if (verseLink) window.location.href = verseLink.href;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -450,6 +450,68 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard navigation for story cards (2D grid)
|
||||
var visibleStories = function() {
|
||||
return Array.from(document.querySelectorAll('.story-card:not(.hidden)'));
|
||||
};
|
||||
var selectedCardIndex = -1;
|
||||
|
||||
function getGridColumns() {
|
||||
var grid = document.querySelector('.stories-grid');
|
||||
if (!grid) return 1;
|
||||
var style = getComputedStyle(grid);
|
||||
var cols = style.gridTemplateColumns.split(' ').length;
|
||||
return cols || 1;
|
||||
}
|
||||
|
||||
function selectStoryCard(index) {
|
||||
var cards = visibleStories();
|
||||
if (cards.length === 0) return;
|
||||
|
||||
if (selectedCardIndex >= 0 && selectedCardIndex < cards.length) {
|
||||
cards[selectedCardIndex].style.outline = '';
|
||||
cards[selectedCardIndex].style.outlineOffset = '';
|
||||
}
|
||||
|
||||
selectedCardIndex = Math.max(0, Math.min(index, cards.length - 1));
|
||||
cards[selectedCardIndex].style.outline = '2px solid #4a7c59';
|
||||
cards[selectedCardIndex].style.outlineOffset = '4px';
|
||||
cards[selectedCardIndex].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
||||
|
||||
var cards = visibleStories();
|
||||
if (cards.length === 0) return;
|
||||
|
||||
var cols = getGridColumns();
|
||||
|
||||
if (e.key === 'ArrowDown' || e.key === 'j') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else selectStoryCard(selectedCardIndex + cols);
|
||||
} else if (e.key === 'ArrowUp' || e.key === 'k') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else if (selectedCardIndex - cols >= 0) selectStoryCard(selectedCardIndex - cols);
|
||||
} else if (e.key === 'ArrowRight' || e.key === 'l') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else selectStoryCard(selectedCardIndex + 1);
|
||||
} else if (e.key === 'ArrowLeft' || e.key === 'h') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex <= 0) history.back();
|
||||
else selectStoryCard(selectedCardIndex - 1);
|
||||
} else if (e.key === 'Enter' && selectedCardIndex >= 0) {
|
||||
e.preventDefault();
|
||||
var cards = visibleStories();
|
||||
if (cards[selectedCardIndex]) {
|
||||
window.location.href = cards[selectedCardIndex].href;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -488,6 +488,68 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard navigation for story cards (2D grid)
|
||||
var visibleStories = function() {
|
||||
return Array.from(document.querySelectorAll('.kids-story-card:not(.hidden)'));
|
||||
};
|
||||
var selectedCardIndex = -1;
|
||||
|
||||
function getGridColumns() {
|
||||
var grid = document.querySelector('.stories-grid');
|
||||
if (!grid) return 1;
|
||||
var style = getComputedStyle(grid);
|
||||
var cols = style.gridTemplateColumns.split(' ').length;
|
||||
return cols || 1;
|
||||
}
|
||||
|
||||
function selectStoryCard(index) {
|
||||
var cards = visibleStories();
|
||||
if (cards.length === 0) return;
|
||||
|
||||
if (selectedCardIndex >= 0 && selectedCardIndex < cards.length) {
|
||||
cards[selectedCardIndex].style.outline = '';
|
||||
cards[selectedCardIndex].style.outlineOffset = '';
|
||||
}
|
||||
|
||||
selectedCardIndex = Math.max(0, Math.min(index, cards.length - 1));
|
||||
cards[selectedCardIndex].style.outline = '2px solid #8b5cf6';
|
||||
cards[selectedCardIndex].style.outlineOffset = '4px';
|
||||
cards[selectedCardIndex].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
||||
|
||||
var cards = visibleStories();
|
||||
if (cards.length === 0) return;
|
||||
|
||||
var cols = getGridColumns();
|
||||
|
||||
if (e.key === 'ArrowDown' || e.key === 'j') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else selectStoryCard(selectedCardIndex + cols);
|
||||
} else if (e.key === 'ArrowUp' || e.key === 'k') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else if (selectedCardIndex - cols >= 0) selectStoryCard(selectedCardIndex - cols);
|
||||
} else if (e.key === 'ArrowRight' || e.key === 'l') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex < 0) selectStoryCard(0);
|
||||
else selectStoryCard(selectedCardIndex + 1);
|
||||
} else if (e.key === 'ArrowLeft' || e.key === 'h') {
|
||||
e.preventDefault();
|
||||
if (selectedCardIndex <= 0) history.back();
|
||||
else selectStoryCard(selectedCardIndex - 1);
|
||||
} else if (e.key === 'Enter' && selectedCardIndex >= 0) {
|
||||
e.preventDefault();
|
||||
var cards = visibleStories();
|
||||
if (cards[selectedCardIndex]) {
|
||||
window.location.href = cards[selectedCardIndex].href;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user