Files
tv/web/js/search.js
T
2026-08-26 13:22:49 -05:00

89 lines
2.7 KiB
JavaScript

/*
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();
})();