62 lines
1.6 KiB
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>
|