From 8c32cd117abe79f4ee6cff3a950ffc35c95faeff Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 9 May 2026 11:11:49 +0300 Subject: Refine media browsing and set covers --- web/js/search.js | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'web/js/search.js') diff --git a/web/js/search.js b/web/js/search.js index 4e78b55..31c3004 100644 --- a/web/js/search.js +++ b/web/js/search.js @@ -6,10 +6,12 @@ export function initSearch({ onChange, input, clearBtn }) { _onChange = onChange; if (!input) return; input.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - input.value = ''; + if (e.key === 'Escape' || e.key === 'Enter') { + e.preventDefault(); + e.stopPropagation(); input.blur(); - trigger(''); + hideSearch(); + document.dispatchEvent(new CustomEvent('search:navigate-results')); } }); input.addEventListener('input', () => { @@ -29,6 +31,7 @@ export function initSearch({ onChange, input, clearBtn }) { } export function focusSearch() { + showSearch(); const input = document.getElementById('search-input'); if (input) { input.focus(); @@ -41,6 +44,15 @@ export function trigger(query) { _onChange(query); } +export function showSearch() { + document.getElementById('search-overlay')?.classList.remove('hidden'); +} + +export function hideSearch() { + document.getElementById('search-overlay')?.classList.add('hidden'); + hideSearchHelp(); +} + /** * Parse a raw search string into structured filters and free-text search. * @@ -50,6 +62,7 @@ export function trigger(query) { * tag:a,b – comma-separated tag names * like:1 – only favorited items * type:video – media type (video | audio) + * set:yoga – select a set by id or name * sort:name – sort order (name | date | duration | play_count | random) * minsize:10 – minimum file size in MB * maxsize:500 – maximum file size in MB @@ -62,6 +75,7 @@ export function parseQuery(raw) { favorites: false, tags: '', sort: '', + set: '', minDuration: '', maxDuration: '', minFileSize: '', @@ -69,8 +83,7 @@ export function parseQuery(raw) { search: '', }; const tokens = []; - // Split by whitespace while respecting double-quoted strings. - const parts = raw.match(/(".*?"|\S+)/g) || []; + const parts = tokenize(raw); for (const part of parts) { const m = part.match(/^([a-zA-Z_]+):(.+)$/); if (m) { @@ -95,6 +108,9 @@ export function parseQuery(raw) { case 'type': filters.type = value; break; + case 'set': + filters.set = value; + break; case 'sort': filters.sort = value; break; @@ -116,6 +132,28 @@ export function parseQuery(raw) { return filters; } +function tokenize(raw) { + const parts = []; + let current = ''; + let inQuote = false; + for (const ch of raw || '') { + if (ch === '"') { + inQuote = !inQuote; + continue; + } + if (/\s/.test(ch) && !inQuote) { + if (current) { + parts.push(current); + current = ''; + } + continue; + } + current += ch; + } + if (current) parts.push(current); + return parts; +} + export function showSearchHelp() { const el = document.getElementById('search-help'); if (!el) return; -- cgit v1.2.3