feat: Add search to library

This commit is contained in:
Aleksi Lassila
2023-09-01 17:24:58 +03:00
parent 69482e1ded
commit 247f52db21
2 changed files with 50 additions and 11 deletions

View File

@@ -65,7 +65,7 @@
on:click
class={classNames(
'aspect-video bg-center bg-cover rounded-lg overflow-hidden transition-opacity shadow-lg selectable flex-shrink-0 placeholder-image relative',
'flex flex-col px-2 lg:px-3 py-2 gap-2',
'flex flex-col px-2 lg:px-3 py-2 gap-2 text-left',
{
'h-40': size === 'md',
'h-full': size === 'dynamic',

View File

@@ -3,11 +3,11 @@
import IconButton from '$lib/components/IconButton.svelte';
import { settings } from '$lib/stores/settings.store';
import classNames from 'classnames';
import { fade } from 'svelte/transition';
import { fade, fly } from 'svelte/transition';
import { _ } from 'svelte-i18n';
import { CaretDown, ChevronDown, Gear } from 'radix-icons-svelte';
import { CaretDown, ChevronDown, Cross2, Gear, MagnifyingGlass } from 'radix-icons-svelte';
import CardPlaceholder from '$lib/components/Card/CardPlaceholder.svelte';
import type { ComponentProps } from 'svelte';
import { tick, type ComponentProps } from 'svelte';
import Poster from '$lib/components/Poster/Poster.svelte';
import { getJellyfinPosterUrl, type JellyfinItem } from '$lib/apis/jellyfin/jellyfinApi';
import { getRadarrPosterUrl, type RadarrMovie } from '$lib/apis/radarr/radarrApi';
@@ -33,7 +33,8 @@
let openTab: 'available' | 'watched' | 'unavailable' = 'available';
let page = 0;
let loading = true;
let searchVisible = false;
let searchInput: HTMLInputElement | undefined;
@@ -97,7 +98,7 @@
if (page === 0) posterProps = [];
const jellyfinItemsPromise = jellyfinItemsStore.promise
.then((i) => i || [])
.then((i) => i.filter((i) => i.Name?.toLowerCase().includes(searchQuery.toLowerCase())) || [])
.then((i) => {
const sorted = i.sort((a, b) => {
if (sort === 'Date Added') {
@@ -146,6 +147,7 @@
}))
.then(({ items, jellyfinItems }) =>
items
.filter((i) => i.title?.toLowerCase().includes(searchQuery.toLowerCase()))
.filter(
(i) =>
!jellyfinItems.find((j) => j.ProviderIds?.Tmdb === String((<any>i).tmdbId || '-'))
@@ -159,6 +161,7 @@
}
const toAdd = props.slice(PAGE_SIZE * page, PAGE_SIZE * (page + 1));
hasMore = toAdd.length === PAGE_SIZE;
libraryLoading = false;
posterProps = [...posterProps, ...toAdd];
@@ -169,18 +172,54 @@
page = 0;
}
function handleShortcuts(event: KeyboardEvent) {
async function handleOpenSearch() {
searchVisible = true;
await tick();
searchInput?.focus();
}
async function handleCloseSearch() {
searchVisible = false;
searchQuery = '';
}
async function handleShortcuts(event: KeyboardEvent) {
if (event.key === 'f' && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
searchInput?.focus();
handleOpenSearch();
} else if (event.key === 'Escape') {
handleCloseSearch();
}
}
</script>
<svelte:window on:keydown={handleShortcuts} />
{#if searchVisible}
<div
transition:fly={{ y: 5, duration: 200 }}
class="fixed top-20 left-1/2 w-80 -ml-40 z-10 bg-[#33333388] backdrop-blur-xl rounded-full
flex items-center text-zinc-300"
>
<div class="absolute inset-y-0 left-4 flex items-center justify-center">
<MagnifyingGlass size={20} />
</div>
<div class="absolute inset-y-0 right-4 flex items-center justify-center">
<IconButton on:click={handleCloseSearch}>
<Cross2 size={20} />
</IconButton>
</div>
<input
bind:this={searchInput}
bind:value={searchQuery}
placeholder="Seach in library"
class="appearance-none mx-2.5 my-2.5 px-10 bg-transparent outline-none placeholder:text-zinc-400 font-medium w-full"
/>
</div>
{/if}
<div class="flex flex-col gap-4">
<div class="flex items-center justify-between gap-2">
<div class="flex items-center justify-between gap-4">
<UiCarousel>
<div class="flex gap-6 text-lg font-medium text-zinc-400">
<button
@@ -243,8 +282,8 @@
</div>
</IconButton>
</ContextMenu>
<IconButton>
<Gear size={20} />
<IconButton on:click={handleOpenSearch}>
<MagnifyingGlass size={20} />
</IconButton>
</div>
</div>