website: snap

This commit is contained in:
nym21
2026-05-12 22:32:53 +02:00
parent 445c60a6f1
commit 8fc2e71492
11 changed files with 1050 additions and 128 deletions

View File

@@ -63,6 +63,9 @@
* @typedef {Brk.AddrStats} AddrStats
* @typedef {Brk.TxIn} TxIn
* @typedef {Brk.TxOut} TxOut
* @typedef {Brk.BlockTemplate} BlockTemplate
* @typedef {Brk.MempoolBlock} MempoolBlock
* @typedef {Brk.NextBlockHash} NextBlockHash
* ActivePriceRatioPattern: ratio pattern with price (extended)
* @typedef {Brk.BpsPriceRatioPattern} ActivePriceRatioPattern
* PriceRatioPercentilesPattern: price pattern with ratio + percentiles (no SMAs/stdDev)

View File

@@ -1,6 +1,7 @@
import { brk } from "../utils/client.js";
import { onPlainClick } from "../utils/dom.js";
import { createCube } from "./cube.js";
import { initMempool, renderMempool } from "./mempool.js";
import { createHeightElement, formatFeeRate } from "./render.js";
const LOOKAHEAD = 15;
@@ -59,6 +60,8 @@ export function initChain(parent, callbacks) {
blocksEl.classList.add("blocks");
scrollEl.append(blocksEl);
initMempool(scrollEl);
olderObserver = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) loadOlder();
@@ -208,7 +211,10 @@ export async function goToCube(hashOrHeight, { silent } = {}) {
}
export async function poll() {
if (newestHeight === -1 || !reachedTip) return;
if (!reachedTip) return;
brk.getMempoolBlocks()
.then(renderMempool)
.catch((e) => console.error("mempool poll:", e));
try {
const blocks = await brk.getBlocksV1();
appendNewerBlocks(blocks);

View File

@@ -6,7 +6,7 @@ import {
poll,
selectCube,
deselectCube,
} from "./chain.js";
} from "../../src/explorer/chain/index.js";
import {
initBlockDetails,
update as updateBlock,

View File

@@ -0,0 +1,89 @@
import { createCube } from "./cube.js";
import { formatFeeRate } from "./render.js";
const NUM_BLOCKS = 8;
/**
* @typedef {{
* el: HTMLElement,
* topFace: HTMLDivElement,
* rightFace: HTMLDivElement,
* leftFace: HTMLDivElement,
* }} Cube
*/
/** @type {HTMLDivElement | null} */ let mempoolBlocksEl = null;
/** @type {Cube[]} */ const cubes = [];
/** @param {HTMLElement} parent the `.chain-scroll` element */
export function initMempool(parent) {
mempoolBlocksEl = document.createElement("div");
mempoolBlocksEl.classList.add("mempool-blocks");
mempoolBlocksEl.hidden = true;
parent.prepend(mempoolBlocksEl);
}
/** @param {MempoolBlock[]} blocks */
export function renderMempool(blocks) {
if (!mempoolBlocksEl) return;
mempoolBlocksEl.hidden = blocks.length === 0;
const want = Math.min(blocks.length, NUM_BLOCKS);
while (cubes.length > want) {
const last = cubes.pop();
if (last) last.el.remove();
}
while (cubes.length < want) {
const cube = createMempoolCube(cubes.length);
cubes.push(cube);
mempoolBlocksEl.append(cube.el);
}
for (let i = 0; i < want; i++) updateMempoolCube(cubes[i], blocks[i], i);
}
/** @param {number} position @returns {Cube} */
function createMempoolCube(position) {
const el = document.createElement("div");
el.classList.add("cube", "projected");
if (position === 0) el.classList.add("next");
const { topFace, rightFace, leftFace } = createCube(el, 0);
return { el, topFace, rightFace, leftFace };
}
/**
* @param {Cube} cube
* @param {MempoolBlock} block
* @param {number} position
*/
function updateMempoolCube(cube, block, position) {
const fill = Math.min(1, block.blockVSize / 1_000_000);
cube.el.style.setProperty("--fill", String(fill));
cube.topFace.textContent = "";
const label = document.createElement("p");
label.textContent = position === 0 ? "next" : `+${position}`;
cube.topFace.append(label);
cube.rightFace.textContent = "";
const txs = document.createElement("p");
txs.textContent = block.nTx.toLocaleString();
const txsUnit = document.createElement("p");
txsUnit.classList.add("dim");
txsUnit.textContent = block.nTx === 1 ? "tx" : "txs";
cube.rightFace.append(txs, txsUnit);
cube.leftFace.textContent = "";
const median = document.createElement("p");
const tilde = document.createElement("span");
tilde.classList.add("dim");
tilde.textContent = "~";
median.append(tilde, formatFeeRate(block.medianFee));
const range = document.createElement("p");
const dash = document.createElement("span");
dash.classList.add("dim");
dash.textContent = "-";
range.append(formatFeeRate(block.feeRange[0]), dash, formatFeeRate(block.feeRange[6]));
const unit = document.createElement("p");
unit.classList.add("dim");
unit.textContent = "sat/vB";
cube.leftFace.append(median, range, unit);
}