reorganize code into smaller files & dirs
This commit is contained in:
61
packages/app/src/Components/Toaster/Toaster.tsx
Normal file
61
packages/app/src/Components/Toaster/Toaster.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import "./Toaster.css";
|
||||
import { ReactNode, useSyncExternalStore } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { ExternalStore, unixNow } from "@snort/shared";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
|
||||
interface ToastNotification {
|
||||
element: ReactNode | ((remove: () => void) => ReactNode);
|
||||
expire?: number;
|
||||
icon?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
class ToasterSlots extends ExternalStore<Array<ToastNotification>> {
|
||||
#stack: Array<ToastNotification> = [];
|
||||
#cleanup = setInterval(() => this.#eatToast(), 1000);
|
||||
|
||||
push(n: ToastNotification) {
|
||||
n.expire ??= unixNow() + 10;
|
||||
n.id ??= uuid();
|
||||
this.#stack.push(n);
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
takeSnapshot(): ToastNotification[] {
|
||||
return [...this.#stack];
|
||||
}
|
||||
|
||||
remove(id?: string) {
|
||||
this.#stack = this.#stack.filter(a => a.id !== id);
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
#eatToast() {
|
||||
const now = unixNow();
|
||||
this.#stack = this.#stack.filter(a => (a.expire ?? 0) > now);
|
||||
this.notifyChange();
|
||||
}
|
||||
}
|
||||
|
||||
export const Toastore = new ToasterSlots();
|
||||
|
||||
export default function Toaster() {
|
||||
const toast = useSyncExternalStore(
|
||||
c => Toastore.hook(c),
|
||||
() => Toastore.snapshot(),
|
||||
);
|
||||
|
||||
return createPortal(
|
||||
<div className="toaster">
|
||||
{toast.map(a => (
|
||||
<div className="p br b flex bg-dark g8 fade-in" key={a.id}>
|
||||
{a.icon && <Icon name={a.icon} />}
|
||||
{typeof a.element === "function" ? a.element(() => Toastore.remove(a.id)) : a.element}
|
||||
</div>
|
||||
))}
|
||||
</div>,
|
||||
document.body,
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user