From c89073e025c57c0ab11dc6bf8571f7c0776ac2c9 Mon Sep 17 00:00:00 2001 From: 409 Date: Thu, 28 Nov 2024 05:41:47 +0100 Subject: [PATCH] feat(tracks): search + lazy load images --- bun.lockb | Bin 90271 -> 90605 bytes package.json | 1 + src/lib/components/groove/Queue.svelte | 3 +- src/lib/components/groove/TrackListing.svelte | 20 ++++++-- src/lib/search.svelte.ts | 25 ++++++++++ src/routes/+layout.svelte | 17 ++++++- src/routes/tracks/+page.svelte | 47 +++++++++++++++++- 7 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 src/lib/search.svelte.ts diff --git a/bun.lockb b/bun.lockb index b1b5288f48b9ecf4f7d50e7769f71f1075868269..abf32e4a86e52ae9e3ec661b54344405f84684e5 100755 GIT binary patch delta 14048 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 K+k?cle*Xec8id{e delta 14011 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 - {#each player.queue as track, i (track.hash)} + {#each player.queue as track, i} diff --git a/src/lib/search.svelte.ts b/src/lib/search.svelte.ts new file mode 100644 index 0000000..72a62b4 --- /dev/null +++ b/src/lib/search.svelte.ts @@ -0,0 +1,25 @@ +import { Fzf } from 'fzf'; +import type { Track } from './proto/library'; +import { getContext, setContext } from 'svelte'; + +class SearchState { + input = $state(''); + + filterTracks(tracks: Track[]) { + const fzf = new Fzf(tracks, { + selector: (t) => `${t.name} ${t.artistName}`, + sort: true, + }); + return fzf.find(this.input); + } +} + +const SEARCH_KEY = Symbol('SEARCH'); + +export function setSearchState() { + return setContext(SEARCH_KEY, new SearchState()); +} + +export function getSearchState() { + return getContext>(SEARCH_KEY); +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 3d076a4..1b88cfa 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -7,11 +7,17 @@ import { ScrollArea } from '$lib/components/ui/scroll-area'; import { getPlayerState, setPlayerState } from '$lib/player.svelte'; import { onMount } from 'svelte'; + import { Separator } from '$lib/components/ui/separator'; + import { Input } from '$lib/components/ui/input'; + import { Search } from 'lucide-svelte'; + import { setSearchState, getSearchState } from '$lib/search.svelte'; let { children } = $props(); setPlayerState(); + setSearchState(); const player = getPlayerState(); + const search = getSearchState(); onMount(() => { return () => player.abort(); @@ -24,8 +30,17 @@
-
+
+ +
+ + +
+
+
diff --git a/src/routes/tracks/+page.svelte b/src/routes/tracks/+page.svelte index c7cb406..7b01150 100644 --- a/src/routes/tracks/+page.svelte +++ b/src/routes/tracks/+page.svelte @@ -1,18 +1,61 @@
- {#each data.tracks as track} - + {#each search.input.length > 0 ? (search.filterTracks(data.tracks).map(r => r.item) ?? []) : data.tracks as track (track.hash)} + {/each}