feat: add toast component

This commit is contained in:
2026-05-07 17:01:33 +02:00
parent 73155dcb46
commit 308626bcdc
4 changed files with 132 additions and 3 deletions
+36
View File
@@ -0,0 +1,36 @@
<script lang="ts">
import { toasts } from './toast.svelte';
const typeClasses: Record<string, string> = {
success: 'border-l-green-500',
error: 'border-l-red-500',
info: 'border-l-active'
};
</script>
<div
class="fixed bottom-4 right-4 flex flex-col gap-2 z-[9999] pointer-events-none"
role="status"
aria-live="polite"
aria-atomic="false"
>
{#each toasts.value as item (item.id)}
<div
class="
bg-layer-2 text-text border border-outline rounded
px-3.5 py-2 text-sm min-w-[180px] max-w-xs
border-l-3 {typeClasses[item.type] ?? 'border-l-outline'}
animate-[slide-in_0.18s_ease]
"
>
{item.message}
</div>
{/each}
</div>
<style>
@keyframes slide-in {
from { opacity: 0; transform: translateX(12px); }
to { opacity: 1; transform: translateX(0); }
}
</style>
+6
View File
@@ -2,14 +2,20 @@ export { default as Input } from './Input.svelte';
export { default as InputCheckbox } from './inputs/InputCheckbox.svelte';
export { default as InputColor } from './inputs/InputColor.svelte';
export { default as InputNumber } from './inputs/InputNumber.svelte';
export { default as InputSearch } from './inputs/InputSearch.svelte';
export { default as InputSelect } from './inputs/InputSelect.svelte';
export { default as InputShape } from './inputs/InputShape.svelte';
export { default as InputVec3 } from './inputs/InputVec3.svelte';
export { default as SocketTable } from './inputs/SocketTable.svelte';
export { default as Button } from './Button.svelte';
export { default as Details } from './Details.svelte';
export { default as JsonViewer } from './JsonViewer.svelte';
export { default as ShortCut } from './ShortCut.svelte';
export { default as Spinner } from './Spinner.svelte';
export { default as Toast } from './Toast.svelte';
export { toast } from './toast.svelte';
export { default as ConfirmDialog } from './ConfirmDialog.svelte';
import Input from './Input.svelte';
export default Input;
+24
View File
@@ -0,0 +1,24 @@
export type ToastType = 'info' | 'success' | 'error';
export type ToastItem = {
id: number;
message: string;
type: ToastType;
};
let _toasts = $state<ToastItem[]>([]);
let _nextId = 0;
export const toasts = {
get value() {
return _toasts;
}
};
export function toast(message: string, type: ToastType = 'info', duration = 3000) {
const id = _nextId++;
_toasts.push({ id, message, type });
setTimeout(() => {
_toasts = _toasts.filter((t) => t.id !== id);
}, duration);
}