First working POC
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
<script lang="ts">
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import MediaCard from "$lib/components/library/MediaCard.svelte";
|
||||
import TrackList from "$lib/components/library/TrackList.svelte";
|
||||
|
||||
interface Props {
|
||||
results: MediaItem[];
|
||||
loading?: boolean;
|
||||
onItemClick?: (item: MediaItem) => void;
|
||||
}
|
||||
|
||||
let { results, loading = false, onItemClick }: Props = $props();
|
||||
|
||||
// Categorize results by type
|
||||
const categorized = $derived({
|
||||
music: {
|
||||
tracks: results.filter((i) => i.type === "Audio"),
|
||||
albums: results.filter((i) => i.type === "MusicAlbum"),
|
||||
artists: results.filter((i) => i.type === "MusicArtist"),
|
||||
},
|
||||
movies: results.filter((i) => i.type === "Movie"),
|
||||
tvShows: results.filter((i) => i.type === "Series" || i.type === "Episode"),
|
||||
});
|
||||
|
||||
const hasMusic = $derived(
|
||||
categorized.music.tracks.length > 0 ||
|
||||
categorized.music.albums.length > 0 ||
|
||||
categorized.music.artists.length > 0
|
||||
);
|
||||
|
||||
const hasAnyResults = $derived(
|
||||
hasMusic || categorized.movies.length > 0 || categorized.tvShows.length > 0
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
<div class="flex justify-center py-12">
|
||||
<div
|
||||
class="w-8 h-8 border-2 border-[var(--color-jellyfin)] border-t-transparent rounded-full animate-spin"
|
||||
></div>
|
||||
</div>
|
||||
{:else if !hasAnyResults}
|
||||
<div class="text-center py-12 text-gray-400">
|
||||
<svg class="w-16 h-16 mx-auto mb-4 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
||||
</svg>
|
||||
<p>No results found</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-8">
|
||||
<!-- Music Section -->
|
||||
{#if hasMusic}
|
||||
<div class="space-y-6">
|
||||
<h2 class="text-2xl font-semibold text-white px-4">Music</h2>
|
||||
|
||||
<!-- Tracks Subsection -->
|
||||
{#if categorized.music.tracks.length > 0}
|
||||
<div>
|
||||
<h3 class="text-lg text-gray-300 px-4 mb-3">
|
||||
Tracks ({categorized.music.tracks.length})
|
||||
</h3>
|
||||
<TrackList tracks={categorized.music.tracks} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Albums Subsection -->
|
||||
{#if categorized.music.albums.length > 0}
|
||||
<div>
|
||||
<h3 class="text-lg text-gray-300 px-4 mb-3">
|
||||
Albums ({categorized.music.albums.length})
|
||||
</h3>
|
||||
<div class="flex gap-4 overflow-x-auto scrollbar-hide px-4">
|
||||
{#each categorized.music.albums as item (item.id)}
|
||||
<MediaCard
|
||||
{item}
|
||||
size="medium"
|
||||
showProgress={true}
|
||||
onclick={() => onItemClick?.(item)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Artists Subsection -->
|
||||
{#if categorized.music.artists.length > 0}
|
||||
<div>
|
||||
<h3 class="text-lg text-gray-300 px-4 mb-3">
|
||||
Artists ({categorized.music.artists.length})
|
||||
</h3>
|
||||
<div class="flex gap-4 overflow-x-auto scrollbar-hide px-4">
|
||||
{#each categorized.music.artists as item (item.id)}
|
||||
<MediaCard
|
||||
{item}
|
||||
size="medium"
|
||||
showProgress={false}
|
||||
onclick={() => onItemClick?.(item)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Movies Section -->
|
||||
{#if categorized.movies.length > 0}
|
||||
<div>
|
||||
<h2 class="text-2xl font-semibold text-white px-4 mb-3">
|
||||
Movies ({categorized.movies.length})
|
||||
</h2>
|
||||
<div class="flex gap-4 overflow-x-auto scrollbar-hide px-4">
|
||||
{#each categorized.movies as item (item.id)}
|
||||
<MediaCard
|
||||
{item}
|
||||
size="medium"
|
||||
showProgress={true}
|
||||
onclick={() => onItemClick?.(item)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- TV Shows Section -->
|
||||
{#if categorized.tvShows.length > 0}
|
||||
<div>
|
||||
<h2 class="text-2xl font-semibold text-white px-4 mb-3">
|
||||
TV Shows ({categorized.tvShows.length})
|
||||
</h2>
|
||||
<div class="flex gap-4 overflow-x-auto scrollbar-hide px-4">
|
||||
{#each categorized.tvShows as item (item.id)}
|
||||
<MediaCard
|
||||
{item}
|
||||
size="medium"
|
||||
showProgress={true}
|
||||
onclick={() => onItemClick?.(item)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-hide {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user