git / moonbite-network / static/shell.js · raw

/* MoonBite site shell: header scroll state, phone menu, live network pill.   External file (CSP: script-src 'self'), no inline handlers. */(function () {  "use strict";  var h = document.querySelector("[data-mbs-header]");  if (!h) return;  /* header gains its blurred background once the page scrolls */  function onScroll() { h.classList.toggle("is-scrolled", window.scrollY > 8); }  onScroll(); window.addEventListener("scroll", onScroll, { passive: true });  /* phone menu */  var btn = h.querySelector("[data-mbs-menu]"), sheet = document.getElementById("mbs-sheet");  function setOpen(open) {    if (!btn || !sheet) return;    sheet.hidden = !open; btn.setAttribute("aria-expanded", String(open));    btn.textContent = open ? "Close" : "Menu";    h.classList.toggle("is-open", open); document.body.classList.toggle("mbs-locked", open);  }  if (btn) btn.addEventListener("click", function () { setOpen(sheet.hidden); });  document.addEventListener("keydown", function (e) { if (e.key === "Escape") setOpen(false); });  window.addEventListener("resize", function () { if (window.innerWidth > 900) setOpen(false); });  /* live network pill: before launch, when mining opens (genesis is stamped     2 h after launch); afterwards, the current block height */  var pills = document.querySelectorAll("[data-mbs-status]");  if (!pills.length) return;  var CET = { timeZone: "Europe/Paris" };  function opensText(ms) {    var d = new Date(ms);    return d.toLocaleString("en-GB", Object.assign({ weekday: "short", hour: "2-digit", minute: "2-digit", timeZoneName: "short" }, CET));  }  function left(ms) {    var s = Math.max(0, Math.round((ms - Date.now()) / 1000)), d = Math.floor(s / 86400), hh = Math.floor(s % 86400 / 3600), m = Math.floor(s % 3600 / 60);    return d ? d + "d " + hh + "h" : hh ? hh + "h " + m + "m" : m + "m";  }  var state = null;  function paint() {    if (!state) return;    pills.forEach(function (p) {      var dot = p.querySelector(".mbs-dot"), txt = p.querySelector("[data-mbs-status-text]");      if (state.launchAt && Date.now() < state.launchAt) {        dot.className = "mbs-dot is-soon";        txt.innerHTML = "Mining opens <b>" + opensText(state.launchAt) + "</b> · " + left(state.launchAt);        p.title = "Nobody can mine before launch; the rule is in the genesis block.";      } else if (state.height === 0) {        dot.className = "mbs-dot is-soon"; txt.innerHTML = "Mining open · <b>block 1 unclaimed</b>";      } else {        dot.className = "mbs-dot is-live"; txt.innerHTML = "Block <b>#" + state.height + "</b>";   // heights never separated (d11)        p.title = "Live height of the MoonBite network";      }    });  }  function poll() {    fetch("/api/blockchain/info", { cache: "no-store" }).then(function (r) { return r.json(); }).then(function (d) {      if (!d || d.height === undefined) return;      var hgt = Number(d.height);      state = { height: hgt, launchAt: (hgt === 0 && d.tip_time) ? (Number(d.tip_time) - 7200) * 1000 : null };      paint();    }).catch(function () {});  }  poll(); setInterval(poll, 30000); setInterval(paint, 15000);})();