diff --git a/src/app.scss b/src/app.scss index 4a00f11..77faba0 100644 --- a/src/app.scss +++ b/src/app.scss @@ -31,10 +31,15 @@ @mixin light { // general --accent-pink: hsl(302, 100%, 76%); + --accent-pink-alt: hsl(302, 100%, 50%); --accent-red: hsl(348, 100%, 80%); + --accent-red-alt: hsl(348, 100%, 50%); --accent-purple: hsl(264, 100%, 81%); + --accent-purple-alt: hsl(264, 100%, 50%); --accent-blue: hsl(220, 100%, 78%); + --accent-blue-alt: hsl(220, 100%, 50%); --accent: var(--accent-pink); + --accent-alt: var(--accent-pink-alt); // foregrounds --fg: hsl(0, 0%, 0%); @@ -107,10 +112,15 @@ @mixin dark { // general --accent-pink: hsl(302, 100%, 76%); + --accent-pink-alt: hsl(302, 100%, 50%); --accent-red: hsl(348, 100%, 80%); + --accent-red-alt: hsl(348, 100%, 50%); --accent-purple: hsl(264, 100%, 81%); + --accent-purple-alt: hsl(264, 100%, 50%); --accent-blue: hsl(220, 100%, 78%); + --accent-blue-alt: hsl(220, 100%, 50%); --accent: var(--accent-pink); + --accent-alt: var(--accent-pink-alt); // foregrounds --fg: hsl(0, 0%, 100%); diff --git a/src/lib/components/visual/Toast.svelte b/src/lib/components/visual/Toast.svelte new file mode 100644 index 0000000..5fa413f --- /dev/null +++ b/src/lib/components/visual/Toast.svelte @@ -0,0 +1,78 @@ + + +
+
+ +

{message}

+
+ +
\ No newline at end of file diff --git a/src/lib/store/ToastProvider.ts b/src/lib/store/ToastProvider.ts new file mode 100644 index 0000000..20c692d --- /dev/null +++ b/src/lib/store/ToastProvider.ts @@ -0,0 +1,68 @@ +import { writable } from "svelte/store"; + +export type ToastType = "success" | "error" | "info" | "warning"; + +export interface Toast { + id: number; + type: ToastType; + message: string; + disappearing: boolean; + durations: { + enter: number; + stay: number; + exit: number; + }; +} + +const toasts = writable([]); + +let toastId = 0; + +function addToast( + type: ToastType, + message: string, + disappearing?: boolean, + durations?: { enter: number; stay: number; exit: number }, +) { + const id = toastId++; + + durations = durations ?? { + enter: 300, + stay: disappearing || disappearing === undefined ? 5000 : Infinity, + exit: 500, + }; + + // if "disappearing" not set, default error/warning to infinite duration + if (disappearing === undefined) { + switch (type) { + case "error": + case "warning": + durations.stay = Infinity; + break; + } + } + + const newToast: Toast = { + id, + type, + message, + disappearing: disappearing ?? true, + durations, + }; + toasts.update((currentToasts) => [...currentToasts, newToast]); + + setTimeout( + () => { + removeToast(id); + }, + durations.enter + durations.stay + durations.exit, + ); +} + +function removeToast(id: number) { + toasts.update((currentToasts) => + currentToasts.filter((toast) => toast.id !== id), + ); +} + +export { toasts, addToast, removeToast }; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a6e4542..e5ca680 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -29,11 +29,18 @@ import "../app.scss"; import { writable } from "svelte/store"; import { DISCORD_URL, GITHUB_URL } from "$lib/consts"; + import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider"; + import Toast from "$lib/components/visual/Toast.svelte"; let { children } = $props(); let shouldGoBack = writable(false); let navbar = $state(); let hover = $state(false); + let toastList = $state([]); + + toasts.subscribe((value) => { + toastList = value as ToastType[]; + }); const items = $derived< { @@ -218,6 +225,12 @@ {/key} +
+ {#each toastList as { id, type, message, durations }} + + {/each} +
+
+ +
diff --git a/tailwind.config.ts b/tailwind.config.ts index 35381ca..4dab3f9 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -25,10 +25,15 @@ export default { }, colors: { accent: "var(--accent)", + "accent-alt": "var(--accent-alt)", "accent-pink": "var(--accent-pink)", + "accent-pink-alt": "var(--accent-pink-alt)", "accent-red": "var(--accent-red)", + "accent-red-alt": "var(--accent-red-alt)", + "accent-purple-alt": "var(--accent-purple-alt)", "accent-purple": "var(--accent-purple)", "accent-blue": "var(--accent-blue)", + "accent-blue-alt": "var(--accent-blue-alt)", }, boxShadow: { panel: "var(--shadow-panel)",