diff --git a/src/lib/components/Toast.svelte b/src/lib/components/Toast.svelte new file mode 100644 index 0000000..9d6a9ed --- /dev/null +++ b/src/lib/components/Toast.svelte @@ -0,0 +1,66 @@ + + + + + diff --git a/src/lib/components/Toasts.svelte b/src/lib/components/Toasts.svelte new file mode 100644 index 0000000..379c894 --- /dev/null +++ b/src/lib/components/Toasts.svelte @@ -0,0 +1,32 @@ + + +{#if $toasts} +
+ {#each $toasts as toast (toast.id)} + dismissToast(toast.id)}>{toast.message} + {/each} +
+{/if} + + diff --git a/src/lib/components/store.ts b/src/lib/components/store.ts new file mode 100644 index 0000000..07ad73c --- /dev/null +++ b/src/lib/components/store.ts @@ -0,0 +1,70 @@ +import { writable } from "svelte/store"; + +interface ToastNotification { + id: number; + type: "info" | "success" | "error" | "warning"; + dismissible: boolean; + timeout: number; + message: string; +} + +export const toasts = writable([]); + +interface InternalToast { + type: "info" | "success" | "error" | "warning"; + dismissible: boolean; + timeout: number; + message: string; +} + +const addToast = (toast: InternalToast) => { + // Create a unique ID so we can easily find/remove it + // if it is dismissible/has a timeout. + const id = Math.floor(Math.random() * 10000); + + // Setup some sensible defaults for a toast. + const defaults = { + id, + type: "info", + dismissible: true, + timeout: 3000, + }; + + // Push the toast to the top of the list of toasts + toasts.update((all) => [{ ...defaults, ...toast }, ...all]); + + // If toast is dismissible, dismiss it after "timeout" amount of time. + if (toast.timeout) setTimeout(() => dismissToast(id), toast.timeout); +}; + +export const dismissToast = (id: number) => { + toasts.update((all) => all.filter((t) => t.id !== id)); +}; + +export const addSuccessToast = (message: string, dismissible: boolean = false, timeout: number = 1000) => { + addToast({ + type: "success", + dismissible, + timeout, + message, + }) +} + +export const addErrorToast = (message: string, dismissible: boolean = false, timeout: number = 1000) => { + addToast({ + type: "error", + dismissible, + timeout, + message, + }) +} + +export const addInfoToast = (message: string, dismissible: boolean = false, timeout: number = 1000) => { + addToast({ + type: "error", + dismissible, + timeout, + message, + }) +} + diff --git a/src/lib/icons/CloseIcon.svelte b/src/lib/icons/CloseIcon.svelte new file mode 100644 index 0000000..2911de3 --- /dev/null +++ b/src/lib/icons/CloseIcon.svelte @@ -0,0 +1,18 @@ + + + diff --git a/src/lib/icons/ErrorIcon.svelte b/src/lib/icons/ErrorIcon.svelte new file mode 100644 index 0000000..059d916 --- /dev/null +++ b/src/lib/icons/ErrorIcon.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/lib/icons/InfoIcon.svelte b/src/lib/icons/InfoIcon.svelte new file mode 100644 index 0000000..d39711b --- /dev/null +++ b/src/lib/icons/InfoIcon.svelte @@ -0,0 +1,18 @@ + + + diff --git a/src/lib/icons/SuccessIcon.svelte b/src/lib/icons/SuccessIcon.svelte new file mode 100644 index 0000000..18a7b93 --- /dev/null +++ b/src/lib/icons/SuccessIcon.svelte @@ -0,0 +1,18 @@ + + +