// generic DOM utilities and element factories // generic element creator function createElement(tag, config = {}) { const { className, textContent, html, attributes = {}, listeners = {}, children = [], } = config; const el = document.createElement(tag); if (className) el.className = className; if (textContent) el.textContent = textContent; if (html) el.innerHTML = html; Object.entries(attributes).forEach(([key, value]) => el.setAttribute(key, value), ); Object.entries(listeners).forEach(([event, handler]) => el.addEventListener(event, handler), ); children.forEach((child) => el.appendChild(child)); return el; } // create a button with icon function createIconButton(className, alt, iconPath, onCallback) { const btn = createElement("button", { className, children: [createElement("img", { attributes: { src: iconPath, alt } })], }); if (onCallback) { btn.addEventListener("click", async (e) => { e.preventDefault(); btn.classList.add(CLASSES.DISABLED); try { await onCallback(); } finally { btn.classList.remove(CLASSES.DISABLED); } }); } return btn; } // format seconds as mm:ss string function formatDuration(seconds) { if (!seconds || !Number.isFinite(seconds)) return "0:00"; const minutes = Math.floor(seconds / 60); return `${minutes}:${Math.floor(seconds % 60) .toString() .padStart(2, "0")}`; }