a simple web player for subsonic tinysub.devins.page
subsonic navidrome javascript
at main 56 lines 1.4 kB view raw
1// generic DOM utilities and element factories 2 3// generic element creator 4function createElement(tag, config = {}) { 5 const { 6 className, 7 textContent, 8 html, 9 attributes = {}, 10 listeners = {}, 11 children = [], 12 } = config; 13 const el = document.createElement(tag); 14 if (className) el.className = className; 15 if (textContent) el.textContent = textContent; 16 if (html) el.innerHTML = html; 17 Object.entries(attributes).forEach(([key, value]) => 18 el.setAttribute(key, value), 19 ); 20 Object.entries(listeners).forEach(([event, handler]) => 21 el.addEventListener(event, handler), 22 ); 23 children.forEach((child) => el.appendChild(child)); 24 return el; 25} 26 27// create a button with icon 28function createIconButton(className, alt, iconPath, onCallback) { 29 const btn = createElement("button", { 30 className, 31 children: [createElement("img", { attributes: { src: iconPath, alt } })], 32 }); 33 34 if (onCallback) { 35 btn.addEventListener("click", async (e) => { 36 e.preventDefault(); 37 btn.classList.add(CLASSES.DISABLED); 38 try { 39 await onCallback(); 40 } finally { 41 btn.classList.remove(CLASSES.DISABLED); 42 } 43 }); 44 } 45 46 return btn; 47} 48 49// format seconds as mm:ss string 50function formatDuration(seconds) { 51 if (!seconds || !Number.isFinite(seconds)) return "0:00"; 52 const minutes = Math.floor(seconds / 60); 53 return `${minutes}:${Math.floor(seconds % 60) 54 .toString() 55 .padStart(2, "0")}`; 56}