Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| <script lang="ts"> | |
| import { onDestroy, type Snippet } from "svelte"; | |
| import { computePosition, autoUpdate } from "@floating-ui/dom"; | |
| import { fly } from "svelte/transition"; | |
| interface Props { | |
| children: Snippet<[{ addToast: typeof addToast; trigger: typeof trigger }]>; | |
| closeDelay?: number; | |
| } | |
| const { children, closeDelay = 2000 }: Props = $props(); | |
| const id = $props.id(); | |
| const trigger = { | |
| id, | |
| } as const; | |
| type Toast = { | |
| content: string; | |
| id: string; | |
| }; | |
| let toasts = $state<Toast[]>([]); | |
| let timeouts: ReturnType<typeof window.setTimeout>[] = []; | |
| function addToast(content: string) { | |
| const id = crypto.randomUUID(); | |
| const timeout = setTimeout(() => { | |
| toasts = toasts.filter(t => t.id !== id); | |
| timeouts = timeouts.filter(t => t !== timeout); | |
| }, closeDelay); | |
| toasts.push({ content, id }); | |
| timeouts.push(timeout); | |
| } | |
| onDestroy(() => { | |
| timeouts.forEach(t => clearTimeout(t)); | |
| }); | |
| function float(node: HTMLElement) { | |
| const triggerEl = document.getElementById(trigger.id); | |
| if (!triggerEl) return; | |
| const compute = () => | |
| computePosition(triggerEl, node, { | |
| placement: "top", | |
| strategy: "absolute", | |
| }).then(({ x, y }) => { | |
| Object.assign(node.style, { | |
| left: `${x}px`, | |
| top: `${y - 8}px`, | |
| }); | |
| }); | |
| return { | |
| destroy: autoUpdate(triggerEl, node, compute), | |
| }; | |
| } | |
| </script> | |
| {@render children({ trigger, addToast })} | |
| {#each toasts as toast (toast.id)} | |
| <div | |
| class="rounded-full border border-blue-400 bg-gradient-to-b from-blue-500 to-blue-600 px-2 py-1 text-xs" | |
| in:fly={{ y: 10 }} | |
| out:fly={{ y: -4 }} | |
| use:float | |
| > | |
| {toast.content} | |
| </div> | |
| {/each} | |
| <style> | |
| div { | |
| /* Float on top of the UI */ | |
| position: absolute; | |
| /* Avoid layout interference */ | |
| width: max-content; | |
| top: 0; | |
| left: 0; | |
| } | |
| </style> | |