shared: goa-stats snippet assets for landings

This commit is contained in:
Hernâni Marques 2026-07-09 14:15:26 +02:00
parent 8bd0ec24a0
commit ef40149ed2
No known key found for this signature in database
3 changed files with 255 additions and 0 deletions

View file

@ -0,0 +1,39 @@
<!-- Include CSS: goa-stats.css JS: goa-stats.js -->
<section class="stats" id="stats" aria-labelledby="stats-title" hidden>
<h2 id="stats-title">GOA flow</h2>
<div class="stats-grid">
<div class="stat">
<span class="k">Accounts</span>
<span class="v teal" id="st-accounts"></span>
</div>
<div class="stat">
<span class="k">Bank credits</span>
<span class="v teal" id="st-incoming"></span>
</div>
<div class="stat">
<span class="k">Withdraws</span>
<span class="v" id="st-withdraw"></span>
</div>
<div class="stat">
<span class="k">Unique wallets</span>
<span class="v teal" id="st-wallets"></span>
</div>
<div class="stat">
<span class="k">24h</span>
<span class="v" id="st-24h"></span>
</div>
<div class="stat">
<span class="k">7d</span>
<span class="v" id="st-7d"></span>
</div>
<div class="stat wide">
<span class="k">Recent Withdraws</span>
<ul class="wd-list" id="st-recent" aria-live="polite">
<li class="meta"></li>
</ul>
</div>
</div>
<p class="stats-foot" id="st-foot">
<a href="https://bank.hacktivism.ch/intro/">bank.hacktivism.ch</a>
</p>
</section>

View file

@ -0,0 +1,86 @@
/* Shared GOA flow stats (used on bank / exchange / merchant landings) */
.stats {
background: rgba(18, 28, 28, 0.55);
border: 1px solid rgba(62, 207, 191, 0.28);
border-radius: 16px;
padding: 1.1rem 1.15rem 1.2rem;
margin: 0 0 1.5rem;
}
.stats h2 {
margin: 0 0 0.85rem;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted, #c9b8a0);
text-align: center;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.65rem 0.85rem;
}
@media (min-width: 420px) {
.stats-grid { grid-template-columns: 1fr 1fr 1fr; }
}
.stat {
background: rgba(0, 0, 0, 0.22);
border-radius: 10px;
padding: 0.55rem 0.65rem;
min-width: 0;
}
.stat .k {
display: block;
font-size: 0.68rem;
color: var(--muted, #c9b8a0);
letter-spacing: 0.04em;
text-transform: uppercase;
margin-bottom: 0.2rem;
text-align: center;
}
.stat .v {
display: block;
font-size: 1.05rem;
font-weight: 750;
color: #f0d090;
word-break: break-word;
font-variant-numeric: tabular-nums;
text-align: center;
}
.stat .v.teal { color: #5eead4; }
.stat.wide { grid-column: 1 / -1; }
.wd-list {
list-style: none;
margin: 0.15rem 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.wd-list li {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 0.25rem 0.75rem;
font-size: 0.88rem;
font-weight: 650;
color: #f0d090;
font-variant-numeric: tabular-nums;
border-bottom: 1px solid rgba(201, 184, 160, 0.12);
padding-bottom: 0.3rem;
}
.wd-list li:last-child { border-bottom: none; padding-bottom: 0; }
.wd-list .amt { color: #5eead4; font-weight: 750; }
.wd-list .meta {
color: var(--muted, #c9b8a0);
font-size: 0.78rem;
font-weight: 600;
}
.stats-foot {
margin: 0.75rem 0 0;
font-size: 0.72rem;
color: var(--muted, #c9b8a0);
text-align: center;
}
.stats-foot a { color: #e8c878; }
.stats-foot.err { color: #f0a090; }

130
configs/shared/goa-stats.js Normal file
View file

@ -0,0 +1,130 @@
/* Load GOA flow stats from bank landing stats.json (CORS on bank). */
(function () {
var STATS_URL = "https://bank.hacktivism.ch/intro/stats.json";
var BANK_INTRO = "https://bank.hacktivism.ch/intro/";
function fmtCest(unix, fallback) {
var base = "";
if (fallback) {
base = String(fallback).replace(/\s*(CEST|CET|UTC|Z)\s*$/i, "").trim();
} else if (unix != null && unix !== "") {
try {
base = new Intl.DateTimeFormat("de-CH", {
timeZone: "Europe/Zurich",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: false
}).format(new Date(Number(unix) * 1000));
} catch (e) {
base = "";
}
}
return base ? base + " Europe/Zurich" : "";
}
function set(id, v) {
var el = document.getElementById(id);
if (el) el.textContent = v == null || v === "" ? "—" : String(v);
}
function showFallback(msg) {
var box = document.getElementById("stats");
var foot = document.getElementById("st-foot");
if (box) box.hidden = false;
if (foot) {
foot.hidden = false;
foot.className = "stats-foot err";
foot.innerHTML =
(msg || "Stats offline") +
' · <a href="' + BANK_INTRO + '">bank.hacktivism.ch</a>';
}
}
function loadStats() {
var box = document.getElementById("stats");
var foot = document.getElementById("st-foot");
if (!box) return;
box.hidden = false;
// Same-origin first (bank landing), else public bank URL
var urls = [];
if (location.hostname.indexOf("bank.hacktivism") !== -1) {
urls.push("stats.json");
}
urls.push(STATS_URL);
function tryNext(i) {
if (i >= urls.length) {
showFallback("No stats");
return;
}
fetch(urls[i], { cache: "no-store", mode: "cors" })
.then(function (r) {
if (!r.ok) throw new Error("HTTP " + r.status);
return r.json();
})
.then(function (d) {
if (!d || !d.ok) throw new Error("bad stats");
var w = d.withdraws || {};
var h24 = w.last_24h || {};
var h7 = w.last_7d || {};
var ba = d.bank_accounts || {};
var wl = d.wallets || {};
var flow = d.flow || {};
var fin = flow.incoming || {};
var fwd = flow.withdraw || {};
set("st-accounts", ba.total != null ? ba.total : "—");
set("st-wallets", wl.unique_reserves != null ? wl.unique_reserves : "—");
set("st-incoming", fin.amount || flow.total_in || "—");
set("st-withdraw", fwd.amount || w.total_amount || "—");
set("st-24h", h24.amount || "GOA:0");
set("st-7d", h7.amount || "GOA:0");
var list = document.getElementById("st-recent");
if (list) {
list.innerHTML = "";
var rows = (d.recent_withdraws || []).slice(0, 3);
if (!rows.length) {
var empty = document.createElement("li");
empty.className = "meta";
empty.textContent = "—";
list.appendChild(empty);
} else {
rows.forEach(function (row) {
var li = document.createElement("li");
var amt = document.createElement("span");
amt.className = "amt";
amt.textContent = row.amount || "?";
var meta = document.createElement("span");
meta.className = "meta";
meta.textContent = fmtCest(row.at_unix, row.at || row.at_iso) || "";
li.appendChild(amt);
li.appendChild(meta);
list.appendChild(li);
});
}
}
if (foot) {
foot.hidden = false;
foot.className = "stats-foot";
foot.innerHTML =
'Source: <a href="' + BANK_INTRO + '">bank.hacktivism.ch</a>' +
(d.generated_at_human ? " · " + d.generated_at_human : "");
}
})
.catch(function () {
tryNext(i + 1);
});
}
tryNext(0);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", loadStats);
} else {
loadStats();
}
})();