shared: goa-stats snippet assets for landings
This commit is contained in:
parent
8bd0ec24a0
commit
ef40149ed2
3 changed files with 255 additions and 0 deletions
39
configs/shared/goa-stats-snippet.html
Normal file
39
configs/shared/goa-stats-snippet.html
Normal 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>
|
||||||
86
configs/shared/goa-stats.css
Normal file
86
configs/shared/goa-stats.css
Normal 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
130
configs/shared/goa-stats.js
Normal 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();
|
||||||
|
}
|
||||||
|
})();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue