mirror of https://github.com/VERT-sh/VERT.git
chore: componetize toasts
makes creating a toast return an id, stop settings saving every time you visit page
This commit is contained in:
parent
3a839124d2
commit
775eebbc28
|
@ -0,0 +1,15 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import Toast from "$lib/components/visual/Toast.svelte";
|
||||||
|
import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider";
|
||||||
|
|
||||||
|
let toastList = $state<ToastType[]>([]);
|
||||||
|
toasts.subscribe((value) => {
|
||||||
|
toastList = value as ToastType[];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="fixed bottom-28 md:bottom-0 right-0 p-4 space-y-4 z-50">
|
||||||
|
{#each toastList as { id, type, message, durations }}
|
||||||
|
<Toast {id} {type} {message} {durations} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
|
@ -1,5 +1,6 @@
|
||||||
export { default as UploadRegion } from './UploadRegion.svelte';
|
export { default as UploadRegion } from './UploadRegion.svelte';
|
||||||
export { default as Gradients } from './Gradients.svelte';
|
export { default as Gradients } from './Gradients.svelte';
|
||||||
|
export { default as Toasts } from './Toasts.svelte';
|
||||||
export { default as Dialogs } from './Dialogs.svelte';
|
export { default as Dialogs } from './Dialogs.svelte';
|
||||||
export { default as PageContent } from './PageContent.svelte';
|
export { default as PageContent } from './PageContent.svelte';
|
||||||
export { default as MobileLogo } from './MobileLogo.svelte';
|
export { default as MobileLogo } from './MobileLogo.svelte';
|
||||||
|
|
|
@ -1,78 +1,78 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade, fly } from "$lib/animation";
|
import { fade, fly } from "$lib/animation";
|
||||||
import {
|
import {
|
||||||
BanIcon,
|
BanIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
TriangleAlert,
|
TriangleAlert,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from "lucide-svelte";
|
} from "lucide-svelte";
|
||||||
import { quintOut } from "svelte/easing";
|
import { quintOut } from "svelte/easing";
|
||||||
import { removeToast } from "$lib/store/ToastProvider";
|
import { removeToast } from "$lib/store/ToastProvider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: number;
|
id: number;
|
||||||
type: "success" | "error" | "info" | "warning";
|
type: "success" | "error" | "info" | "warning";
|
||||||
message: string;
|
message: string;
|
||||||
durations: {
|
durations: {
|
||||||
enter: number;
|
enter: number;
|
||||||
stay: number;
|
stay: number;
|
||||||
exit: number;
|
exit: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let { id, type, message, durations }: Props = $props();
|
let { id, type, message, durations }: Props = $props();
|
||||||
|
|
||||||
const color = {
|
const color = {
|
||||||
success: "purple",
|
success: "purple",
|
||||||
error: "red",
|
error: "red",
|
||||||
info: "blue",
|
info: "blue",
|
||||||
warning: "pink",
|
warning: "pink",
|
||||||
}[type];
|
}[type];
|
||||||
|
|
||||||
const Icon = {
|
const Icon = {
|
||||||
success: CheckIcon,
|
success: CheckIcon,
|
||||||
error: BanIcon,
|
error: BanIcon,
|
||||||
info: InfoIcon,
|
info: InfoIcon,
|
||||||
warning: TriangleAlert,
|
warning: TriangleAlert,
|
||||||
}[type];
|
}[type];
|
||||||
|
|
||||||
// intentionally unused. this is so tailwind can generate the css for these colours as it doesn't detect if it's dynamically loaded
|
// intentionally unused. this is so tailwind can generate the css for these colours as it doesn't detect if it's dynamically loaded
|
||||||
// this would lead to the colours not being generated in the final css file by tailwind
|
// this would lead to the colours not being generated in the final css file by tailwind
|
||||||
const colourVariants = [
|
const colourVariants = [
|
||||||
"border-accent-pink-alt",
|
"border-accent-pink-alt",
|
||||||
"border-accent-red-alt",
|
"border-accent-red-alt",
|
||||||
"border-accent-purple-alt",
|
"border-accent-purple-alt",
|
||||||
"border-accent-blue-alt",
|
"border-accent-blue-alt",
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between w-full max-w-sm p-4 gap-4 bg-accent-{color} border-accent-{color}-alt border-l-4 rounded-lg shadow-md"
|
class="flex items-center justify-between w-full max-w-sm p-4 gap-4 bg-accent-{color} border-accent-{color}-alt border-l-4 rounded-lg shadow-md"
|
||||||
in:fly={{
|
in:fly={{
|
||||||
duration: durations.enter,
|
duration: durations.enter,
|
||||||
easing: quintOut,
|
easing: quintOut,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 100,
|
y: 100,
|
||||||
}}
|
}}
|
||||||
out:fade={{
|
out:fade={{
|
||||||
duration: durations.exit,
|
duration: durations.exit,
|
||||||
easing: quintOut,
|
easing: quintOut,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<Icon
|
<Icon
|
||||||
class="w-6 h-6 text-black flex-shrink-0"
|
class="w-6 h-6 text-black flex-shrink-0"
|
||||||
size="32"
|
size="32"
|
||||||
stroke="2"
|
stroke="2"
|
||||||
fill="none"
|
fill="none"
|
||||||
/>
|
/>
|
||||||
<p class="text-black font-normal">{message}</p>
|
<p class="text-black font-normal">{message}</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="text-gray-600 hover:text-black"
|
class="text-gray-600 hover:text-black"
|
||||||
onclick={() => removeToast(id)}
|
onclick={() => removeToast(id)}
|
||||||
>
|
>
|
||||||
<XIcon size="16" />
|
<XIcon size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,6 +47,8 @@ function addToast(
|
||||||
},
|
},
|
||||||
durations.enter + durations.stay + durations.exit,
|
durations.enter + durations.stay + durations.exit,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeToast(id: number) {
|
function removeToast(id: number) {
|
||||||
|
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
||||||
import { VERT_NAME } from "$lib/consts";
|
import { VERT_NAME } from "$lib/consts";
|
||||||
import Toast from "$lib/components/visual/Toast.svelte";
|
|
||||||
import * as Layout from "$lib/components/layout";
|
import * as Layout from "$lib/components/layout";
|
||||||
import * as Navbar from "$lib/components/layout/Navbar";
|
import * as Navbar from "$lib/components/layout/Navbar";
|
||||||
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
||||||
import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider";
|
|
||||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||||
import {
|
import {
|
||||||
files,
|
files,
|
||||||
|
@ -21,12 +19,6 @@
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
let toastList = $state<ToastType[]>([]);
|
|
||||||
|
|
||||||
toasts.subscribe((value) => {
|
|
||||||
toastList = value as ToastType[];
|
|
||||||
});
|
|
||||||
|
|
||||||
const dropFiles = (e: DragEvent) => {
|
const dropFiles = (e: DragEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
dropping.set(false);
|
dropping.set(false);
|
||||||
|
@ -116,12 +108,7 @@
|
||||||
-->
|
-->
|
||||||
<Layout.PageContent {children} />
|
<Layout.PageContent {children} />
|
||||||
|
|
||||||
<div class="fixed bottom-28 md:bottom-0 right-0 p-4 space-y-4 z-50">
|
<Layout.Toasts />
|
||||||
{#each toastList as { id, type, message, durations }}
|
|
||||||
<Toast {id} {type} {message} {durations} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Layout.Dialogs />
|
<Layout.Dialogs />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -16,17 +16,18 @@
|
||||||
isInitial = false;
|
isInitial = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
settings;
|
|
||||||
const savedSettings = localStorage.getItem("settings");
|
const savedSettings = localStorage.getItem("settings");
|
||||||
if (savedSettings) {
|
if (savedSettings) {
|
||||||
const parsedSettings = JSON.parse(savedSettings);
|
const parsedSettings = JSON.parse(savedSettings);
|
||||||
if (parsedSettings === settings) return;
|
if (JSON.stringify(parsedSettings) === JSON.stringify(settings))
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(["settings"], "saving settings");
|
|
||||||
try {
|
try {
|
||||||
Settings.Settings.instance.settings = settings;
|
Settings.Settings.instance.settings = settings;
|
||||||
Settings.Settings.instance.save();
|
Settings.Settings.instance.save();
|
||||||
|
log(["settings"], "saving settings");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log(["settings", "error"], `failed to save settings: ${error}`);
|
log(["settings", "error"], `failed to save settings: ${error}`);
|
||||||
addToast("error", "Failed to save settings!");
|
addToast("error", "Failed to save settings!");
|
||||||
|
|
Loading…
Reference in New Issue