// @ts-check import crel from "../common/crel.js"; import formatBytes from "../common/formatBytes.js"; import parsePng from "./parsePng.js"; import parseHash from "./parseHash.js"; import getNodeUi from "./getNodeUi.js"; /** @typedef {import("./nodePath.js").NodePath} NodePath */ /** @typedef {import("../../types/png.d.ts").PngNode} PngNode */ const errorEl = document.getElementById("error"); const explorerEl = document.getElementById("explorer"); if (!errorEl || !explorerEl) throw new Error("HTML is not set up correctly"); class Explorer { #bytesEl = crel("div", { class: "bytes" }); #treeEl = crel("div", { class: "tree" }); /** * @param {PngNode} rootNode */ constructor(rootNode) { /** * @param {PngNode} node * @param {NodePath} path * @returns [HTMLElement, HTMLElement] Each node's bytes and tree elements. */ const traverse = (node, path) => { const nodeBytesEl = crel("span", { "data-path": path }); const isRoot = path.length === 0; const { title, description } = getNodeUi(node); const nodeTreeEl = crel( "details", { "data-path": path, ...(isRoot ? { open: "open" } : {}) }, crel( "summary", {}, crel("span", { "class": "title" }, title), crel( "span", { "class": "bytecount" }, "TODO: X bytes", ), ), description, ); if (node.children) { const treeChildrenEl = crel("div", { class: "children" }); node.children.forEach((child, index) => { const [childBytesEl, childTreeEl] = traverse( child, path.concat(index), ); if (index > 0) nodeBytesEl.append(" "); nodeBytesEl.append(childBytesEl); treeChildrenEl.append(childTreeEl); }); nodeTreeEl.append(treeChildrenEl); } else { nodeBytesEl.innerHTML = formatBytes(node.bytes, 256); } return [nodeBytesEl, nodeTreeEl]; }; // TODO: better variable names const [a, b] = traverse(rootNode, []); this.#bytesEl.append(a); this.#treeEl.append(b); this.el = document.createDocumentFragment(); this.el.append(this.#bytesEl, this.#treeEl); } } const main = () => { // TODO: We may want a better UI here. // TODO: Handle hash changes. const parsedHash = parseHash(location.hash); if (!parsedHash) { location.href = ".."; return; } const { bytes } = parsedHash; const rootNode = parsePng(bytes); if (!rootNode) { // TODO: Is there better UI than this? errorEl.removeAttribute("hidden"); return; } const explorer = new Explorer(rootNode); explorerEl.innerHTML = ""; explorerEl.append(explorer.el); explorerEl.removeAttribute("hidden"); }; main();