// Shared UI helpers: toasts and a reusable progress panel. import { h, fmtElapsed } from "./dom"; export function toast(message: string, kind: "ok" | "err" | "" = "") { const host = document.getElementById("toasts")!; const el = h("div", { class: `toast ${kind}` }, h("span", {}, kind === "ok" ? "✓" : kind === "err" ? "⚠" : "•"), h("span", {}, message), ); host.append(el); setTimeout(() => { el.style.transition = "opacity .25s, transform .25s"; el.style.opacity = "0"; el.style.transform = "translateY(8px)"; setTimeout(() => el.remove(), 260); }, kind === "err" ? 6000 : 3200); } /** A progress bar + status/timing line + collapsible log, returned as one unit. */ export function makeProgress() { const fill = h("i"); const bar = h("div", { class: "bar" }, fill); const status = h("span", { class: "status" }, "Ready"); const timing = h("span", { class: "timing" }); const log = h("div", { class: "log" }); const root = h("div", { class: "progress-wrap" }, bar, h("div", { class: "progress-meta" }, status, timing), log, ); return { root, reset() { bar.classList.remove("indeterminate"); fill.style.width = "0%"; status.textContent = "Ready"; timing.textContent = ""; log.textContent = ""; }, indeterminate(on: boolean, text?: string) { bar.classList.toggle("indeterminate", on); if (on) fill.style.width = "35%"; if (text) status.textContent = text; }, set(pct: number, statusText: string, opts?: { elapsed?: number; eta?: number; speed?: number }) { bar.classList.remove("indeterminate"); fill.style.width = `${Math.round(pct * 100)}%`; status.textContent = statusText; if (opts) { const bits: string[] = []; if (opts.elapsed != null) bits.push(`Elapsed ${fmtElapsed(opts.elapsed)}`); if (opts.eta != null && opts.eta > 0) bits.push(`ETA ${fmtElapsed(opts.eta)}`); if (opts.speed != null && opts.speed > 0) bits.push(`${opts.speed.toFixed(1)}×`); timing.textContent = bits.join(" · "); } }, setTiming(text: string) { timing.textContent = text; }, appendLog(line: string) { log.textContent += (log.textContent ? "\n" : "") + line; log.scrollTop = log.scrollHeight; }, }; } export type Progress = ReturnType;