Files
filestash/public/components/notification.js
2023-10-07 22:47:37 +11:00

84 lines
3.7 KiB
JavaScript

import { createElement } from "../lib/skeleton/index.js";
import { ApplicationError } from "../lib/error.js";
import { animate, slideYIn, slideYOut } from "../lib/animate.js";
import { CSS } from "../helpers/loader.js";
const createNotification = async (msg, type) => createElement(`
<span class="component_notification">
<style>${await CSS(import.meta.url, "notification.css")}</style>
<div class="no-select">
<div class="component_notification--container ${type}">
<div class="message">${msg}</div>
<div class="close">
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MS45NzYgNTEuOTc2Ij4KICA8cGF0aCBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eTowLjUzMzMzMjg1O3N0cm9rZS13aWR0aDoxLjQ1NjgxMTE5IiBkPSJtIDQxLjAwNTMxLDQwLjg0NDA2MiBjIC0xLjEzNzc2OCwxLjEzNzc2NSAtMi45ODIwODgsMS4xMzc3NjUgLTQuMTE5ODYxLDAgTCAyNi4wNjg2MjgsMzAuMDI3MjM0IDE0LjczNzU1MSw0MS4zNTgzMSBjIC0xLjEzNzc3MSwxLjEzNzc3MSAtMi45ODIwOTMsMS4xMzc3NzEgLTQuMTE5ODYxLDAgLTEuMTM3NzcyMiwtMS4xMzc3NjggLTEuMTM3NzcyMiwtMi45ODIwODggMCwtNC4xMTk4NjEgTCAyMS45NDg3NjYsMjUuOTA3MzcyIDExLjEzMTkzOCwxNS4wOTA1NTEgYyAtMS4xMzc3NjQ3LC0xLjEzNzc3MSAtMS4xMzc3NjQ3LC0yLjk4MzU1MyAwLC00LjExOTg2MSAxLjEzNzc3NCwtMS4xMzc3NzIxIDIuOTgyMDk4LC0xLjEzNzc3MjEgNC4xMTk4NjUsMCBMIDI2LjA2ODYyOCwyMS43ODc1MTIgMzYuMzY5NzM5LDExLjQ4NjM5OSBjIDEuMTM3NzY4LC0xLjEzNzc2OCAyLjk4MjA5MywtMS4xMzc3NjggNC4xMTk4NjIsMCAxLjEzNzc2NywxLjEzNzc2OSAxLjEzNzc2NywyLjk4MjA5NCAwLDQuMTE5ODYyIEwgMzAuMTg4NDg5LDI1LjkwNzM3MiA0MS4wMDUzMSwzNi43MjQxOTcgYyAxLjEzNzc3MSwxLjEzNzc2NyAxLjEzNzc3MSwyLjk4MjA5MSAwLDQuMTE5ODY1IHoiIC8+Cjwvc3ZnPgo=" alt="close">
</div>
</div>
</div>
</span>
`);
class NotificationComponent extends window.HTMLElement {
buffer = [];
constructor() {
super();
}
async trigger(message, type) {
if (this.buffer.length > 20) this.buffer.pop(); // failsafe
this.buffer.push({ message, type });
if (this.buffer.length !== 1) {
const $close = this.querySelector(".close");
if ($close && typeof $close.onclick === "function") $close.onclick();
return;
}
await this.run();
}
async run() {
if (this.buffer.length === 0) return;
const { message, type } = this.buffer[0];
const $notification = await createNotification(message, type);
this.replaceChildren($notification);
await animate($notification, {
keyframes: slideYIn(50),
time: 100,
});
const ids = []
await Promise.race([
new Promise((done) => ids.push(window.setTimeout(done, this.buffer.length === 1 ? 8000 : 800))),
new Promise((done) => ids.push(window.setTimeout(() => $notification.querySelector(".close").onclick = done, 1000))),
]);
ids.forEach((id) => window.clearTimeout(id));
await animate($notification, {
keyframes: slideYOut(10),
time: 200,
});
$notification.remove();
this.buffer.shift();
await this.run();
}
}
customElements.define("component-notification", NotificationComponent);
function find() {
const $dom = document.body.querySelector("component-notification");
if (!($dom instanceof NotificationComponent)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: wrong type notification component");
return $dom;
}
export default class Notification {
static info(msg) {
find().trigger(msg, "info");
}
static success(msg) {
find().trigger(msg, "success");
}
static error(msg) {
find().trigger(msg, "error");
}
}