mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 07:09:59 -07:00
310 lines
7.7 KiB
JavaScript
310 lines
7.7 KiB
JavaScript
/**
|
|
* @import {Options} from './options';
|
|
*/
|
|
|
|
/**
|
|
* @param {Object} args
|
|
* @param {Flexmasonry} args.flexmasonry
|
|
* @param {Signal<Record<LastPath, number> | null>} args.lastValues
|
|
* @param {Options} args.options
|
|
* @param {Accessor<DashboardOption>} args.selected
|
|
* @param {Signals} args.signals
|
|
* @param {Elements} args.elements
|
|
* @param {Utilities} args.utils
|
|
*/
|
|
export function initDashboardElement({
|
|
elements,
|
|
flexmasonry,
|
|
lastValues,
|
|
options,
|
|
selected,
|
|
signals,
|
|
utils,
|
|
}) {
|
|
flexmasonry.destroyAll();
|
|
|
|
const element = elements.dashboard;
|
|
|
|
element.innerHTML = "";
|
|
|
|
/**
|
|
* @param {HTMLElement} parent
|
|
* @param {string} name
|
|
* @param {boolean} [defaultOpen]
|
|
*/
|
|
function createDetails(parent, name, defaultOpen) {
|
|
const details = window.document.createElement("details");
|
|
details.open = defaultOpen || false;
|
|
parent.append(details);
|
|
|
|
const summary = window.document.createElement("summary");
|
|
summary.innerHTML = name;
|
|
details.append(summary);
|
|
|
|
const div = window.document.createElement("div");
|
|
details.append(div);
|
|
|
|
return div;
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} parent
|
|
* @param {string} name
|
|
*/
|
|
function createTable(parent, name) {
|
|
const table = window.document.createElement("table");
|
|
parent.append(table);
|
|
|
|
const tbody = window.document.createElement("tbody");
|
|
table.append(tbody);
|
|
|
|
return tbody;
|
|
}
|
|
|
|
/**
|
|
* @param {Object} args
|
|
* @param {HTMLTableSectionElement} args.tbody
|
|
* @param {string} args.name
|
|
* @param {Unit} [args.unit]
|
|
* @param {string} args.path
|
|
* @param {boolean} [args.formatNumber]
|
|
*/
|
|
function createRow({ tbody, unit, name, path, formatNumber }) {
|
|
path = path.replace("date-to-", "").replace("height-to-", "");
|
|
|
|
const tr = window.document.createElement("tr");
|
|
tbody.append(tr);
|
|
|
|
const tdName = window.document.createElement("td");
|
|
tr.append(tdName);
|
|
|
|
const a = window.document.createElement("a");
|
|
a.href = path;
|
|
a.innerHTML = name;
|
|
tdName.append(a);
|
|
|
|
const tdValue = window.document.createElement("td");
|
|
|
|
const preSmall = window.document.createElement("small");
|
|
tdValue.append(preSmall);
|
|
|
|
const valueSpan = window.document.createElement("span");
|
|
tdValue.append(valueSpan);
|
|
|
|
const postSmall = window.document.createElement("small");
|
|
tdValue.append(postSmall);
|
|
|
|
signals.createEffect(() => {
|
|
const _lastValues = lastValues();
|
|
|
|
if (!_lastValues || !(path in _lastValues)) return;
|
|
|
|
const value = _lastValues[/** @type {LastPath} */ (path)] ?? 0;
|
|
|
|
tdValue.title = `${utils.locale.numberToUSFormat(value ?? 0)}`;
|
|
|
|
const formattedValue =
|
|
formatNumber ?? unit !== "Count"
|
|
? utils.locale.numberToShortUSFormat(value)
|
|
: utils.locale.numberToUSFormat(
|
|
value,
|
|
unit === "Count" ? 0 : undefined,
|
|
);
|
|
|
|
if (unit === "Date") {
|
|
valueSpan.innerHTML = String(value);
|
|
postSmall.innerHTML = ` UTC`;
|
|
return;
|
|
}
|
|
|
|
valueSpan.innerHTML = formattedValue;
|
|
|
|
switch (unit) {
|
|
case "US Dollars": {
|
|
preSmall.innerHTML = `$`;
|
|
break;
|
|
}
|
|
case "Bitcoin": {
|
|
preSmall.innerHTML = `₿`;
|
|
break;
|
|
}
|
|
case "Percentage": {
|
|
postSmall.innerHTML = `%`;
|
|
break;
|
|
}
|
|
case "Seconds": {
|
|
postSmall.innerHTML = ` sec`;
|
|
break;
|
|
}
|
|
case "Megabytes": {
|
|
postSmall.innerHTML = ` MB`;
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
tr.append(tdValue);
|
|
}
|
|
|
|
// selected().groups.forEach(({ name, values, unit: groupUnit }) => {
|
|
// const tbody = createTable(name);
|
|
|
|
// values.forEach(({ name, path, unit: valueUnit, formatNumber }) => {
|
|
// const unit = groupUnit ?? valueUnit;
|
|
|
|
// createRow({
|
|
// name,
|
|
// tbody,
|
|
// path,
|
|
// unit,
|
|
// formatNumber,
|
|
// });
|
|
// });
|
|
// });
|
|
//
|
|
/** @type {HTMLTableSectionElement | null} */
|
|
let currentTbody = null;
|
|
|
|
const separator = " · ";
|
|
/**
|
|
* @param {Object} args
|
|
* @param {OptionsTree} args.tree
|
|
* @param {{group: OptionsGroup; element: HTMLElement} | null} args.parent
|
|
* @param {string[]} [args.namePre]
|
|
*/
|
|
function recursiveOptionConverter({ tree, parent, namePre }) {
|
|
tree.forEach((anyOption) => {
|
|
if ("tree" in anyOption) {
|
|
currentTbody = null;
|
|
|
|
const group = anyOption;
|
|
|
|
if (!group.tree.length || group.dashboard?.skip) return;
|
|
|
|
if (!parent || group.dashboard?.separate) {
|
|
recursiveOptionConverter({
|
|
tree: group.tree,
|
|
parent: {
|
|
group,
|
|
element: createDetails(
|
|
element,
|
|
group.name,
|
|
group.dashboard?.defaultOpen,
|
|
),
|
|
},
|
|
namePre,
|
|
});
|
|
} else {
|
|
const pre = group.dashboard?.flatten
|
|
? [...(namePre || []), group.name]
|
|
: [];
|
|
|
|
let element = parent.element;
|
|
|
|
if (!group.dashboard?.flatten) {
|
|
element = createDetails(
|
|
parent.element,
|
|
group.name,
|
|
group.dashboard?.defaultOpen,
|
|
);
|
|
}
|
|
|
|
recursiveOptionConverter({
|
|
tree: group.tree,
|
|
parent: {
|
|
group,
|
|
element,
|
|
},
|
|
namePre: pre,
|
|
});
|
|
}
|
|
} else if (anyOption.kind === "chart" && parent) {
|
|
currentTbody ||= createTable(
|
|
parent.element,
|
|
(namePre || []).join(separator),
|
|
);
|
|
|
|
if (!currentTbody) throw "Shouldn't be possible";
|
|
|
|
const tbody = currentTbody;
|
|
|
|
const option = anyOption;
|
|
|
|
if (option.dashboard?.skip) return;
|
|
|
|
const { top, bottom } = option;
|
|
|
|
const topLength = top?.length ?? 0;
|
|
const bottomLength = bottom?.length ?? 0;
|
|
|
|
/**
|
|
* @param {SeriesBlueprint[]} array
|
|
*/
|
|
function createRowFromBlueprint(array) {
|
|
const searchArray = array.filter(
|
|
(blueprint) =>
|
|
blueprint.options?.lastValueVisible !== false &&
|
|
/** @type {LineStyleOptions | undefined} */ (blueprint.options)
|
|
?.lineStyle === undefined,
|
|
);
|
|
|
|
const blueprint =
|
|
searchArray.length === 1
|
|
? searchArray[0]
|
|
: searchArray.find((blueprint) => blueprint.main);
|
|
|
|
if (!blueprint) return;
|
|
|
|
let name = namePre?.join(separator) || "";
|
|
if (!option.dashboard?.ignoreName) {
|
|
if (name) {
|
|
name += separator;
|
|
}
|
|
name += option.name;
|
|
}
|
|
|
|
createRow({
|
|
name,
|
|
tbody,
|
|
path: blueprint.datasetPath,
|
|
unit: option.unit,
|
|
formatNumber: blueprint.formatNumber,
|
|
});
|
|
}
|
|
|
|
if (!topLength && !bottomLength) {
|
|
createRow({
|
|
name: option.name,
|
|
tbody,
|
|
path: "close",
|
|
unit: option.unit,
|
|
formatNumber: false,
|
|
});
|
|
} else if (top && bottomLength === 0) {
|
|
createRowFromBlueprint(top);
|
|
} else if (bottom) {
|
|
createRowFromBlueprint(bottom);
|
|
}
|
|
} else if (parent && "unit" in anyOption) {
|
|
createRow({
|
|
name: anyOption.name,
|
|
tbody: currentTbody,
|
|
path: anyOption.path,
|
|
unit: anyOption.unit,
|
|
formatNumber: false,
|
|
});
|
|
}
|
|
});
|
|
currentTbody = null;
|
|
}
|
|
|
|
recursiveOptionConverter({
|
|
tree: /** @type {OptionsGroup} */ (
|
|
/** @type {OptionsGroup} */ (options.tree[1]).tree[0]
|
|
).tree,
|
|
parent: null,
|
|
});
|
|
|
|
flexmasonry.init([element]);
|
|
}
|