mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
Enhance search dropdowns across site
- Limit stories page dropdown to only show stories (remove verse refs, topics) - Add universal search dropdown to /search page - Add stories-only dropdown to kids stories page - Disable verse tooltips on all search dropdown links - Fix cursor style on dropdown links (no help cursor) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -96,6 +96,18 @@
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* But not in search dropdowns */
|
||||
.search-results-dropdown a,
|
||||
.search-results-dropdown a[href*="/book/"],
|
||||
.search-dropdown a,
|
||||
.search-dropdown a[href*="/book/"],
|
||||
.lookup-results-dropdown a,
|
||||
.lookup-results-dropdown a[href*="/book/"],
|
||||
.story-search-dropdown a,
|
||||
.story-search-dropdown a[href*="/book/"] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.verse-tooltip {
|
||||
position: absolute;
|
||||
background: var(--bg-color);
|
||||
@@ -1777,6 +1789,10 @@
|
||||
// Skip if this is a verse number link (the number at the start of each verse)
|
||||
if (target.classList.contains('verse-number-link')) return;
|
||||
|
||||
// Skip links in search dropdowns
|
||||
if (target.closest('.search-results-dropdown') || target.closest('.search-dropdown') ||
|
||||
target.closest('.lookup-results-dropdown') || target.closest('.story-search-dropdown')) return;
|
||||
|
||||
var verseInfo = parseVerseUrl(target.pathname + target.hash);
|
||||
if (!verseInfo) return;
|
||||
|
||||
|
||||
@@ -7,27 +7,36 @@
|
||||
<style>
|
||||
.search-form {
|
||||
margin: 2rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
max-width: 55%;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
max-width: 55%;
|
||||
padding: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--border-color, #ccc);
|
||||
border-radius: 4px;
|
||||
background: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: #111;
|
||||
border-color: var(--text-color, #111);
|
||||
}
|
||||
|
||||
.search-button {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
background: var(--text-color, #111);
|
||||
color: var(--bg-color, #fff);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
@@ -35,7 +44,68 @@
|
||||
}
|
||||
|
||||
.search-button:hover {
|
||||
background: #333;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.search-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--bg-color);
|
||||
border: 1px solid var(--border-color-darker, #999);
|
||||
border-top: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.search-dropdown.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-result-category {
|
||||
padding: 0.5rem 0.75rem 0.25rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--text-tertiary);
|
||||
background: var(--code-bg);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.search-result-item {
|
||||
display: block;
|
||||
padding: 0.5rem 0.75rem;
|
||||
text-decoration: none;
|
||||
color: var(--text-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.search-result-item:hover,
|
||||
.search-result-item.selected {
|
||||
background: var(--code-bg);
|
||||
}
|
||||
|
||||
.search-result-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-result-title {
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.search-result-subtitle {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-tertiary);
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.search-stats {
|
||||
@@ -95,14 +165,19 @@
|
||||
|
||||
<section>
|
||||
<form class="search-form" method="get" action="/search">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
value="{{ query }}"
|
||||
placeholder="Enter words or phrases to search..."
|
||||
class="search-input"
|
||||
autofocus
|
||||
>
|
||||
<div class="search-input-wrapper">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
id="search-input"
|
||||
value="{{ query }}"
|
||||
placeholder="Enter words or phrases to search..."
|
||||
class="search-input"
|
||||
autocomplete="off"
|
||||
autofocus
|
||||
>
|
||||
<div id="search-dropdown" class="search-dropdown"></div>
|
||||
</div>
|
||||
<button type="submit" class="search-button">Search</button>
|
||||
</form>
|
||||
|
||||
@@ -162,4 +237,191 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var searchInput = document.getElementById('search-input');
|
||||
var dropdown = document.getElementById('search-dropdown');
|
||||
var currentResults = [];
|
||||
var selectedIndex = -1;
|
||||
var searchTimeout = null;
|
||||
|
||||
var bookMap = {
|
||||
'gen': 'Genesis', 'ex': 'Exodus', 'lev': 'Leviticus', 'num': 'Numbers', 'deut': 'Deuteronomy',
|
||||
'josh': 'Joshua', 'judg': 'Judges', 'ruth': 'Ruth', 'ps': 'Psalms', 'prov': 'Proverbs',
|
||||
'isa': 'Isaiah', 'jer': 'Jeremiah', 'dan': 'Daniel', 'matt': 'Matthew', 'mk': 'Mark',
|
||||
'lk': 'Luke', 'jn': 'John', 'acts': 'Acts', 'rom': 'Romans', 'rev': 'Revelation',
|
||||
'genesis': 'Genesis', 'exodus': 'Exodus', 'matthew': 'Matthew', 'mark': 'Mark',
|
||||
'luke': 'Luke', 'john': 'John', 'romans': 'Romans', 'revelation': 'Revelation'
|
||||
};
|
||||
|
||||
function capitalizeBook(name) {
|
||||
return bookMap[name.toLowerCase()] || name;
|
||||
}
|
||||
|
||||
function parseVerseReference(input) {
|
||||
var match = input.match(/^(.+)\s+(\d+):(\d+)$/i);
|
||||
if (match) {
|
||||
var book = capitalizeBook(match[1].trim());
|
||||
return { url: '/book/' + encodeURIComponent(book) + '/chapter/' + match[2] + '/verse/' + match[3], display: book + ' ' + match[2] + ':' + match[3] };
|
||||
}
|
||||
match = input.match(/^(.+)\s+(\d+)$/i);
|
||||
if (match) {
|
||||
var book = capitalizeBook(match[1].trim());
|
||||
return { url: '/book/' + encodeURIComponent(book) + '/chapter/' + match[2], display: book + ' ' + match[2] };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function showDropdown(html) {
|
||||
dropdown.innerHTML = html;
|
||||
dropdown.classList.add('show');
|
||||
}
|
||||
|
||||
function hideDropdown() {
|
||||
dropdown.classList.remove('show');
|
||||
currentResults = [];
|
||||
selectedIndex = -1;
|
||||
}
|
||||
|
||||
function updateSelection() {
|
||||
var items = dropdown.querySelectorAll('.search-result-item');
|
||||
items.forEach(function(item, i) {
|
||||
if (i === selectedIndex) {
|
||||
item.classList.add('selected');
|
||||
} else {
|
||||
item.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderDropdown(query, apiResults) {
|
||||
var html = '';
|
||||
currentResults = [];
|
||||
|
||||
// Check for verse reference
|
||||
var verseRef = parseVerseReference(query);
|
||||
if (verseRef) {
|
||||
html += '<div class="search-result-category">Go to Verse</div>';
|
||||
currentResults.push(verseRef.url);
|
||||
html += '<a href="' + verseRef.url + '" class="search-result-item selected">';
|
||||
html += '<div class="search-result-title">' + verseRef.display + '</div>';
|
||||
html += '</a>';
|
||||
}
|
||||
|
||||
// API results
|
||||
if (apiResults && apiResults.results) {
|
||||
var results = apiResults.results;
|
||||
|
||||
// Books
|
||||
if (results.books && results.books.length > 0) {
|
||||
html += '<div class="search-result-category">Books</div>';
|
||||
results.books.forEach(function(book) {
|
||||
currentResults.push(book.url);
|
||||
html += '<a href="' + book.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + book.name + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
|
||||
// Verses
|
||||
if (results.verses && results.verses.length > 0) {
|
||||
html += '<div class="search-result-category">Verses</div>';
|
||||
results.verses.forEach(function(verse) {
|
||||
currentResults.push(verse.url);
|
||||
html += '<a href="' + verse.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + verse.reference + '</div>';
|
||||
html += '<div class="search-result-subtitle">' + verse.text + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
|
||||
// Topics
|
||||
if (results.topics && results.topics.length > 0) {
|
||||
html += '<div class="search-result-category">Topics</div>';
|
||||
results.topics.forEach(function(topic) {
|
||||
currentResults.push(topic.url);
|
||||
html += '<a href="' + topic.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + topic.name + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
|
||||
// Stories
|
||||
if (results.stories && results.stories.length > 0) {
|
||||
html += '<div class="search-result-category">Stories</div>';
|
||||
results.stories.forEach(function(story) {
|
||||
currentResults.push(story.url);
|
||||
html += '<a href="' + story.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + story.title + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (html) {
|
||||
selectedIndex = currentResults.length > 0 ? 0 : -1;
|
||||
showDropdown(html);
|
||||
} else {
|
||||
hideDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', function() {
|
||||
var query = this.value.trim();
|
||||
clearTimeout(searchTimeout);
|
||||
|
||||
if (query.length < 2) {
|
||||
hideDropdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show verse reference immediately if detected
|
||||
var verseRef = parseVerseReference(query);
|
||||
if (verseRef) {
|
||||
renderDropdown(query, null);
|
||||
}
|
||||
|
||||
// Fetch API results with debounce
|
||||
searchTimeout = setTimeout(function() {
|
||||
fetch('/api/universal-search?q=' + encodeURIComponent(query) + '&limit=5')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
renderDropdown(query, data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error('Search error:', err);
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
|
||||
searchInput.addEventListener('keydown', function(e) {
|
||||
if (!dropdown.classList.contains('show')) return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.min(selectedIndex + 1, currentResults.length - 1);
|
||||
updateSelection();
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||
updateSelection();
|
||||
} else if (e.key === 'Enter' && selectedIndex >= 0 && currentResults[selectedIndex]) {
|
||||
e.preventDefault();
|
||||
window.location.href = currentResults[selectedIndex];
|
||||
} else if (e.key === 'Escape') {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
// Click outside to close dropdown
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!dropdown.contains(e.target) && e.target !== searchInput) {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -280,35 +280,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
var noResults = document.getElementById('no-results');
|
||||
var currentResults = [];
|
||||
var selectedIndex = -1;
|
||||
var searchTimeout = null;
|
||||
|
||||
// Book name mapping for verse references
|
||||
var bookMap = {
|
||||
'gen': 'Genesis', 'ex': 'Exodus', 'lev': 'Leviticus', 'num': 'Numbers', 'deut': 'Deuteronomy',
|
||||
'josh': 'Joshua', 'judg': 'Judges', 'ruth': 'Ruth', 'ps': 'Psalms', 'prov': 'Proverbs',
|
||||
'isa': 'Isaiah', 'jer': 'Jeremiah', 'dan': 'Daniel', 'matt': 'Matthew', 'mk': 'Mark',
|
||||
'lk': 'Luke', 'jn': 'John', 'acts': 'Acts', 'rom': 'Romans', 'rev': 'Revelation',
|
||||
'genesis': 'Genesis', 'exodus': 'Exodus', 'matthew': 'Matthew', 'mark': 'Mark',
|
||||
'luke': 'Luke', 'john': 'John', 'romans': 'Romans', 'revelation': 'Revelation'
|
||||
};
|
||||
|
||||
function capitalizeBook(name) {
|
||||
return bookMap[name.toLowerCase()] || name;
|
||||
}
|
||||
|
||||
function parseVerseReference(input) {
|
||||
var match = input.match(/^(.+)\s+(\d+):(\d+)$/i);
|
||||
if (match) {
|
||||
var book = capitalizeBook(match[1].trim());
|
||||
return { url: '/book/' + encodeURIComponent(book) + '/chapter/' + match[2] + '/verse/' + match[3], display: book + ' ' + match[2] + ':' + match[3] };
|
||||
}
|
||||
match = input.match(/^(.+)\s+(\d+)$/i);
|
||||
if (match) {
|
||||
var book = capitalizeBook(match[1].trim());
|
||||
return { url: '/book/' + encodeURIComponent(book) + '/chapter/' + match[2], display: book + ' ' + match[2] };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function filterStories(query) {
|
||||
if (!query) {
|
||||
@@ -399,27 +370,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
|
||||
function renderDropdown(query, apiResults) {
|
||||
function renderDropdown(query) {
|
||||
var html = '';
|
||||
currentResults = [];
|
||||
|
||||
// Check for verse reference
|
||||
var verseRef = parseVerseReference(query);
|
||||
if (verseRef) {
|
||||
html += '<div class="search-result-category">Go to Verse</div>';
|
||||
currentResults.push(verseRef.url);
|
||||
html += '<a href="' + verseRef.url + '" class="search-result-item' + (currentResults.length === 1 ? ' selected' : '') + '">';
|
||||
html += '<div class="search-result-title">' + verseRef.display + '</div>';
|
||||
html += '</a>';
|
||||
}
|
||||
|
||||
// Matching stories on this page
|
||||
var matchingStories = getMatchingStories(query.toLowerCase());
|
||||
if (matchingStories.length > 0) {
|
||||
html += '<div class="search-result-category">Stories on this page</div>';
|
||||
html += '<div class="search-result-category">Stories</div>';
|
||||
matchingStories.forEach(function(story) {
|
||||
currentResults.push(story.url);
|
||||
var isSelected = currentResults.length === 1 && !verseRef;
|
||||
var isSelected = currentResults.length === 1;
|
||||
html += '<a href="' + story.url + '" class="search-result-item' + (isSelected ? ' selected' : '') + '">';
|
||||
html += '<div class="search-result-title">' + story.title + '</div>';
|
||||
if (story.description) {
|
||||
@@ -429,34 +390,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
|
||||
// API results for other content
|
||||
if (apiResults && apiResults.results) {
|
||||
var results = apiResults.results;
|
||||
|
||||
// Topics
|
||||
if (results.topics && results.topics.length > 0) {
|
||||
html += '<div class="search-result-category">Topics</div>';
|
||||
results.topics.slice(0, 3).forEach(function(topic) {
|
||||
currentResults.push(topic.url);
|
||||
html += '<a href="' + topic.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + topic.name + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
|
||||
// Verses
|
||||
if (results.verses && results.verses.length > 0) {
|
||||
html += '<div class="search-result-category">Verses</div>';
|
||||
results.verses.slice(0, 3).forEach(function(verse) {
|
||||
currentResults.push(verse.url);
|
||||
html += '<a href="' + verse.url + '" class="search-result-item">';
|
||||
html += '<div class="search-result-title">' + verse.reference + '</div>';
|
||||
html += '<div class="search-result-subtitle">' + verse.text + '</div>';
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (html) {
|
||||
selectedIndex = currentResults.length > 0 ? 0 : -1;
|
||||
showDropdown(html);
|
||||
@@ -467,7 +400,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
var query = this.value.trim();
|
||||
clearTimeout(searchTimeout);
|
||||
|
||||
// Filter stories on page
|
||||
filterStories(query.toLowerCase());
|
||||
@@ -477,20 +409,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show immediate results (verse ref + matching stories)
|
||||
renderDropdown(query, null);
|
||||
|
||||
// Fetch API results with debounce
|
||||
searchTimeout = setTimeout(function() {
|
||||
fetch('/api/universal-search?q=' + encodeURIComponent(query) + '&limit=3')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
renderDropdown(query, data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error('Search error:', err);
|
||||
});
|
||||
}, 200);
|
||||
// Show matching stories in dropdown
|
||||
renderDropdown(query);
|
||||
});
|
||||
|
||||
searchInput.addEventListener('keydown', function(e) {
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
.story-search {
|
||||
max-width: 400px;
|
||||
margin: 1.5rem auto;
|
||||
position: relative;
|
||||
}
|
||||
.story-search input {
|
||||
width: 100%;
|
||||
@@ -90,6 +91,60 @@
|
||||
.story-search input::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
.story-search-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-top: none;
|
||||
border-radius: 0 0 16px 16px;
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.15);
|
||||
}
|
||||
.story-search-dropdown.show {
|
||||
display: block;
|
||||
}
|
||||
.search-result-category {
|
||||
padding: 0.5rem 1rem 0.25rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #9ca3af;
|
||||
background: linear-gradient(135deg, #f0f9ff 0%, #faf5ff 100%);
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
.search-result-item {
|
||||
display: block;
|
||||
padding: 0.6rem 1rem;
|
||||
text-decoration: none;
|
||||
color: #4338ca;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.search-result-item:hover,
|
||||
.search-result-item.selected {
|
||||
background: linear-gradient(135deg, #f0f9ff 0%, #faf5ff 100%);
|
||||
}
|
||||
.search-result-item:last-child {
|
||||
border-bottom: none;
|
||||
border-radius: 0 0 14px 14px;
|
||||
}
|
||||
.search-result-title {
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.search-result-subtitle {
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.stories-grid {
|
||||
display: grid;
|
||||
@@ -230,6 +285,7 @@
|
||||
|
||||
<div class="story-search">
|
||||
<input type="text" id="story-search" placeholder="Search for a story..." autocomplete="off">
|
||||
<div id="story-search-dropdown" class="story-search-dropdown"></div>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
@@ -288,33 +344,33 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('story-search');
|
||||
const stories = document.querySelectorAll('.kids-story-card');
|
||||
const categories = document.querySelectorAll('.category-section');
|
||||
const noResults = document.getElementById('no-results');
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
const query = this.value.toLowerCase().trim();
|
||||
var searchInput = document.getElementById('story-search');
|
||||
var dropdown = document.getElementById('story-search-dropdown');
|
||||
var stories = document.querySelectorAll('.kids-story-card');
|
||||
var categorySections = document.querySelectorAll('.category-section');
|
||||
var noResults = document.getElementById('no-results');
|
||||
var currentResults = [];
|
||||
var selectedIndex = -1;
|
||||
|
||||
function filterStories(query) {
|
||||
if (!query) {
|
||||
stories.forEach(s => s.classList.remove('hidden'));
|
||||
categories.forEach(c => c.classList.remove('hidden'));
|
||||
stories.forEach(function(s) { s.classList.remove('hidden'); });
|
||||
categorySections.forEach(function(c) { c.classList.remove('hidden'); });
|
||||
noResults.classList.remove('visible');
|
||||
return;
|
||||
}
|
||||
|
||||
let matchCount = 0;
|
||||
var matchCount = 0;
|
||||
stories.forEach(function(story) {
|
||||
var title = story.dataset.title || '';
|
||||
var description = story.dataset.description || '';
|
||||
var characters = story.dataset.characters || '';
|
||||
var themes = story.dataset.themes || '';
|
||||
|
||||
stories.forEach(story => {
|
||||
const title = story.dataset.title || '';
|
||||
const description = story.dataset.description || '';
|
||||
const characters = story.dataset.characters || '';
|
||||
const themes = story.dataset.themes || '';
|
||||
|
||||
const matches = title.includes(query) ||
|
||||
description.includes(query) ||
|
||||
characters.includes(query) ||
|
||||
themes.includes(query);
|
||||
var matches = title.includes(query) ||
|
||||
description.includes(query) ||
|
||||
characters.includes(query) ||
|
||||
themes.includes(query);
|
||||
|
||||
if (matches) {
|
||||
story.classList.remove('hidden');
|
||||
@@ -324,8 +380,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
|
||||
categories.forEach(category => {
|
||||
const visibleStories = category.querySelectorAll('.kids-story-card:not(.hidden)');
|
||||
categorySections.forEach(function(category) {
|
||||
var visibleStories = category.querySelectorAll('.kids-story-card:not(.hidden)');
|
||||
if (visibleStories.length === 0) {
|
||||
category.classList.add('hidden');
|
||||
} else {
|
||||
@@ -338,6 +394,116 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
} else {
|
||||
noResults.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
|
||||
function getMatchingStories(query) {
|
||||
var matches = [];
|
||||
stories.forEach(function(story) {
|
||||
var title = story.dataset.title || '';
|
||||
var description = story.dataset.description || '';
|
||||
var characters = story.dataset.characters || '';
|
||||
var themes = story.dataset.themes || '';
|
||||
|
||||
if (title.includes(query) || description.includes(query) ||
|
||||
characters.includes(query) || themes.includes(query)) {
|
||||
var link = story.querySelector('h3 a');
|
||||
if (link) {
|
||||
matches.push({
|
||||
title: link.textContent,
|
||||
url: link.getAttribute('href'),
|
||||
description: story.querySelector('.description')?.textContent?.substring(0, 50) + '...'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return matches.slice(0, 5);
|
||||
}
|
||||
|
||||
function showDropdown(html) {
|
||||
dropdown.innerHTML = html;
|
||||
dropdown.classList.add('show');
|
||||
}
|
||||
|
||||
function hideDropdown() {
|
||||
dropdown.classList.remove('show');
|
||||
currentResults = [];
|
||||
selectedIndex = -1;
|
||||
}
|
||||
|
||||
function updateSelection() {
|
||||
var items = dropdown.querySelectorAll('.search-result-item');
|
||||
items.forEach(function(item, i) {
|
||||
if (i === selectedIndex) {
|
||||
item.classList.add('selected');
|
||||
} else {
|
||||
item.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderDropdown(query) {
|
||||
var html = '';
|
||||
currentResults = [];
|
||||
|
||||
var matchingStories = getMatchingStories(query.toLowerCase());
|
||||
if (matchingStories.length > 0) {
|
||||
html += '<div class="search-result-category">Stories</div>';
|
||||
matchingStories.forEach(function(story) {
|
||||
currentResults.push(story.url);
|
||||
var isSelected = currentResults.length === 1;
|
||||
html += '<a href="' + story.url + '" class="search-result-item' + (isSelected ? ' selected' : '') + '">';
|
||||
html += '<div class="search-result-title">' + story.title + '</div>';
|
||||
if (story.description) {
|
||||
html += '<div class="search-result-subtitle">' + story.description + '</div>';
|
||||
}
|
||||
html += '</a>';
|
||||
});
|
||||
}
|
||||
|
||||
if (html) {
|
||||
selectedIndex = currentResults.length > 0 ? 0 : -1;
|
||||
showDropdown(html);
|
||||
} else {
|
||||
hideDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
var query = this.value.trim();
|
||||
|
||||
filterStories(query.toLowerCase());
|
||||
|
||||
if (query.length < 2) {
|
||||
hideDropdown();
|
||||
return;
|
||||
}
|
||||
|
||||
renderDropdown(query);
|
||||
});
|
||||
|
||||
searchInput.addEventListener('keydown', function(e) {
|
||||
if (!dropdown.classList.contains('show')) return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.min(selectedIndex + 1, currentResults.length - 1);
|
||||
updateSelection();
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||
updateSelection();
|
||||
} else if (e.key === 'Enter' && selectedIndex >= 0 && currentResults[selectedIndex]) {
|
||||
e.preventDefault();
|
||||
window.location.href = currentResults[selectedIndex];
|
||||
} else if (e.key === 'Escape') {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!dropdown.contains(e.target) && e.target !== searchInput) {
|
||||
hideDropdown();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user