mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
bitview: reorg part 1
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
"**/modern-screenshot/*/index.mjs",
|
||||
"**/solidjs-signals/*/dist/prod.js",
|
||||
"uFuzzy.mjs",
|
||||
"lightweight-charts.standalone.production.mjs",
|
||||
"lightweight-charts.standalone.production.mjs"
|
||||
// "scripts/packages",
|
||||
"dist"
|
||||
// "dist"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -90,4 +90,3 @@ ci = "github"
|
||||
allow-dirty = ["ci"]
|
||||
installers = []
|
||||
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]
|
||||
rust-toolchain-version = "1.89"
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::path::Path;
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::Parser;
|
||||
use brk_structs::{BlkPosition, Height, StoredU32, TxIndex, Version};
|
||||
use brk_structs::{BlkPosition, Height, TxIndex, Version};
|
||||
use vecdb::{
|
||||
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, CompressedVec, Database, Exit,
|
||||
GenericStoredVec, PAGE_SIZE, VecIterator,
|
||||
@@ -16,9 +16,7 @@ pub struct Vecs {
|
||||
db: Database,
|
||||
|
||||
pub height_to_position: CompressedVec<Height, BlkPosition>,
|
||||
pub height_to_len: CompressedVec<Height, StoredU32>,
|
||||
pub txindex_to_position: CompressedVec<TxIndex, BlkPosition>,
|
||||
pub txindex_to_len: CompressedVec<TxIndex, StoredU32>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -34,13 +32,11 @@ impl Vecs {
|
||||
"position",
|
||||
version + Version::TWO,
|
||||
)?,
|
||||
height_to_len: CompressedVec::forced_import(&db, "len", version + Version::TWO)?,
|
||||
txindex_to_position: CompressedVec::forced_import(
|
||||
&db,
|
||||
"position",
|
||||
version + Version::TWO,
|
||||
)?,
|
||||
txindex_to_len: CompressedVec::forced_import(&db, "len", version + Version::TWO)?,
|
||||
|
||||
db,
|
||||
};
|
||||
@@ -104,9 +100,6 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.height_to_len
|
||||
.forced_push_at(height, block.metadata().len().into(), exit)?;
|
||||
|
||||
let txindex = height_to_first_txindex_iter.unwrap_get_inner(height);
|
||||
|
||||
block.tx_metadata().iter().enumerate().try_for_each(
|
||||
@@ -117,8 +110,6 @@ impl Vecs {
|
||||
metadata.position(),
|
||||
exit,
|
||||
)?;
|
||||
self.txindex_to_len
|
||||
.forced_push_at(txindex, metadata.len().into(), exit)?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
@@ -126,18 +117,14 @@ impl Vecs {
|
||||
if *height % 1_000 == 0 {
|
||||
let _lock = exit.lock();
|
||||
self.height_to_position.flush()?;
|
||||
self.height_to_len.flush()?;
|
||||
self.txindex_to_position.flush()?;
|
||||
self.txindex_to_len.flush()?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.height_to_position.flush()?;
|
||||
self.height_to_len.flush()?;
|
||||
self.txindex_to_position.flush()?;
|
||||
self.txindex_to_len.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -146,9 +133,7 @@ impl Vecs {
|
||||
Box::new(
|
||||
[
|
||||
&self.height_to_position as &dyn AnyCollectableVec,
|
||||
&self.height_to_len,
|
||||
&self.txindex_to_position,
|
||||
&self.txindex_to_len,
|
||||
]
|
||||
.into_iter(),
|
||||
)
|
||||
|
||||
@@ -12,7 +12,6 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use bitcoin::{Address, Network, Transaction, consensus::Decodable};
|
||||
use bitcoincore_rpc::bitcoin;
|
||||
use brk_interface::{IdParam, Index, PaginatedIndexParam, PaginationParam, Params, ParamsOpt};
|
||||
use brk_parser::XORIndex;
|
||||
use brk_structs::{
|
||||
@@ -182,7 +181,7 @@ impl ApiRoutes for Router<AppState> {
|
||||
let computer = interface.computer();
|
||||
|
||||
let position = computer.blks.txindex_to_position.iter().unwrap_get_inner(txindex);
|
||||
let len = computer.blks.txindex_to_len.iter().unwrap_get_inner(txindex);
|
||||
let len = indexer.vecs.txindex_to_total_size.iter().unwrap_get_inner(txindex);
|
||||
|
||||
let blk_index_to_blk_path = parser.blk_index_to_blk_path();
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "1.89.0"
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-check
|
||||
|
||||
/** @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData } from './packages/lightweight-charts/5.0.8/dist/typings' */
|
||||
/** @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData } from '../packages/lightweight-charts/5.0.8/dist/typings' */
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, number, number]} OHLCTuple
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
LineSeries,
|
||||
BaselineSeries,
|
||||
// } from "./5.0.8/dist/lightweight-charts.standalone.development.mjs";
|
||||
} from "./packages/lightweight-charts/5.0.8/dist/lightweight-charts.standalone.production.mjs";
|
||||
} from "../packages/lightweight-charts/5.0.8/dist/lightweight-charts.standalone.production.mjs";
|
||||
|
||||
const oklchToRGBA = createOklchToRGBA();
|
||||
|
||||
120
websites/bitview/scripts/core/colors.js
Normal file
120
websites/bitview/scripts/core/colors.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @import { Accessor } from "../packages/solidjs-signals/wrapper";
|
||||
*/
|
||||
|
||||
const globalComputedStyle = getComputedStyle(window.document.documentElement);
|
||||
|
||||
/**
|
||||
* @param {Accessor<boolean>} dark
|
||||
*/
|
||||
export function createColors(dark) {
|
||||
/**
|
||||
* @param {string} color
|
||||
*/
|
||||
function getColor(color) {
|
||||
return globalComputedStyle.getPropertyValue(`--${color}`);
|
||||
}
|
||||
function red() {
|
||||
return getColor("red");
|
||||
}
|
||||
function orange() {
|
||||
return getColor("orange");
|
||||
}
|
||||
function amber() {
|
||||
return getColor("amber");
|
||||
}
|
||||
function yellow() {
|
||||
return getColor("yellow");
|
||||
}
|
||||
function avocado() {
|
||||
return getColor("avocado");
|
||||
}
|
||||
function lime() {
|
||||
return getColor("lime");
|
||||
}
|
||||
function green() {
|
||||
return getColor("green");
|
||||
}
|
||||
function emerald() {
|
||||
return getColor("emerald");
|
||||
}
|
||||
function teal() {
|
||||
return getColor("teal");
|
||||
}
|
||||
function cyan() {
|
||||
return getColor("cyan");
|
||||
}
|
||||
function sky() {
|
||||
return getColor("sky");
|
||||
}
|
||||
function blue() {
|
||||
return getColor("blue");
|
||||
}
|
||||
function indigo() {
|
||||
return getColor("indigo");
|
||||
}
|
||||
function violet() {
|
||||
return getColor("violet");
|
||||
}
|
||||
function purple() {
|
||||
return getColor("purple");
|
||||
}
|
||||
function fuchsia() {
|
||||
return getColor("fuchsia");
|
||||
}
|
||||
function pink() {
|
||||
return getColor("pink");
|
||||
}
|
||||
function rose() {
|
||||
return getColor("rose");
|
||||
}
|
||||
function gray() {
|
||||
return getColor("gray");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} property
|
||||
*/
|
||||
function getLightDarkValue(property) {
|
||||
const value = globalComputedStyle.getPropertyValue(property);
|
||||
const [light, _dark] = value.slice(11, -1).split(", ");
|
||||
return dark() ? _dark : light;
|
||||
}
|
||||
|
||||
function textColor() {
|
||||
return getLightDarkValue("--color");
|
||||
}
|
||||
function borderColor() {
|
||||
return getLightDarkValue("--border-color");
|
||||
}
|
||||
|
||||
return {
|
||||
default: textColor,
|
||||
gray,
|
||||
border: borderColor,
|
||||
|
||||
red,
|
||||
orange,
|
||||
amber,
|
||||
yellow,
|
||||
avocado,
|
||||
lime,
|
||||
green,
|
||||
emerald,
|
||||
teal,
|
||||
cyan,
|
||||
sky,
|
||||
blue,
|
||||
indigo,
|
||||
violet,
|
||||
purple,
|
||||
fuchsia,
|
||||
pink,
|
||||
rose,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @typedef {ReturnType<typeof createColors>} Colors
|
||||
* @typedef {Colors["orange"]} Color
|
||||
* @typedef {keyof Colors} ColorName
|
||||
*/
|
||||
0
websites/bitview/scripts/core/dom.js
Normal file
0
websites/bitview/scripts/core/dom.js
Normal file
28
websites/bitview/scripts/core/elements.js
Normal file
28
websites/bitview/scripts/core/elements.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @param {string} id
|
||||
*/
|
||||
function getElementById(id) {
|
||||
const element = window.document.getElementById(id);
|
||||
if (!element) throw `Element with id = "${id}" should exist`;
|
||||
return element;
|
||||
}
|
||||
|
||||
export default {
|
||||
head: window.document.getElementsByTagName("head")[0],
|
||||
body: window.document.body,
|
||||
main: getElementById("main"),
|
||||
aside: getElementById("aside"),
|
||||
asideLabel: getElementById("aside-selector-label"),
|
||||
navLabel: getElementById(`nav-selector-label`),
|
||||
searchLabel: getElementById(`search-selector-label`),
|
||||
search: getElementById("search"),
|
||||
nav: getElementById("nav"),
|
||||
searchInput: /** @type {HTMLInputElement} */ (getElementById("search-input")),
|
||||
searchResults: getElementById("search-results"),
|
||||
selectors: getElementById("frame-selectors"),
|
||||
style: getComputedStyle(window.document.documentElement),
|
||||
charts: getElementById("charts"),
|
||||
table: getElementById("table"),
|
||||
explorer: getElementById("explorer"),
|
||||
simulation: getElementById("simulation"),
|
||||
};
|
||||
24
websites/bitview/scripts/core/env.js
Normal file
24
websites/bitview/scripts/core/env.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const localhost = window.location.hostname === "localhost";
|
||||
const standalone =
|
||||
"standalone" in window.navigator && !!window.navigator.standalone;
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
const isChrome = userAgent.includes("chrome");
|
||||
const safari = userAgent.includes("safari");
|
||||
const safariOnly = safari && !isChrome;
|
||||
const macOS = userAgent.includes("mac os");
|
||||
const iphone = userAgent.includes("iphone");
|
||||
const ipad = userAgent.includes("ipad");
|
||||
const ios = iphone || ipad;
|
||||
|
||||
export default {
|
||||
standalone,
|
||||
userAgent,
|
||||
isChrome,
|
||||
safari,
|
||||
safariOnly,
|
||||
macOS,
|
||||
iphone,
|
||||
ipad,
|
||||
ios,
|
||||
localhost,
|
||||
};
|
||||
371
websites/bitview/scripts/core/options/full.js
Normal file
371
websites/bitview/scripts/core/options/full.js
Normal file
@@ -0,0 +1,371 @@
|
||||
import { createPartialOptions } from "./partial";
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Colors} args.colors
|
||||
* @param {Signals} args.signals
|
||||
* @param {Env} args.env
|
||||
* @param {Utilities} args.utils
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
* @param {Pools} args.pools
|
||||
* @param {Signal<string | null>} args.qrcode
|
||||
*/
|
||||
export function initOptions({
|
||||
colors,
|
||||
signals,
|
||||
env,
|
||||
utils,
|
||||
qrcode,
|
||||
vecIdToIndexes,
|
||||
pools,
|
||||
}) {
|
||||
const LS_SELECTED_KEY = `selected_path`;
|
||||
|
||||
const urlPath_ = window.document.location.pathname
|
||||
.split("/")
|
||||
.filter((v) => v);
|
||||
const urlPath = urlPath_.length ? urlPath_ : undefined;
|
||||
const savedPath = /** @type {string[]} */ (
|
||||
JSON.parse(utils.storage.read(LS_SELECTED_KEY) || "[]") || []
|
||||
).filter((v) => v);
|
||||
console.log(savedPath);
|
||||
|
||||
/** @type {Signal<Option>} */
|
||||
const selected = signals.createSignal(/** @type {any} */ (undefined));
|
||||
|
||||
const partialOptions = createPartialOptions({
|
||||
env,
|
||||
colors,
|
||||
vecIdToIndexes,
|
||||
pools,
|
||||
});
|
||||
|
||||
/** @type {Option[]} */
|
||||
const list = [];
|
||||
|
||||
const parent = signals.createSignal(/** @type {HTMLElement | null} */ (null));
|
||||
|
||||
/**
|
||||
* @param {AnyFetchedSeriesBlueprint[]} [arr]
|
||||
*/
|
||||
function arrayToRecord(arr = []) {
|
||||
return (arr || []).reduce((record, blueprint) => {
|
||||
if (env.localhost && !(blueprint.key in vecIdToIndexes)) {
|
||||
throw Error(`${blueprint.key} not recognized`);
|
||||
}
|
||||
const unit = blueprint.unit ?? utils.vecidToUnit(blueprint.key);
|
||||
record[unit] ??= [];
|
||||
record[unit].push(blueprint);
|
||||
return record;
|
||||
}, /** @type {Record<Unit, AnyFetchedSeriesBlueprint[]>} */ ({}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Option} option
|
||||
*/
|
||||
function selectOption(option) {
|
||||
utils.url.pushHistory(option.path);
|
||||
utils.url.resetParams(option);
|
||||
utils.storage.write(LS_SELECTED_KEY, JSON.stringify(option.path));
|
||||
selected.set(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Option} args.option
|
||||
* @param {string} args.frame
|
||||
* @param {Signal<string | null>} args.qrcode
|
||||
* @param {string} [args.name]
|
||||
*/
|
||||
function createOptionElement({ option, frame, name, qrcode }) {
|
||||
const title = option.title;
|
||||
if (option.kind === "url") {
|
||||
const href = option.url();
|
||||
|
||||
if (option.qrcode) {
|
||||
return utils.dom.createButtonElement({
|
||||
inside: option.name,
|
||||
title,
|
||||
onClick: () => {
|
||||
qrcode.set(option.url);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return utils.dom.createAnchorElement({
|
||||
href,
|
||||
blank: true,
|
||||
text: option.name,
|
||||
title,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return utils.dom.createAnchorElement({
|
||||
href: `/${option.path.join("/")}`,
|
||||
title,
|
||||
text: name || option.name,
|
||||
onClick: () => {
|
||||
selectOption(option);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Option | undefined} */
|
||||
let savedOption;
|
||||
|
||||
/**
|
||||
* @param {PartialOptionsTree} partialTree
|
||||
* @param {Accessor<HTMLElement | null>} parent
|
||||
* @param {string[] | undefined} parentPath
|
||||
* @returns {Accessor<number>}
|
||||
*/
|
||||
function recursiveProcessPartialTree(
|
||||
partialTree,
|
||||
parent,
|
||||
parentPath = [],
|
||||
depth = 0,
|
||||
) {
|
||||
/** @type {Accessor<number>[]} */
|
||||
const listForSum = [];
|
||||
|
||||
const ul = signals.createMemo(
|
||||
// @ts_ignore
|
||||
(_previous) => {
|
||||
const previous = /** @type {HTMLUListElement | null} */ (_previous);
|
||||
previous?.remove();
|
||||
|
||||
const _parent = parent();
|
||||
if (_parent) {
|
||||
if ("open" in _parent && !_parent.open) {
|
||||
throw "Set accesor to null instead";
|
||||
}
|
||||
|
||||
const ul = window.document.createElement("ul");
|
||||
_parent.append(ul);
|
||||
return ul;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
null,
|
||||
);
|
||||
|
||||
partialTree.forEach((anyPartial, partialIndex) => {
|
||||
const renderLi = signals.createSignal(true);
|
||||
|
||||
const li = signals.createMemo((_previous) => {
|
||||
const previous = _previous;
|
||||
previous?.remove();
|
||||
|
||||
const _ul = ul();
|
||||
|
||||
if (renderLi() && _ul) {
|
||||
const li = window.document.createElement("li");
|
||||
utils.dom.insertElementAtIndex(_ul, li, partialIndex);
|
||||
return li;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, /** @type {HTMLLIElement | null} */ (null));
|
||||
|
||||
if ("tree" in anyPartial) {
|
||||
/** @type {Omit<OptionsGroup, keyof PartialOptionsGroup>} */
|
||||
const groupAddons = {};
|
||||
|
||||
Object.assign(anyPartial, groupAddons);
|
||||
|
||||
const passedDetails = signals.createSignal(
|
||||
/** @type {HTMLDivElement | HTMLDetailsElement | null} */ (null),
|
||||
);
|
||||
|
||||
const serName = utils.stringToId(anyPartial.name);
|
||||
const path = [...parentPath, serName];
|
||||
const childOptionsCount = recursiveProcessPartialTree(
|
||||
anyPartial.tree,
|
||||
passedDetails,
|
||||
path,
|
||||
depth + 1,
|
||||
);
|
||||
|
||||
listForSum.push(childOptionsCount);
|
||||
|
||||
signals.createEffect(li, (li) => {
|
||||
if (!li) {
|
||||
passedDetails.set(null);
|
||||
return;
|
||||
}
|
||||
|
||||
signals.createEffect(selected, (selected) => {
|
||||
if (
|
||||
path.length <= selected.path.length &&
|
||||
path.every((v, i) => selected.path.at(i) === v)
|
||||
) {
|
||||
li.dataset.highlight = "";
|
||||
} else {
|
||||
delete li.dataset.highlight;
|
||||
}
|
||||
});
|
||||
|
||||
const details = window.document.createElement("details");
|
||||
details.dataset.name = serName;
|
||||
li.appendChild(details);
|
||||
|
||||
const summary = window.document.createElement("summary");
|
||||
details.append(summary);
|
||||
summary.append(anyPartial.name);
|
||||
|
||||
const supCount = window.document.createElement("sup");
|
||||
summary.append(supCount);
|
||||
|
||||
signals.createEffect(childOptionsCount, (childOptionsCount) => {
|
||||
supCount.innerHTML = childOptionsCount.toLocaleString("en-us");
|
||||
});
|
||||
|
||||
details.addEventListener("toggle", () => {
|
||||
const open = details.open;
|
||||
|
||||
if (open) {
|
||||
passedDetails.set(details);
|
||||
} else {
|
||||
passedDetails.set(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createRenderLiEffect() {
|
||||
signals.createEffect(childOptionsCount, (count) => {
|
||||
renderLi.set(!!count);
|
||||
});
|
||||
}
|
||||
createRenderLiEffect();
|
||||
} else {
|
||||
const option = /** @type {Option} */ (anyPartial);
|
||||
|
||||
const name = option.name;
|
||||
const path = [...parentPath, utils.stringToId(option.name)];
|
||||
|
||||
if ("kind" in anyPartial && anyPartial.kind === "explorer") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {ExplorerOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: option.title,
|
||||
}),
|
||||
);
|
||||
} else if ("kind" in anyPartial && anyPartial.kind === "table") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {TableOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: option.title,
|
||||
}),
|
||||
);
|
||||
} else if ("kind" in anyPartial && anyPartial.kind === "simulation") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {SimulationOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: anyPartial.title,
|
||||
}),
|
||||
);
|
||||
} else if ("url" in anyPartial) {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {UrlOption} */ ({
|
||||
kind: "url",
|
||||
path,
|
||||
name,
|
||||
title: name,
|
||||
qrcode: !!anyPartial.qrcode,
|
||||
url: anyPartial.url,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
const title = option.title || option.name;
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {ChartOption} */ ({
|
||||
kind: "chart",
|
||||
name,
|
||||
title,
|
||||
path,
|
||||
top: arrayToRecord(anyPartial.top),
|
||||
bottom: arrayToRecord(anyPartial.bottom),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
list.push(option);
|
||||
|
||||
if (urlPath) {
|
||||
const sameAsURLPath =
|
||||
urlPath.length === path.length &&
|
||||
urlPath.every((val, i) => val === path[i]);
|
||||
if (sameAsURLPath) {
|
||||
selected.set(option);
|
||||
}
|
||||
} else if (savedPath) {
|
||||
const sameAsSavedPath =
|
||||
savedPath.length === path.length &&
|
||||
savedPath.every((val, i) => val === path[i]);
|
||||
if (sameAsSavedPath) {
|
||||
savedOption = option;
|
||||
}
|
||||
}
|
||||
|
||||
signals.createEffect(li, (li) => {
|
||||
if (!li) {
|
||||
return;
|
||||
}
|
||||
|
||||
signals.createEffect(selected, (selected) => {
|
||||
if (selected === option) {
|
||||
li.dataset.highlight = "";
|
||||
} else {
|
||||
delete li.dataset.highlight;
|
||||
}
|
||||
});
|
||||
|
||||
const element = createOptionElement({
|
||||
option,
|
||||
frame: "nav",
|
||||
qrcode,
|
||||
});
|
||||
|
||||
li.append(element);
|
||||
});
|
||||
|
||||
listForSum.push(() => 1);
|
||||
}
|
||||
});
|
||||
|
||||
return signals.createMemo(() =>
|
||||
listForSum.reduce((acc, s) => acc + s(), 0),
|
||||
);
|
||||
}
|
||||
recursiveProcessPartialTree(partialOptions, parent);
|
||||
|
||||
if (!selected()) {
|
||||
const option =
|
||||
savedOption || list.find((option) => option.kind === "chart");
|
||||
if (option) {
|
||||
selected.set(option);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
selected,
|
||||
list,
|
||||
tree: /** @type {OptionsTree} */ (partialOptions),
|
||||
parent,
|
||||
createOptionElement,
|
||||
selectOption,
|
||||
};
|
||||
}
|
||||
/** @typedef {ReturnType<typeof initOptions>} Options */
|
||||
@@ -127,7 +127,7 @@
|
||||
* @param {Pools} args.pools
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
export function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/**
|
||||
* @template {string} S
|
||||
* @typedef {Extract<VecId, `${S}${string}`>} StartsWith
|
||||
@@ -720,7 +720,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `UTXOs ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const addressesAboveAmount = aboveAmount.map(
|
||||
@@ -730,7 +730,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `Addresses ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const underAmount = /** @type {const} */ ([
|
||||
@@ -821,7 +821,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `UTXOs ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const addressesUnderAmount = underAmount.map(
|
||||
@@ -831,7 +831,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `Addresses ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const amountRanges = /** @type {const} */ ([
|
||||
@@ -934,7 +934,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `UTXOs ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const addressesAmountRanges = amountRanges.map(
|
||||
@@ -944,7 +944,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
title: `Addresses ${title}`,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const type = /** @type {const} */ ([
|
||||
@@ -1129,7 +1129,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
lastValueVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1426,7 +1426,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
options: {
|
||||
lineStyle: 1,
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
: []),
|
||||
],
|
||||
@@ -1449,7 +1449,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
options: {
|
||||
lineStyle: 1,
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
: []),
|
||||
...(`${key}_ratio_sma` in vecIdToIndexes
|
||||
@@ -1462,7 +1462,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
options: {
|
||||
lineStyle: 1,
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
: []),
|
||||
createPriceLine({
|
||||
@@ -1641,7 +1641,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
options: {
|
||||
lineStyle: 1,
|
||||
},
|
||||
})
|
||||
}),
|
||||
),
|
||||
],
|
||||
bottom: [
|
||||
@@ -2014,11 +2014,11 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
}),
|
||||
},
|
||||
...(list.filter(
|
||||
({ key }) => `${fixKey(key)}addr_count` in vecIdToIndexes
|
||||
({ key }) => `${fixKey(key)}addr_count` in vecIdToIndexes,
|
||||
).length > ("list" in args ? 1 : 0)
|
||||
? !("list" in args) ||
|
||||
list.filter(
|
||||
({ key }) => `${fixKey(key)}empty_addr_count` in vecIdToIndexes
|
||||
({ key }) => `${fixKey(key)}empty_addr_count` in vecIdToIndexes,
|
||||
).length <= 1
|
||||
? [
|
||||
{
|
||||
@@ -2060,7 +2060,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
bottom: list
|
||||
.filter(
|
||||
({ key }) =>
|
||||
`${fixKey(key)}addr_count` in vecIdToIndexes
|
||||
`${fixKey(key)}addr_count` in vecIdToIndexes,
|
||||
)
|
||||
.flatMap(({ name, color, key: _key }) => {
|
||||
const key = fixKey(_key);
|
||||
@@ -2075,7 +2075,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
},
|
||||
...(list.filter(
|
||||
({ key }) =>
|
||||
`${fixKey(key)}empty_addr_count` in vecIdToIndexes
|
||||
`${fixKey(key)}empty_addr_count` in vecIdToIndexes,
|
||||
).length
|
||||
? [
|
||||
{
|
||||
@@ -2085,7 +2085,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
.filter(
|
||||
({ key }) =>
|
||||
`${fixKey(key)}empty_addr_count` in
|
||||
vecIdToIndexes
|
||||
vecIdToIndexes,
|
||||
)
|
||||
.flatMap(({ name, color, key: _key }) => {
|
||||
const key = fixKey(_key);
|
||||
@@ -2117,7 +2117,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key: `${fixKey(key)}realized_price`,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -2129,7 +2129,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key: `${fixKey(key)}realized_price_ratio`,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
createPriceLine({
|
||||
unit: "ratio",
|
||||
@@ -2195,7 +2195,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
? [
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}realized_profit_to_loss_ratio`,
|
||||
name: "proft / loss",
|
||||
color: colors.yellow,
|
||||
@@ -2234,7 +2234,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}realized_profit_rel_to_realized_cap`,
|
||||
title: "Profit",
|
||||
color: colors.green,
|
||||
@@ -2242,7 +2242,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}realized_loss_rel_to_realized_cap`,
|
||||
title: "Loss",
|
||||
color: colors.red,
|
||||
@@ -2274,7 +2274,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta`,
|
||||
title: "cumulative 30d change",
|
||||
defaultActive: false,
|
||||
@@ -2282,14 +2282,14 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_rel_to_realized_cap`,
|
||||
title: "Raw",
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap`,
|
||||
title: "cumulative 30d change",
|
||||
defaultActive: false,
|
||||
@@ -2297,7 +2297,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta_rel_to_market_cap`,
|
||||
title: "cumulative 30d change",
|
||||
}),
|
||||
@@ -2500,7 +2500,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_rel_to_realized_cap`,
|
||||
title: name,
|
||||
color,
|
||||
@@ -2571,7 +2571,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta`,
|
||||
title: name,
|
||||
color,
|
||||
@@ -2579,7 +2579,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap`,
|
||||
title: name,
|
||||
color,
|
||||
@@ -2587,7 +2587,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_realized_pnl_cumulative_30d_delta_rel_to_market_cap`,
|
||||
title: name,
|
||||
color,
|
||||
@@ -2650,7 +2650,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
title: name,
|
||||
color,
|
||||
}),
|
||||
]
|
||||
],
|
||||
),
|
||||
createPriceLine({
|
||||
number: 1,
|
||||
@@ -2730,7 +2730,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
bottom: list.flatMap(({ color, name, key }) => {
|
||||
const normalKey = `${fixKey(key)}value_destroyed`;
|
||||
const adjKey = `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}adjusted_value_destroyed`;
|
||||
return [
|
||||
createBaseSeries({
|
||||
@@ -2785,7 +2785,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
]
|
||||
@@ -2826,7 +2826,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
]
|
||||
@@ -2871,14 +2871,14 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_profit_rel_to_market_cap`,
|
||||
name: "Profit",
|
||||
color: colors.green,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_loss_rel_to_market_cap`,
|
||||
name: "Loss",
|
||||
color: colors.red,
|
||||
@@ -2886,26 +2886,26 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}neg_unrealized_loss_rel_to_market_cap`,
|
||||
name: "Negative Loss",
|
||||
color: colors.red,
|
||||
}),
|
||||
...(`${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_profit_rel_to_own_market_cap` in
|
||||
vecIdToIndexes
|
||||
? [
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_profit_rel_to_own_market_cap`,
|
||||
name: "Profit",
|
||||
color: colors.green,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_loss_rel_to_own_market_cap`,
|
||||
name: "Loss",
|
||||
color: colors.red,
|
||||
@@ -2913,7 +2913,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}neg_unrealized_loss_rel_to_own_market_cap`,
|
||||
name: "Negative Loss",
|
||||
color: colors.red,
|
||||
@@ -2928,20 +2928,20 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
]
|
||||
: []),
|
||||
...(`${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_profit_rel_to_own_total_unrealized_pnl` in
|
||||
vecIdToIndexes
|
||||
? [
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_profit_rel_to_own_total_unrealized_pnl`,
|
||||
name: "Profit",
|
||||
color: colors.green,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}unrealized_loss_rel_to_own_total_unrealized_pnl`,
|
||||
name: "Loss",
|
||||
color: colors.red,
|
||||
@@ -2949,7 +2949,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
args.key,
|
||||
)}neg_unrealized_loss_rel_to_own_total_unrealized_pnl`,
|
||||
name: "Negative Loss",
|
||||
color: colors.red,
|
||||
@@ -3036,13 +3036,13 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
color: useGroupName ? color : undefined,
|
||||
}),
|
||||
...(`${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_unrealized_pnl_rel_to_own_market_cap` in vecIdToIndexes
|
||||
? [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_unrealized_pnl_rel_to_own_market_cap`,
|
||||
title: useGroupName ? name : "Net",
|
||||
color: useGroupName ? color : undefined,
|
||||
@@ -3053,14 +3053,14 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
]
|
||||
: []),
|
||||
...(`${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_unrealized_pnl_rel_to_own_total_unrealized_pnl` in
|
||||
vecIdToIndexes
|
||||
? [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
key,
|
||||
)}net_unrealized_pnl_rel_to_own_total_unrealized_pnl`,
|
||||
title: useGroupName ? name : "Net",
|
||||
color: useGroupName ? color : undefined,
|
||||
@@ -3277,7 +3277,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key: `price_${key}_${keyAddon}`,
|
||||
name: key,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
...averages.map(({ key, name, color }) => ({
|
||||
@@ -3494,7 +3494,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
unit: "percentage",
|
||||
}),
|
||||
],
|
||||
})
|
||||
}),
|
||||
),
|
||||
.../** @type {const} */ ([
|
||||
{ name: "2 Year", key: "2y" },
|
||||
@@ -3551,7 +3551,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
unit: "percentage",
|
||||
}),
|
||||
],
|
||||
})
|
||||
}),
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -3567,7 +3567,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name: `${year}`,
|
||||
color,
|
||||
defaultActive,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
...dcaClasses.map(
|
||||
@@ -3592,7 +3592,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
unit: "percentage",
|
||||
}),
|
||||
],
|
||||
})
|
||||
}),
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -3681,13 +3681,13 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
// name: "Weight",
|
||||
// }),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"block_size"
|
||||
"block_size",
|
||||
),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"block_weight"
|
||||
"block_weight",
|
||||
),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"block_vbytes"
|
||||
"block_vbytes",
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -3703,7 +3703,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
{
|
||||
key: "tx_count",
|
||||
name: "Count",
|
||||
}
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -3771,7 +3771,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
common: `v${index + 1}`,
|
||||
sumColor,
|
||||
cumulativeColor,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -3905,19 +3905,19 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
{
|
||||
key: "coinbase",
|
||||
name: "Coinbase",
|
||||
}
|
||||
},
|
||||
),
|
||||
...createBaseAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
{
|
||||
key: "coinbase_btc",
|
||||
name: "Coinbase",
|
||||
}
|
||||
},
|
||||
),
|
||||
...createBaseAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
{
|
||||
key: "coinbase_usd",
|
||||
name: "Coinbase",
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -3929,7 +3929,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
{
|
||||
key: "subsidy",
|
||||
name: "Subsidy",
|
||||
}
|
||||
},
|
||||
),
|
||||
createBaseSeries({
|
||||
key: "subsidy_usd_1y_sma",
|
||||
@@ -3939,13 +3939,13 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
{
|
||||
key: "subsidy_btc",
|
||||
name: "Subsidy",
|
||||
}
|
||||
},
|
||||
),
|
||||
...createBaseAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
{
|
||||
key: "subsidy_usd",
|
||||
name: "Subsidy",
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -3954,13 +3954,13 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
title: "Transaction Fee",
|
||||
bottom: [
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"fee"
|
||||
"fee",
|
||||
),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"fee_btc"
|
||||
"fee_btc",
|
||||
),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"fee_usd"
|
||||
"fee_usd",
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -4312,7 +4312,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
sumColor,
|
||||
cumulativeColor,
|
||||
}),
|
||||
]
|
||||
],
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -4550,7 +4550,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
...cointimePrices.map(({ key, name, color, title }) => ({
|
||||
@@ -4587,7 +4587,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
key,
|
||||
name,
|
||||
color,
|
||||
})
|
||||
}),
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -4612,7 +4612,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
color: colors.orange,
|
||||
}),
|
||||
],
|
||||
})
|
||||
}),
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -4653,7 +4653,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
])
|
||||
]),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -4868,373 +4868,3 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) {
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Colors} args.colors
|
||||
* @param {Signals} args.signals
|
||||
* @param {Env} args.env
|
||||
* @param {Utilities} args.utils
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
* @param {Pools} args.pools
|
||||
* @param {Signal<string | null>} args.qrcode
|
||||
*/
|
||||
export function initOptions({
|
||||
colors,
|
||||
signals,
|
||||
env,
|
||||
utils,
|
||||
qrcode,
|
||||
vecIdToIndexes,
|
||||
pools,
|
||||
}) {
|
||||
const LS_SELECTED_KEY = `selected_path`;
|
||||
|
||||
const urlPath_ = window.document.location.pathname
|
||||
.split("/")
|
||||
.filter((v) => v);
|
||||
const urlPath = urlPath_.length ? urlPath_ : undefined;
|
||||
const savedPath = /** @type {string[]} */ (
|
||||
JSON.parse(utils.storage.read(LS_SELECTED_KEY) || "[]") || []
|
||||
).filter((v) => v);
|
||||
console.log(savedPath);
|
||||
|
||||
/** @type {Signal<Option>} */
|
||||
const selected = signals.createSignal(/** @type {any} */ (undefined));
|
||||
|
||||
const partialOptions = createPartialOptions({
|
||||
env,
|
||||
colors,
|
||||
vecIdToIndexes,
|
||||
pools,
|
||||
});
|
||||
|
||||
/** @type {Option[]} */
|
||||
const list = [];
|
||||
|
||||
const parent = signals.createSignal(/** @type {HTMLElement | null} */ (null));
|
||||
|
||||
/**
|
||||
* @param {AnyFetchedSeriesBlueprint[]} [arr]
|
||||
*/
|
||||
function arrayToRecord(arr = []) {
|
||||
return (arr || []).reduce((record, blueprint) => {
|
||||
if (env.localhost && !(blueprint.key in vecIdToIndexes)) {
|
||||
throw Error(`${blueprint.key} not recognized`);
|
||||
}
|
||||
const unit = blueprint.unit ?? utils.vecidToUnit(blueprint.key);
|
||||
record[unit] ??= [];
|
||||
record[unit].push(blueprint);
|
||||
return record;
|
||||
}, /** @type {Record<Unit, AnyFetchedSeriesBlueprint[]>} */ ({}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Option} option
|
||||
*/
|
||||
function selectOption(option) {
|
||||
utils.url.pushHistory(option.path);
|
||||
utils.url.resetParams(option);
|
||||
utils.storage.write(LS_SELECTED_KEY, JSON.stringify(option.path));
|
||||
selected.set(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Option} args.option
|
||||
* @param {string} args.frame
|
||||
* @param {Signal<string | null>} args.qrcode
|
||||
* @param {string} [args.name]
|
||||
*/
|
||||
function createOptionElement({ option, frame, name, qrcode }) {
|
||||
const title = option.title;
|
||||
if (option.kind === "url") {
|
||||
const href = option.url();
|
||||
|
||||
if (option.qrcode) {
|
||||
return utils.dom.createButtonElement({
|
||||
inside: option.name,
|
||||
title,
|
||||
onClick: () => {
|
||||
qrcode.set(option.url);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return utils.dom.createAnchorElement({
|
||||
href,
|
||||
blank: true,
|
||||
text: option.name,
|
||||
title,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return utils.dom.createAnchorElement({
|
||||
href: `/${option.path.join("/")}`,
|
||||
title,
|
||||
text: name || option.name,
|
||||
onClick: () => {
|
||||
selectOption(option);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Option | undefined} */
|
||||
let savedOption;
|
||||
|
||||
/**
|
||||
* @param {PartialOptionsTree} partialTree
|
||||
* @param {Accessor<HTMLElement | null>} parent
|
||||
* @param {string[] | undefined} parentPath
|
||||
* @returns {Accessor<number>}
|
||||
*/
|
||||
function recursiveProcessPartialTree(
|
||||
partialTree,
|
||||
parent,
|
||||
parentPath = [],
|
||||
depth = 0
|
||||
) {
|
||||
/** @type {Accessor<number>[]} */
|
||||
const listForSum = [];
|
||||
|
||||
const ul = signals.createMemo(
|
||||
// @ts_ignore
|
||||
(_previous) => {
|
||||
const previous = /** @type {HTMLUListElement | null} */ (_previous);
|
||||
previous?.remove();
|
||||
|
||||
const _parent = parent();
|
||||
if (_parent) {
|
||||
if ("open" in _parent && !_parent.open) {
|
||||
throw "Set accesor to null instead";
|
||||
}
|
||||
|
||||
const ul = window.document.createElement("ul");
|
||||
_parent.append(ul);
|
||||
return ul;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
partialTree.forEach((anyPartial, partialIndex) => {
|
||||
const renderLi = signals.createSignal(true);
|
||||
|
||||
const li = signals.createMemo((_previous) => {
|
||||
const previous = _previous;
|
||||
previous?.remove();
|
||||
|
||||
const _ul = ul();
|
||||
|
||||
if (renderLi() && _ul) {
|
||||
const li = window.document.createElement("li");
|
||||
utils.dom.insertElementAtIndex(_ul, li, partialIndex);
|
||||
return li;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, /** @type {HTMLLIElement | null} */ (null));
|
||||
|
||||
if ("tree" in anyPartial) {
|
||||
/** @type {Omit<OptionsGroup, keyof PartialOptionsGroup>} */
|
||||
const groupAddons = {};
|
||||
|
||||
Object.assign(anyPartial, groupAddons);
|
||||
|
||||
const passedDetails = signals.createSignal(
|
||||
/** @type {HTMLDivElement | HTMLDetailsElement | null} */ (null)
|
||||
);
|
||||
|
||||
const serName = utils.stringToId(anyPartial.name);
|
||||
const path = [...parentPath, serName];
|
||||
const childOptionsCount = recursiveProcessPartialTree(
|
||||
anyPartial.tree,
|
||||
passedDetails,
|
||||
path,
|
||||
depth + 1
|
||||
);
|
||||
|
||||
listForSum.push(childOptionsCount);
|
||||
|
||||
signals.createEffect(li, (li) => {
|
||||
if (!li) {
|
||||
passedDetails.set(null);
|
||||
return;
|
||||
}
|
||||
|
||||
signals.createEffect(selected, (selected) => {
|
||||
if (
|
||||
path.length <= selected.path.length &&
|
||||
path.every((v, i) => selected.path.at(i) === v)
|
||||
) {
|
||||
li.dataset.highlight = "";
|
||||
} else {
|
||||
delete li.dataset.highlight;
|
||||
}
|
||||
});
|
||||
|
||||
const details = window.document.createElement("details");
|
||||
details.dataset.name = serName;
|
||||
li.appendChild(details);
|
||||
|
||||
const summary = window.document.createElement("summary");
|
||||
details.append(summary);
|
||||
summary.append(anyPartial.name);
|
||||
|
||||
const supCount = window.document.createElement("sup");
|
||||
summary.append(supCount);
|
||||
|
||||
signals.createEffect(childOptionsCount, (childOptionsCount) => {
|
||||
supCount.innerHTML = childOptionsCount.toLocaleString("en-us");
|
||||
});
|
||||
|
||||
details.addEventListener("toggle", () => {
|
||||
const open = details.open;
|
||||
|
||||
if (open) {
|
||||
passedDetails.set(details);
|
||||
} else {
|
||||
passedDetails.set(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createRenderLiEffect() {
|
||||
signals.createEffect(childOptionsCount, (count) => {
|
||||
renderLi.set(!!count);
|
||||
});
|
||||
}
|
||||
createRenderLiEffect();
|
||||
} else {
|
||||
const option = /** @type {Option} */ (anyPartial);
|
||||
|
||||
const name = option.name;
|
||||
const path = [...parentPath, utils.stringToId(option.name)];
|
||||
|
||||
if ("kind" in anyPartial && anyPartial.kind === "explorer") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {ExplorerOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: option.title,
|
||||
})
|
||||
);
|
||||
} else if ("kind" in anyPartial && anyPartial.kind === "table") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {TableOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: option.title,
|
||||
})
|
||||
);
|
||||
} else if ("kind" in anyPartial && anyPartial.kind === "simulation") {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {SimulationOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
path,
|
||||
name,
|
||||
title: anyPartial.title,
|
||||
})
|
||||
);
|
||||
} else if ("url" in anyPartial) {
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {UrlOption} */ ({
|
||||
kind: "url",
|
||||
path,
|
||||
name,
|
||||
title: name,
|
||||
qrcode: !!anyPartial.qrcode,
|
||||
url: anyPartial.url,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
const title = option.title || option.name;
|
||||
Object.assign(
|
||||
option,
|
||||
/** @satisfies {ChartOption} */ ({
|
||||
kind: "chart",
|
||||
name,
|
||||
title,
|
||||
path,
|
||||
top: arrayToRecord(anyPartial.top),
|
||||
bottom: arrayToRecord(anyPartial.bottom),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
list.push(option);
|
||||
|
||||
if (urlPath) {
|
||||
const sameAsURLPath =
|
||||
urlPath.length === path.length &&
|
||||
urlPath.every((val, i) => val === path[i]);
|
||||
if (sameAsURLPath) {
|
||||
selected.set(option);
|
||||
}
|
||||
} else if (savedPath) {
|
||||
const sameAsSavedPath =
|
||||
savedPath.length === path.length &&
|
||||
savedPath.every((val, i) => val === path[i]);
|
||||
if (sameAsSavedPath) {
|
||||
savedOption = option;
|
||||
}
|
||||
}
|
||||
|
||||
signals.createEffect(li, (li) => {
|
||||
if (!li) {
|
||||
return;
|
||||
}
|
||||
|
||||
signals.createEffect(selected, (selected) => {
|
||||
if (selected === option) {
|
||||
li.dataset.highlight = "";
|
||||
} else {
|
||||
delete li.dataset.highlight;
|
||||
}
|
||||
});
|
||||
|
||||
const element = createOptionElement({
|
||||
option,
|
||||
frame: "nav",
|
||||
qrcode,
|
||||
});
|
||||
|
||||
li.append(element);
|
||||
});
|
||||
|
||||
listForSum.push(() => 1);
|
||||
}
|
||||
});
|
||||
|
||||
return signals.createMemo(() =>
|
||||
listForSum.reduce((acc, s) => acc + s(), 0)
|
||||
);
|
||||
}
|
||||
recursiveProcessPartialTree(partialOptions, parent);
|
||||
|
||||
if (!selected()) {
|
||||
const option =
|
||||
savedOption || list.find((option) => option.kind === "chart");
|
||||
if (option) {
|
||||
selected.set(option);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
selected,
|
||||
list,
|
||||
tree: /** @type {OptionsTree} */ (partialOptions),
|
||||
parent,
|
||||
createOptionElement,
|
||||
selectOption,
|
||||
};
|
||||
}
|
||||
/** @typedef {ReturnType<typeof initOptions>} Options */
|
||||
1459
websites/bitview/scripts/core/utils.js
Normal file
1459
websites/bitview/scripts/core/utils.js
Normal file
File diff suppressed because it is too large
Load Diff
128
websites/bitview/scripts/core/ws.js
Normal file
128
websites/bitview/scripts/core/ws.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @param {Signals} signals
|
||||
*/
|
||||
export function createWebSockets(signals) {
|
||||
/**
|
||||
* @template T
|
||||
* @param {(callback: (value: T) => void) => WebSocket} creator
|
||||
*/
|
||||
function createWebsocket(creator) {
|
||||
let ws = /** @type {WebSocket | null} */ (null);
|
||||
|
||||
const live = signals.createSignal(false);
|
||||
const latest = signals.createSignal(/** @type {T | null} */ (null));
|
||||
|
||||
function reinitWebSocket() {
|
||||
if (!ws || ws.readyState === ws.CLOSED) {
|
||||
console.log("ws: reinit");
|
||||
resource.open();
|
||||
}
|
||||
}
|
||||
|
||||
function reinitWebSocketIfDocumentNotHidden() {
|
||||
!window.document.hidden && reinitWebSocket();
|
||||
}
|
||||
|
||||
const resource = {
|
||||
live,
|
||||
latest,
|
||||
open() {
|
||||
ws = creator((value) => latest.set(() => value));
|
||||
|
||||
ws.addEventListener("open", () => {
|
||||
console.log("ws: open");
|
||||
live.set(true);
|
||||
});
|
||||
|
||||
ws.addEventListener("close", () => {
|
||||
console.log("ws: close");
|
||||
live.set(false);
|
||||
});
|
||||
|
||||
window.document.addEventListener(
|
||||
"visibilitychange",
|
||||
reinitWebSocketIfDocumentNotHidden,
|
||||
);
|
||||
|
||||
window.document.addEventListener("online", reinitWebSocket);
|
||||
},
|
||||
close() {
|
||||
ws?.close();
|
||||
window.document.removeEventListener(
|
||||
"visibilitychange",
|
||||
reinitWebSocketIfDocumentNotHidden,
|
||||
);
|
||||
window.document.removeEventListener("online", reinitWebSocket);
|
||||
live.set(false);
|
||||
ws = null;
|
||||
},
|
||||
};
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(candle: CandlestickData) => void} callback
|
||||
*/
|
||||
function krakenCandleWebSocketCreator(callback) {
|
||||
const ws = new WebSocket("wss://ws.kraken.com/v2");
|
||||
|
||||
ws.addEventListener("open", () => {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
method: "subscribe",
|
||||
params: {
|
||||
channel: "ohlc",
|
||||
symbol: ["BTC/USD"],
|
||||
interval: 1440,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
ws.addEventListener("message", (message) => {
|
||||
const result = JSON.parse(message.data);
|
||||
|
||||
if (result.channel !== "ohlc") return;
|
||||
|
||||
const { interval_begin, open, high, low, close } = result.data.at(-1);
|
||||
|
||||
/** @type {CandlestickData} */
|
||||
const candle = {
|
||||
// index: -1,
|
||||
time: new Date(interval_begin).valueOf() / 1000,
|
||||
open: Number(open),
|
||||
high: Number(high),
|
||||
low: Number(low),
|
||||
close: Number(close),
|
||||
};
|
||||
|
||||
candle && callback({ ...candle });
|
||||
});
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
/** @type {ReturnType<typeof createWebsocket<CandlestickData>>} */
|
||||
const kraken1dCandle = createWebsocket((callback) =>
|
||||
krakenCandleWebSocketCreator(callback),
|
||||
);
|
||||
|
||||
kraken1dCandle.open();
|
||||
|
||||
signals.createEffect(kraken1dCandle.latest, (latest) => {
|
||||
if (latest) {
|
||||
const close = latest.close;
|
||||
console.log("close:", close);
|
||||
|
||||
window.document.title = `${latest.close.toLocaleString("en-us")} | ${
|
||||
window.location.host
|
||||
}`;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
kraken1dCandle,
|
||||
};
|
||||
}
|
||||
/** @typedef {ReturnType<typeof createWebSockets>} WebSockets */
|
||||
@@ -1,3 +1,88 @@
|
||||
/**
|
||||
*
|
||||
* @import { Valued, SingleValueData, CandlestickData, OHLCTuple, Series, ISeries, HistogramData, LineData, BaselineData, LineSeriesPartialOptions, BaselineSeriesPartialOptions, HistogramSeriesPartialOptions, CandlestickSeriesPartialOptions, CreateChartElement, Chart } from "./core/chart"
|
||||
*
|
||||
* @import * as _ from "./packages/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.d.ts"
|
||||
*
|
||||
* @import { SerializedChartableIndex } from "./panes/chart";
|
||||
*
|
||||
* @import { Signal, Signals, Accessor } from "./packages/solidjs-signals/wrapper";
|
||||
*
|
||||
* @import { DateIndex, DecadeIndex, DifficultyEpoch, Index, HalvingEpoch, Height, MonthIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2MSOutputIndex, P2AAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxIndex, InputIndex, OutputIndex, VecId, WeekIndex, SemesterIndex, YearIndex, VecIdToIndexes, QuarterIndex, EmptyOutputIndex, OpReturnIndex, UnknownOutputIndex, EmptyAddressIndex, LoadedAddressIndex } from "./bridge/vecs"
|
||||
*
|
||||
* @import { Pools, Pool } from "./bridge/pools"
|
||||
*
|
||||
* @import { Color, ColorName, Colors } from "./core/colors"
|
||||
*
|
||||
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree } from "./core/options/partial"
|
||||
*
|
||||
* @import { WebSockets } from "./core/ws"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {typeof import("./lazy")["default"]} Packages
|
||||
* @typedef {typeof import("./core/utils")} Utilities
|
||||
* @typedef {typeof import("./core/env")["default"]} Env
|
||||
* @typedef {typeof import("./core/elements")["default"]} Elements
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {"" |
|
||||
* "%all" |
|
||||
* "%cmcap" |
|
||||
* "%cp+l" |
|
||||
* "%mcap" |
|
||||
* "%pnl" |
|
||||
* "%rcap" |
|
||||
* "%self" |
|
||||
* "/sec" |
|
||||
* "address data" |
|
||||
* "block" |
|
||||
* "blocks" |
|
||||
* "bool" |
|
||||
* "btc" |
|
||||
* "bytes" |
|
||||
* "cents" |
|
||||
* "coinblocks" |
|
||||
* "coindays" |
|
||||
* "constant" |
|
||||
* "count" |
|
||||
* "date" |
|
||||
* "days" |
|
||||
* "difficulty" |
|
||||
* "epoch" |
|
||||
* "gigabytes" |
|
||||
* "h/s" |
|
||||
* "hash" |
|
||||
* "height" |
|
||||
* "id" |
|
||||
* "index" |
|
||||
* "len" |
|
||||
* "locktime" |
|
||||
* "percentage" |
|
||||
* "position" |
|
||||
* "ratio" |
|
||||
* "sat/vb" |
|
||||
* "satblocks" |
|
||||
* "satdays" |
|
||||
* "sats" |
|
||||
* "sats/(ph/s)/day" |
|
||||
* "sats/(th/s)/day" |
|
||||
* "sd" |
|
||||
* "secs" |
|
||||
* "timestamp" |
|
||||
* "tx" |
|
||||
* "type" |
|
||||
* "usd" |
|
||||
* "usd/(ph/s)/day" |
|
||||
* "usd/(th/s)/day" |
|
||||
* "vb" |
|
||||
* "version" |
|
||||
* "wu" |
|
||||
* "years" |
|
||||
* "" } Unit
|
||||
*/
|
||||
|
||||
// DO NOT CHANGE, Exact format is expected in `brk_bundler`
|
||||
// @ts-ignore
|
||||
import("./main.js");
|
||||
|
||||
58
websites/bitview/scripts/lazy.js
Normal file
58
websites/bitview/scripts/lazy.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const imports = {
|
||||
async signals() {
|
||||
return import("./packages/solidjs-signals/wrapper.js").then(
|
||||
(d) => d.default,
|
||||
);
|
||||
},
|
||||
async chart() {
|
||||
return window.document.fonts.ready.then(() =>
|
||||
import("./core/chart.js").then((d) => d.default),
|
||||
);
|
||||
},
|
||||
async leanQr() {
|
||||
return import("./packages/lean-qr/2.5.0/index.mjs").then((d) => d);
|
||||
},
|
||||
async ufuzzy() {
|
||||
return import("./packages/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs").then(
|
||||
({ default: d }) => d,
|
||||
);
|
||||
},
|
||||
async modernScreenshot() {
|
||||
return import("./packages/modern-screenshot/wrapper.js").then((d) => d);
|
||||
},
|
||||
|
||||
async options() {
|
||||
return import("./core/options/full.js").then((d) => d);
|
||||
},
|
||||
async vecs() {
|
||||
return import("./bridge/vecs.js").then((d) => d);
|
||||
},
|
||||
async pools() {
|
||||
return import("./bridge/pools.js").then((d) => d);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @template {keyof typeof imports} K
|
||||
* @param {K} key
|
||||
*/
|
||||
function lazyImport(key) {
|
||||
/** @type {any | null} */
|
||||
let packagePromise = null;
|
||||
|
||||
return function () {
|
||||
if (!packagePromise) {
|
||||
packagePromise = imports[key]();
|
||||
}
|
||||
return /** @type {ReturnType<typeof imports[K]>} */ (packagePromise);
|
||||
};
|
||||
}
|
||||
|
||||
export default /** @type {{ [K in keyof typeof imports]: () => ReturnType<typeof imports[K]> }} */ (
|
||||
Object.fromEntries(
|
||||
Object.keys(imports).map((key) => [
|
||||
key,
|
||||
lazyImport(/** @type {keyof typeof imports} */ (key)),
|
||||
]),
|
||||
)
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
0
websites/bitview/scripts/panes/nav.js
Normal file
0
websites/bitview/scripts/panes/nav.js
Normal file
0
websites/bitview/scripts/panes/search.js
Normal file
0
websites/bitview/scripts/panes/search.js
Normal file
Reference in New Issue
Block a user