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,77 @@
|
||||
// Persisted order of search result groups.
|
||||
//
|
||||
// Frontend-only preference, stored in localStorage per the `jellytau-view-mode`
|
||||
// precedent in library.ts — no Rust settings command backs this.
|
||||
//
|
||||
// TRACES: UR-050 | DR-066
|
||||
|
||||
import { writable } from "svelte/store";
|
||||
import {
|
||||
DEFAULT_GROUP_ORDER,
|
||||
moveGroup,
|
||||
normalizeGroupOrder,
|
||||
reorderGroups,
|
||||
type SearchGroupId,
|
||||
} from "$lib/utils/searchScope";
|
||||
|
||||
const STORAGE_KEY = "jellytau-search-group-order";
|
||||
|
||||
function load(): SearchGroupId[] {
|
||||
if (typeof localStorage === "undefined") return [...DEFAULT_GROUP_ORDER];
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
// A corrupt or hand-edited value must not break search rendering.
|
||||
return normalizeGroupOrder(raw ? JSON.parse(raw) : null);
|
||||
} catch {
|
||||
return [...DEFAULT_GROUP_ORDER];
|
||||
}
|
||||
}
|
||||
|
||||
function persist(order: SearchGroupId[]) {
|
||||
if (typeof localStorage === "undefined") return;
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(order));
|
||||
} catch {
|
||||
// Quota or private-mode failure — keep the in-memory order.
|
||||
}
|
||||
}
|
||||
|
||||
function createSearchGroupOrderStore() {
|
||||
const { subscribe, set, update } = writable<SearchGroupId[]>(load());
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
set(order: SearchGroupId[]) {
|
||||
const normalized = normalizeGroupOrder(order);
|
||||
persist(normalized);
|
||||
set(normalized);
|
||||
},
|
||||
|
||||
/** Move one group up (-1) or down (+1) — the keyboard-accessible path. */
|
||||
move(id: SearchGroupId, delta: number) {
|
||||
update((order) => {
|
||||
const next = moveGroup(order, id, delta);
|
||||
persist(next);
|
||||
return next;
|
||||
});
|
||||
},
|
||||
|
||||
/** Drop handler for drag-and-drop reordering. */
|
||||
reorder(from: number, to: number) {
|
||||
update((order) => {
|
||||
const next = reorderGroups(order, from, to);
|
||||
persist(next);
|
||||
return next;
|
||||
});
|
||||
},
|
||||
|
||||
reset() {
|
||||
const next = [...DEFAULT_GROUP_ORDER];
|
||||
persist(next);
|
||||
set(next);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const searchGroupOrder = createSearchGroupOrderStore();
|
||||
Reference in New Issue
Block a user