/* ===================================================================== * 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 without 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 (no leading #), 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 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 first failure hide the box quietly; if it was already showing, // leave the last-known fronters up rather than 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); }); })();