| <script lang="ts"> |
| import { onMount, createEventDispatcher } from "svelte"; |
|
|
| const dispatch = createEventDispatcher(); |
| let loader: HTMLDivElement | undefined = $state(); |
| let observer: IntersectionObserver; |
| let intervalId: ReturnType<typeof setInterval> | undefined; |
|
|
| onMount(() => { |
| if (!loader) { |
| return; |
| } |
|
|
| observer = new IntersectionObserver((entries) => { |
| entries.forEach((entry) => { |
| if (entry.isIntersecting) { |
| |
| if (intervalId) { |
| clearInterval(intervalId); |
| } |
| |
| intervalId = setInterval(() => { |
| dispatch("visible"); |
| }, 250); |
| } else { |
| |
| if (intervalId) { |
| clearInterval(intervalId); |
| intervalId = undefined; |
| } |
| } |
| }); |
| }); |
|
|
| observer.observe(loader); |
|
|
| return () => { |
| observer.disconnect(); |
| if (intervalId) { |
| clearInterval(intervalId); |
| } |
| }; |
| }); |
| </script> |
|
|
| <div bind:this={loader} class="flex animate-pulse flex-col gap-4"> |
| <div class="ml-2 h-5 w-4/5 gap-5 rounded bg-gray-200 dark:bg-gray-700"></div> |
| <div class="ml-2 h-5 w-4/5 gap-5 rounded bg-gray-200 dark:bg-gray-700"></div> |
| <div class="ml-2 h-5 w-4/5 gap-5 rounded bg-gray-200 dark:bg-gray-700"></div> |
| </div> |
|
|