Files
brk/website_next/explore/block/receipt.js
T
2026-07-06 11:15:39 +02:00

140 lines
3.9 KiB
JavaScript

import { createBrand } from "../../brand/index.js";
import { openDialog } from "../../dialog/index.js";
import { getCoinbaseMessage } from "./format.js";
import { createBlockUrl, getReceiptSections } from "./receipt/data.js";
import { createReceiptQr } from "./receipt/qr.js";
import { createBlockTitle } from "./title.js";
/** @typedef {import("../../modules/brk-client/index.js").BlockInfoV1} Block */
/** @typedef {import("./receipt/data.js").ReceiptRow} ReceiptRow */
/** @typedef {import("./receipt/data.js").ReceiptSection} ReceiptSection */
/** @param {ReceiptRow} data */
function createReceiptRow(data) {
const row = document.createElement("div");
const name = document.createElement("span");
const amount = document.createElement("strong");
row.dataset.receiptRow = data.variant ?? (data.detail ? "amount" : "");
name.textContent = data.label;
amount.textContent = data.value;
if (data.detail) {
const detail = document.createElement("small");
detail.textContent = data.detail;
amount.append(detail);
}
row.append(name, amount);
return row;
}
/** @param {ReceiptSection} data */
function createReceiptSection(data) {
const section = document.createElement("section");
const heading = document.createElement("h3");
section.dataset.receiptSection = "";
heading.textContent = data.title;
section.append(heading, ...data.rows.map(createReceiptRow));
return section;
}
/** @param {string} message */
function createCoinbaseNote(message) {
const note = document.createElement("p");
note.dataset.receiptNote = "";
note.textContent = message;
return note;
}
/** @param {Block} block */
function createReceiptHead(block) {
const head = document.createElement("header");
const title = document.createElement("h2");
head.dataset.receiptHead = "";
title.append(...createBlockTitle(block.height));
head.append(title);
return head;
}
function createReceiptBrand() {
const section = document.createElement("section");
section.dataset.receiptBrand = "";
section.append(createBrand({ tone: "receipt", fill: 1 }));
return section;
}
/** @param {Block} block */
function openReceiptDialog(block) {
const dialog = document.createElement("dialog");
const paper = document.createElement("article");
const controls = document.createElement("footer");
const print = document.createElement("button");
const closeForm = document.createElement("form");
const close = document.createElement("button");
const url = createBlockUrl(block);
const coinbase = getCoinbaseMessage(block.extras.coinbaseSignatureAscii);
dialog.dataset.blockReceipt = "";
dialog.tabIndex = -1;
paper.dataset.receiptPaper = "";
controls.dataset.receiptControls = "";
print.type = "button";
print.dataset.receiptAction = "print";
print.textContent = "Print";
closeForm.method = "dialog";
close.type = "submit";
close.dataset.receiptAction = "close";
close.textContent = "Close";
closeForm.append(close);
controls.append(closeForm, print);
paper.append(
createReceiptHead(block),
...getReceiptSections(block).map(createReceiptSection),
...(coinbase ? [createCoinbaseNote(coinbase)] : []),
createReceiptQr(block, url),
createReceiptBrand(),
);
dialog.append(paper, controls);
print.addEventListener("click", () => {
window.print();
});
openDialog(dialog, document.body);
dialog.focus({ preventScroll: true });
dialog.scrollTop = 0;
}
export function createBlockReceipt() {
const button = document.createElement("button");
/** @type {Block | null} */
let block = null;
button.type = "button";
button.disabled = true;
button.dataset.receiptButton = "";
button.textContent = "Receipt";
button.addEventListener("click", () => {
if (block) openReceiptDialog(block);
});
/** @param {Block} nextBlock */
function update(nextBlock) {
block = nextBlock;
button.disabled = false;
}
return /** @type {const} */ ({
button,
update,
});
}