Files
groove-web/src/routes/tracks/+page.svelte

62 lines
1.6 KiB
Svelte

<script lang="ts">
import TrackListing from '$lib/components/groove/TrackListing.svelte';
import type { PageServerData } from './$types';
import { getSearchState } from '$lib/search.svelte';
import type { Action } from 'svelte/action';
import { SvelteSet as Set } from 'svelte/reactivity';
interface Props {
data: PageServerData;
}
const search = getSearchState();
let { data }: Props = $props();
let container: HTMLDivElement;
let visibleTracks = $state<Set<string>>(new Set());
const options: IntersectionObserverInit = {
// @ts-ignore
root: container,
rootMargin: "400px 0px 400px 0px",
threshold: 0.0,
};
const callback: IntersectionObserverCallback = (entries, _observer) => {
entries.forEach(entry => {
const hash = entry.target.getAttribute('data-track-hash')!;
if (entry.isIntersecting) {
if (!visibleTracks.has(hash)) {
visibleTracks.add(hash);
}
}
else if (visibleTracks.has(hash)) {
visibleTracks.delete(hash);
}
});
};
const observer = new IntersectionObserver(callback, options);
const observe: Action = (node) => {
observer.observe(node);
}
$effect(() => {
const firstFewTracks = search.filterTracks(data.tracks).slice(0,40);
firstFewTracks.forEach(e => {
visibleTracks.add(e.item.hash);
});
});
</script>
<div
class="grid grid-cols-2 gap-4 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-7 2xl:grid-cols-8"
bind:this={container}
>
{#each search.input.length > 0 ? (search.filterTracks(data.tracks).map(r => r.item) ?? []) : data.tracks as track (track.hash)}
<TrackListing {track} action={observe} hideCover={!visibleTracks.has(track.hash)}/>
{/each}
</div>