export function h(tag, props = {}, ...children) { const el = document.createElement(tag); const { class: className, style, data, ...rest } = props; if (className) { el.className = className; } if (style) { el.setAttribute("style", style); } for (const [key, value] of Object.entries(data ?? {})) { el.dataset[key] = value; } Object.assign(el, rest); append(el, ...children); return el; } export function append(el, ...children) { for (const child of children) { if (child === null || child === undefined || child === false) { continue; } el.appendChild(typeof child === "object" ? child : document.createTextNode(String(child))); } } export function replace(el, ...children) { el.replaceChildren(); append(el, ...children); } export function ago(iso) { const seconds = Math.round((Date.now() - Date.parse(iso)) / 1000); if (seconds < 60) { return "just now"; } if (seconds < 3600) { return `${Math.floor(seconds / 60)}m ago`; } if (seconds < 86400) { return `${Math.floor(seconds / 3600)}h ago`; } return `${Math.floor(seconds / 86400)}d ago`; } export function errorText(err) { return err instanceof Error ? err.message : String(err); } function modal(text, buttons) { const actions = buttons.map((b) => h("button", { type: "submit", value: b.value, class: b.class ?? "" }, b.label)); const dialog = h("dialog", { class: "modal" }, h("form", { method: "dialog" }, h("p", { class: "modal-text" }, text), h("div", { class: "modal-actions" }, ...actions))); document.body.append(dialog); return new Promise((resolve) => { dialog.onclose = () => { dialog.remove(); resolve(dialog.returnValue); }; dialog.showModal(); actions.at(-1)?.focus(); }); } export function openPanel(title, mount) { if (document.querySelector("dialog.panel[open]")) { return; } const close = h("button", { type: "button", class: "panel-close", title: "Close (Esc)" }, "×"); const body = h("div", { class: "panel-body" }); const dialog = h("dialog", { class: "modal panel" }, h("header", { class: "panel-head" }, h("h2", {}, title), close), body); close.onclick = () => dialog.close(); dialog.onclick = (e) => { if (e.target === dialog || e.target.closest("a[href^='#']")) { dialog.close(); } }; document.body.append(dialog); const dispose = mount(body); dialog.onclose = () => { dispose(); dialog.remove(); }; dialog.showModal(); } export async function showAlert(text) { await modal(text, [{ label: "OK", value: "ok", class: "primary" }]); } export async function showConfirm(text, action, danger = false) { const value = await modal(text, [ { label: "Cancel", value: "cancel" }, { label: action, value: "ok", class: danger ? "danger-primary" : "primary" }, ]); return value === "ok"; } //# sourceMappingURL=dom.js.map