push
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
SEARCH — debounced live search with client-side type filter.
|
||||
URL ?q= is kept in sync so results are shareable/bookmarkable.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
SR.app.initChrome();
|
||||
|
||||
const input = document.getElementById('searchInput');
|
||||
const chipsEl = document.getElementById('typeChips');
|
||||
const resultsEl = document.getElementById('results');
|
||||
const countEl = document.getElementById('searchCount');
|
||||
|
||||
const state = { type: 'all', results: [] };
|
||||
|
||||
function render() {
|
||||
resultsEl.replaceChildren();
|
||||
const filtered = state.type === 'all' ? state.results : state.results.filter((i) => i.type === state.type);
|
||||
if (!state.results.length) {
|
||||
countEl.textContent = '';
|
||||
resultsEl.appendChild(
|
||||
SR.cards.emptyState('Nothing found', 'Check the spelling or try a different name.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
countEl.textContent = `${filtered.length} of ${state.results.length} result${state.results.length === 1 ? '' : 's'}`;
|
||||
if (!filtered.length) {
|
||||
resultsEl.appendChild(SR.cards.emptyState('No matches for this filter', 'Try the All filter, or a different search.'));
|
||||
return;
|
||||
}
|
||||
resultsEl.appendChild(SR.cards.grid(filtered));
|
||||
}
|
||||
|
||||
async function runSearch(q) {
|
||||
q = (q || '').trim();
|
||||
if (!q) {
|
||||
state.results = [];
|
||||
countEl.textContent = '';
|
||||
resultsEl.replaceChildren(SR.cards.emptyState('Search the catalog', 'Type a movie or show name above.'));
|
||||
return;
|
||||
}
|
||||
countEl.textContent = 'Searching…';
|
||||
try {
|
||||
const data = await SR.api.search(q);
|
||||
state.results = data.results.map(SR.cards.normalizeItem);
|
||||
render();
|
||||
} catch (e) {
|
||||
SR.app.showError(e, 'search failed');
|
||||
countEl.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
const LABELS = { all: 'All', movie: 'Movies', tv: 'TV' };
|
||||
for (const t of ['all', 'movie', 'tv']) {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button';
|
||||
b.className = t === 'all' ? 'chip chip--active' : 'chip';
|
||||
b.textContent = LABELS[t];
|
||||
b.addEventListener('click', () => {
|
||||
state.type = t;
|
||||
for (const c of chipsEl.querySelectorAll('.chip')) c.classList.remove('chip--active');
|
||||
b.classList.add('chip--active');
|
||||
render();
|
||||
});
|
||||
chipsEl.appendChild(b);
|
||||
}
|
||||
|
||||
input.addEventListener(
|
||||
'input',
|
||||
SR.util.debounce(() => {
|
||||
const q = input.value.trim();
|
||||
history.replaceState(null, '', q ? `?q=${encodeURIComponent(q)}` : 'search.html');
|
||||
runSearch(q);
|
||||
}, 450)
|
||||
);
|
||||
input.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
runSearch(input.value.trim());
|
||||
}
|
||||
});
|
||||
|
||||
const initialQ = SR.util.getParam('q') || '';
|
||||
input.value = initialQ;
|
||||
if (initialQ) runSearch(initialQ);
|
||||
else input.focus();
|
||||
})();
|
||||
Reference in New Issue
Block a user