254 lines
6.4 KiB
Plaintext
254 lines
6.4 KiB
Plaintext
<div class="subheader-search-container">
|
|
<form
|
|
class="lang-en"
|
|
id="client-search-form"
|
|
onsubmit="return false;"
|
|
data-test="desktop-search">
|
|
<i class="subheader-search-icon far fa-search"></i>
|
|
<input
|
|
aria-label="Search"
|
|
class="subheader-search-input"
|
|
type="text"
|
|
id="client-search-input"
|
|
placeholder="Browse by titles or tags..."
|
|
autocomplete="off" />
|
|
</form>
|
|
<!-- No Results Message -->
|
|
<div id="no-results-message" class="no-results-message" style="display: none;">
|
|
<p>No matches found. Try different keywords or <a href="/courses">browse all lessons</a>.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
'use strict';
|
|
|
|
const searchInput = document.getElementById('client-search-input');
|
|
const noResultsMessage = document.getElementById('no-results-message');
|
|
|
|
if (!searchInput) return;
|
|
|
|
// Get all searchable cards
|
|
function getSearchableCards() {
|
|
return document.querySelectorAll('.np-card');
|
|
}
|
|
|
|
// Extract searchable text from a card
|
|
function getCardSearchText(card) {
|
|
const texts = [];
|
|
|
|
// Get course/learning path title
|
|
const title = card.querySelector('.np-card-content-title');
|
|
if (title) texts.push(title.textContent.trim());
|
|
|
|
// Get instructor names
|
|
const instructor = card.querySelector('.np-card-content-subtitle');
|
|
if (instructor) texts.push(instructor.textContent.trim());
|
|
|
|
// Get description (learning paths have this)
|
|
const description = card.querySelector('.np-card-content-description');
|
|
if (description) texts.push(description.textContent.trim());
|
|
|
|
// Get ribbon/tag content
|
|
const ribbon = card.querySelector('.np-card-ribbon');
|
|
if (ribbon) texts.push(ribbon.textContent.trim());
|
|
|
|
// Also get any badge/type content that might contain searchable terms
|
|
const badges = card.querySelectorAll('.np-card-header-type, .np-product-badge-name');
|
|
badges.forEach(badge => {
|
|
if (badge) texts.push(badge.textContent.trim());
|
|
});
|
|
|
|
// Normalize the text - remove extra whitespace, normalize characters
|
|
const fullText = texts.join(' ').toLowerCase()
|
|
.replace(/\s+/g, ' ') // Replace multiple spaces with single space
|
|
.replace(/[^\w\s]/g, ' ') // Replace non-word chars (except spaces) with spaces
|
|
.trim();
|
|
|
|
return fullText;
|
|
}
|
|
|
|
// Get the grid container for a card (Bootstrap column)
|
|
function getCardContainer(card) {
|
|
// Look for the Bootstrap grid column container (col-*)
|
|
let container = card.parentElement;
|
|
while (container && container !== document.body) {
|
|
if (container.classList && Array.from(container.classList).some(cls => cls.startsWith('col-'))) {
|
|
return container;
|
|
}
|
|
container = container.parentElement;
|
|
}
|
|
// Fallback to the card itself if no grid container found
|
|
return card;
|
|
}
|
|
|
|
// Perform the search
|
|
function performSearch(query) {
|
|
const cards = getSearchableCards();
|
|
const searchTerms = query.toLowerCase().trim().split(/\s+/).filter(term => term.length > 0);
|
|
|
|
if (searchTerms.length === 0) {
|
|
// Show all cards
|
|
cards.forEach(card => {
|
|
const container = getCardContainer(card);
|
|
container.style.display = '';
|
|
});
|
|
noResultsMessage.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
let visibleCount = 0;
|
|
|
|
cards.forEach(card => {
|
|
const cardText = getCardSearchText(card);
|
|
const matches = searchTerms.every(term => cardText.includes(term));
|
|
const container = getCardContainer(card);
|
|
|
|
if (matches) {
|
|
container.style.display = '';
|
|
visibleCount++;
|
|
} else {
|
|
container.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Show/hide no results message
|
|
noResultsMessage.style.display = visibleCount === 0 ? 'block' : 'none';
|
|
}
|
|
|
|
// Debounced search
|
|
let searchTimeout;
|
|
function debouncedSearch(query) {
|
|
clearTimeout(searchTimeout);
|
|
searchTimeout = setTimeout(() => performSearch(query), 150);
|
|
}
|
|
|
|
// Event listeners
|
|
searchInput.addEventListener('input', function(e) {
|
|
debouncedSearch(e.target.value);
|
|
});
|
|
|
|
// Clear search on escape
|
|
searchInput.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') {
|
|
e.target.value = '';
|
|
performSearch('');
|
|
}
|
|
});
|
|
|
|
})();
|
|
</script>
|
|
|
|
<style>
|
|
.subheader-search-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
padding: 10px 16px 30px 16px;
|
|
position: relative;
|
|
}
|
|
|
|
.subheader-search-container > form {
|
|
width: 60%;
|
|
max-width: 600px;
|
|
min-width: 300px;
|
|
position: relative;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
/* Mobile Search Bar */
|
|
@media (max-width: 768px) {
|
|
.subheader-search-container > form {
|
|
width: 100%;
|
|
min-width: unset;
|
|
}
|
|
}
|
|
|
|
.subheader-search-icon {
|
|
position: absolute;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
top: 12px;
|
|
left: 18px;
|
|
color: #888;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.subheader-search-input {
|
|
width: 100%;
|
|
padding: 12px 12px 12px 50px;
|
|
border-radius: 8px;
|
|
border: 2px solid #e0e0e0;
|
|
font-size: 16px;
|
|
background-color: white;
|
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
}
|
|
|
|
.subheader-search-input:focus {
|
|
outline: none;
|
|
border-color: #4CAF50;
|
|
box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1);
|
|
}
|
|
|
|
.subheader-search-input:focus + .subheader-search-icon,
|
|
.subheader-search-input:not(:placeholder-shown) + .subheader-search-icon {
|
|
color: #4CAF50;
|
|
}
|
|
|
|
/* Search Tips */
|
|
.search-tips {
|
|
width: 60%;
|
|
max-width: 600px;
|
|
min-width: 300px;
|
|
text-align: center;
|
|
}
|
|
|
|
.search-tip {
|
|
color: #666;
|
|
font-size: 13px;
|
|
font-weight: 400;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
/* No Results Message */
|
|
.no-results-message {
|
|
width: 60%;
|
|
max-width: 600px;
|
|
min-width: 300px;
|
|
text-align: center;
|
|
margin-top: 20px;
|
|
padding: 20px;
|
|
background-color: #f8f9fa;
|
|
border-radius: 8px;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.no-results-message p {
|
|
color: #666;
|
|
margin: 0;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.no-results-message a {
|
|
color: #013d29;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.no-results-message a:hover {
|
|
color: #022f20;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.search-tips, .no-results-message {
|
|
width: 100%;
|
|
min-width: unset;
|
|
padding: 0 10px;
|
|
}
|
|
|
|
.search-tip {
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
</style> |