/* fronting.js * * Homepage "who's fronting" box. Polls the system's PluralKit-style API * for the current fronter(s) and renders a small card. Each member links * to their page on the system site. Refreshes every 30s so switches show * up without needing a reload. */ (function fronting() { "use strict"; const mount = document.getElementById("fronting"); if (!mount) return; const API = "https://doughmination.co.uk/api/fronters"; const POLL_MS = 30000; function esc(s) { return String(s == null ? "" : s) .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } /* member.color is a 6-char hex string with no leading #, and may be null. */ function colorHex(c) { return /^[0-9a-fA-F]{6}$/.test(c || "") ? "#" + c : null; } /* ---- build the shell ---- */ const card = document.createElement("section"); card.id = "fronting"; card.className = "fronting-card"; card.hidden = true; card.setAttribute("aria-label", "Currently fronting"); card.innerHTML = '
' + '' + 'Currently fronting' + '
' + '
'; mount.replaceWith(card); const membersEl = card.querySelector(".fr-members"); function memberHtml(m) { const name = m.display_name || m.name || "Unknown"; const accent = colorHex(m.color); const av = m.avatar_url ? '' : ''; const pronouns = m.pronouns ? '' + esc(m.pronouns) + '' : ""; return '
' + av + '' + '' + esc(name) + '' + pronouns + '' + '
'; } function render(members) { if (!Array.isArray(members) || !members.length) { /* No one registered as fronting, keep the box up but say so. */ membersEl.innerHTML = 'no one is currently fronting'; card.hidden = false; return; } membersEl.innerHTML = members.map(memberHtml).join(""); card.hidden = false; } let failed = false; function load() { fetch(API, { headers: { Accept: "application/json" } }) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (j) { if (!j) throw new Error("bad response"); render(j.members || []); failed = false; }) .catch(function () { /* On the first failure, hide the box quietly. If it was already * showing, leave the last known fronters up instead of flashing * an error. */ if (!failed && card.hidden) card.hidden = true; failed = true; }); } load(); const timer = setInterval(load, POLL_MS); /* Refresh immediately when the tab becomes visible again. */ document.addEventListener("visibilitychange", function () { if (!document.hidden) load(); }); window.addEventListener("beforeunload", function () { clearInterval(timer); }); })();