feat(search): context-scoped search with filter chips and group order
Add a search scope (all/music/shows/movies) resolved from the entry route and adjustable via filter chips, threaded through the library store's search() into includeItemTypes. Results group by type in a user-configurable order, editable from settings. TRACES: UR-049 | DR-063, DR-064, DR-065; UR-050 | DR-066, DR-067
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<script lang="ts">
|
||||
// Scope filter chips shown under the search bar.
|
||||
//
|
||||
// The chip row is a *radio group*: exactly one scope is active, so arrow keys
|
||||
// move between chips and the selected one is the sole tab stop.
|
||||
//
|
||||
// TRACES: UR-049 | DR-064
|
||||
import { SCOPE_LABELS, SEARCH_SCOPES, type SearchScope } from "$lib/utils/searchScope";
|
||||
|
||||
interface Props {
|
||||
scope: SearchScope;
|
||||
onChange: (scope: SearchScope) => void;
|
||||
}
|
||||
|
||||
let { scope, onChange }: Props = $props();
|
||||
|
||||
let chipEls: HTMLButtonElement[] = $state([]);
|
||||
|
||||
function select(next: SearchScope) {
|
||||
if (next === scope) return;
|
||||
onChange(next);
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent, index: number) {
|
||||
const delta = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
|
||||
if (delta === 0) return;
|
||||
event.preventDefault();
|
||||
const next = (index + delta + SEARCH_SCOPES.length) % SEARCH_SCOPES.length;
|
||||
chipEls[next]?.focus();
|
||||
select(SEARCH_SCOPES[next]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex gap-2 overflow-x-auto scrollbar-hide"
|
||||
role="radiogroup"
|
||||
aria-label="Search scope"
|
||||
>
|
||||
{#each SEARCH_SCOPES as s, i (s)}
|
||||
<button
|
||||
bind:this={chipEls[i]}
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={scope === s}
|
||||
tabindex={scope === s ? 0 : -1}
|
||||
onclick={() => select(s)}
|
||||
onkeydown={(e) => onKeyDown(e, i)}
|
||||
class="px-4 py-1.5 rounded-full text-sm whitespace-nowrap transition-colors border {scope === s
|
||||
? 'bg-[var(--color-jellyfin)] border-[var(--color-jellyfin)] text-white'
|
||||
: 'bg-[var(--color-surface)] border-gray-700 text-gray-300 hover:text-white hover:border-gray-500'}"
|
||||
>
|
||||
{SCOPE_LABELS[s]}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-hide {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user