Categorize components/ui into primitives, overlay, media, forms and layout
Splits the flat 38-component ui/ folder into primitives/ (generic controls), overlay/ (menus/modals), media/ (music-domain display components), forms/ (composite entity forms) and layout/ (page scaffolding), and updates every import path accordingly.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import LoaderCircle from '@lucide/svelte/icons/loader-circle';
|
||||
import { INFINITE_SCROLL_ROOT_MARGIN } from '$lib/config';
|
||||
|
||||
interface Props {
|
||||
onLoadMore: () => void;
|
||||
hasMore: boolean;
|
||||
loading: boolean;
|
||||
rootMargin?: string;
|
||||
}
|
||||
|
||||
let { onLoadMore, hasMore, loading, rootMargin = INFINITE_SCROLL_ROOT_MARGIN }: Props = $props();
|
||||
|
||||
let sentinel = $state<HTMLDivElement>();
|
||||
let visible = $state(false);
|
||||
|
||||
$effect(() => {
|
||||
const node = sentinel;
|
||||
if (!node) return;
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
visible = entries[0].isIntersecting;
|
||||
},
|
||||
{ rootMargin }
|
||||
);
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (visible && hasMore && !loading) onLoadMore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={sentinel} class="flex min-h-12 items-center justify-center py-8">
|
||||
{#if loading}
|
||||
<LoaderCircle class="size-5 animate-spin text-muted" />
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user