|
|
@@ -0,0 +1,64 @@
|
|
|
+/** @typedef {'ok' | 'fail' | 'warn' | 'info'} NoticeKind */
|
|
|
+
|
|
|
+/**
|
|
|
+ * @typedef {object} Notice
|
|
|
+ * @property {number} id
|
|
|
+ * @property {NoticeKind} kind
|
|
|
+ * @property {string} message
|
|
|
+ * @property {ReturnType<typeof setTimeout>} [timer]
|
|
|
+ */
|
|
|
+
|
|
|
+const DEFAULT_MS = 4000;
|
|
|
+
|
|
|
+let nextId = 0;
|
|
|
+
|
|
|
+/** @type {Notice[]} */
|
|
|
+export const notices = $state([]);
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {number} id
|
|
|
+ */
|
|
|
+export function dismiss(id) {
|
|
|
+ const index = notices.findIndex((notice) => notice.id === id);
|
|
|
+ if (index === -1) return;
|
|
|
+
|
|
|
+ const [notice] = notices.splice(index, 1);
|
|
|
+ if (notice?.timer) clearTimeout(notice.timer);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {string} message
|
|
|
+ * @param {NoticeKind} [kind]
|
|
|
+ * @param {{ duration?: number }} [options]
|
|
|
+ * @returns {number}
|
|
|
+ */
|
|
|
+export function notify(message, kind = 'info', options = {}) {
|
|
|
+ const text = String(message ?? '').trim();
|
|
|
+ if (!text) return -1;
|
|
|
+
|
|
|
+ const id = ++nextId;
|
|
|
+ const duration = options.duration ?? DEFAULT_MS;
|
|
|
+
|
|
|
+ /** @type {Notice} */
|
|
|
+ const notice = { id, kind, message: text };
|
|
|
+ notices.push(notice);
|
|
|
+
|
|
|
+ if (duration > 0) {
|
|
|
+ notice.timer = setTimeout(() => dismiss(id), duration);
|
|
|
+ }
|
|
|
+
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+export const notifier = {
|
|
|
+ /** @param {string} message @param {{ duration?: number }} [options] */
|
|
|
+ info: (message, options) => notify(message, 'info', options),
|
|
|
+ /** @param {string} message @param {{ duration?: number }} [options] */
|
|
|
+ ok: (message, options) => notify(message, 'ok', options),
|
|
|
+ /** @param {string} message @param {{ duration?: number }} [options] */
|
|
|
+ warn: (message, options) => notify(message, 'warn', options),
|
|
|
+ /** @param {string} message @param {{ duration?: number }} [options] */
|
|
|
+ fail: (message, options) => notify(message, 'fail', options),
|
|
|
+ dismiss,
|
|
|
+ notify
|
|
|
+};
|