Complete Toaster system

This commit is contained in:
2025-03-28 17:02:58 +01:00
parent ca2bd2f50a
commit 3aa6590c9a
6 changed files with 92 additions and 42 deletions

View File

@@ -0,0 +1,60 @@
<script lang="ts">
import {
melt,
type Toast,
type ToastsElements,
} from '@melt-ui/svelte';
import type { ToastData } from "$lib/ToastSystem/types";
import { onMount } from "svelte";
interface Props {
elements: ToastsElements,
toast: Toast<ToastData>,
}
const { elements, toast }: Props = $props();
const { content, title, description, close } = $derived(elements);
const { data, id, getPercentage } = $derived(toast);
const alertClass = $derived.by(() => {
switch (data.type) {
case "success":
return 'alert-success';
case "warning":
return 'alert-warning';
case "error":
return 'alert-error';
case "info":
return 'alert-info';
default:
return '';
}
});
let percentage = $state(0);
onMount(() => {
let frame: number;
const updatePercentage = () => {
percentage = getPercentage();
frame = requestAnimationFrame(updatePercentage);
};
frame = requestAnimationFrame(updatePercentage);
return () => cancelAnimationFrame(frame);
});
</script>
<div use:melt={$content(id)} class="relative w-[70%] visible">
<div class="absolute w-full flex flex-col px-2">
<progress class="progress h-1 w-full" value={percentage} max="100"></progress>
</div>
<div class={["alert", alertClass]}>
<button use:melt={$close(id)} aria-label="close notification" class="absolute right-2 top-0">x</button>
<h3 use:melt={$title(id)} class="font-bold">
{data.title}
</h3>
<div use:melt={$description(id)}>
{data.description}
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<script lang="ts" module>
import { createToaster } from '@melt-ui/svelte';
import type { ToastData } from "$lib/ToastSystem/types";
const {
elements,
helpers,
states: { toasts },
actions: { portal }
} = createToaster<ToastData>();
export const addToast = helpers.addToast;
</script>
<script>
import Toast from "$lib/ToastSystem/Toast.svelte";
</script>
<div use:portal
class="fixed w-screen h-screen top-0 z-50 pb-4 flex flex-col-reverse justify-start items-center gap-2 invisible">
{#each $toasts as toast (toast.id)}
<Toast {elements} {toast}/>
{/each}
</div>

View File

@@ -0,0 +1,5 @@
export type ToastData = {
title: string
description: string
type: 'info' | 'success' | 'warning' | 'error',
}

View File

@@ -1,38 +0,0 @@
<script lang="ts" module>
import { createToaster, melt } from '@melt-ui/svelte';
export type ToastData = {
title: string
description: string
color: string
}
// TODO: Change color with type e setta classe
// TODO: Usa getPercentage per mostrare la loading bar sugli alert!
const {
elements: { content, title, description, close },
helpers,
states: { toasts },
actions: { portal }
} = createToaster<ToastData>();
export const addToast = helpers.addToast;
</script>
<div use:portal class="fixed w-screen top-0 z-50 m-4 flex flex-col items-center gap-2 invisible">
{#each $toasts as { id, data } (id)}
<div use:melt={$content(id)} class="alert alert-info relative w-[70%] visible">
<div>
<h3 use:melt={$title(id)} class="font-bold">
{data.title}
<!-- <span style:color={data.color}></span>-->
</h3>
<div use:melt={$description(id)}>
{data.description}
</div>
</div>
<button use:melt={$close(id)} aria-label="close notification" class="absolute right-2 top-0">x</button>
</div>
{/each}
</div>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import '../app.css';
import Toaster from "$lib/Toaster.svelte";
import Toaster from "$lib/ToastSystem/Toaster.svelte";
let { children } = $props();
</script>

View File

@@ -2,7 +2,7 @@
import { scale } from 'svelte/transition';
import { goto } from "$app/navigation";
import BSlideOverlay from "$lib/BSlideOverlay.svelte";
import { addToast } from '$lib/Toaster.svelte';
import { addToast } from '$lib/ToastSystem/Toaster.svelte';
let { data } = $props();
@@ -29,11 +29,11 @@
function test() {
addToast({
closeDelay: 50000,
closeDelay: 5000,
data: {
title: 'Success',
description: 'The resource was created!',
color: 'green'
type: 'success'
},
});
}