general: snapshot

This commit is contained in:
k
2024-10-19 10:34:12 +02:00
parent 7dac857135
commit 35dd194b28
13 changed files with 260 additions and 1351 deletions
+1 -1
View File
@@ -27,7 +27,7 @@
## Website
- Added a dashboard
- ~Added a dashboard~ Added the latest value to the tree instead
- Added a library of PDFs
- Fixed service worker not passing 304 (not modified) response and instead serving cached responses
- Fixed history not being properly registered
+5 -4
View File
@@ -42,8 +42,9 @@ This project is still in an early stage. Until more people look at the code and
## Instances
- [kibo.money](https://kibo.money)
- [backup.kibo.money](https://backup.kibo.money)
- [kibo.money](https://kibo.money) ![Uptime Robot status](https://img.shields.io/uptimerobot/status/m797259009-043f6b92d4cc2deef7d13f50)
- [backup.kibo.money](https://backup.kibo.money) ![Uptime Robot status](https://img.shields.io/uptimerobot/status/m797259013-bb29a8264fab8786fb80c5ed)
- [preview.kibo.money](https://preview.kibo.money) ![Uptime Robot status](https://img.shields.io/uptimerobot/status/m797869753-d40fc161bcb34624857a8082)
## Structure
@@ -67,12 +68,12 @@ This project is still in an early stage. Until more people look at the code and
- At least 16 GB of RAM
- 1 TB of free space (will use 60-80% of that)
- A running instance of bitcoin-core with txindex=1 and rpc credentials
- A running instance of bitcoin-core (>= 28.0 **NOT** supported) with txindex=1 and rpc credentials,
- Git
### Docker
Coming soon
Working on it
### Manual
+2
View File
@@ -104,6 +104,8 @@ pub struct MiningDataset {
pub hash_rate_1m_sma: DateMap<f32>,
pub hash_rate_2m_sma: DateMap<f32>,
pub hash_price: DateMap<f64>,
// pub hash_price_min: DateMap<f64>,
// pub hash_price_rebound: DateMap<f64>,
pub difficulty_adjustment: DateMap<f64>,
pub block_size_recap: DateRecapDataset<f32>, // in MB
pub block_weight_recap: DateRecapDataset<f32>, // in MB
+101 -54
View File
@@ -232,11 +232,11 @@
/* current: oklch(90% 0.01 44) */
--lighter-gray: #e4dcd9;
/* before: #c0c0ab */
/* current: oklch(75% 0.01 44) */
--light-gray: #b4aca9;
/* current: oklch(65% 0.01 44) */
--light-gray: #867e7b;
/* before: #666660 */
/* current: oklch(50% 0.01 44) */
--dark-gray: #68625f;
/* current: oklch(60% 0.01 44) */
--dark-gray: #867e7b;
/* before: #30302b */
/* current: oklch(25% 0.01 44) */
--darker-gray: #26201e;
@@ -265,7 +265,7 @@
--transform-scale-active: scaleX(0.95) scaleY(0.9);
--default-main-width: 384px;
--default-main-width: 400px;
--background-color: var(--white);
--color: var(--black);
@@ -580,7 +580,7 @@
}
> span.emoji {
filter: grayscale(100%) brightness(60%) contrast(150%);
filter: grayscale(100%) brightness(66%) opacity(66%);
}
> svg.favorite {
@@ -590,6 +590,15 @@
color: var(--orange);
}
> span.value {
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
&:has(+ *) {
margin-right: 0.375rem;
}
}
> span.new {
width: 0.375rem /* 6px */;
height: 0.375rem /* 6px */;
@@ -607,23 +616,10 @@
> span.main > .emoji {
filter: sepia(90%) saturate(420%) hue-rotate(320deg)
brightness(80%);
brightness(80%) !important;
}
}
> span.absolute {
text-align: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin-bottom: -0.375rem;
color: var(--off-color);
font-size: var(--font-size-2xs);
line-height: var(--line-height-2xs);
overflow: visible !important;
}
> *:not(input):not(svg) {
width: 100%;
overflow: hidden;
@@ -635,7 +631,6 @@
margin-top: -0.5rem /* -8px */;
}
.tree &,
.list & {
color: var(--color);
}
@@ -644,13 +639,8 @@
&:has(input:checked) {
color: var(--color);
.tree &,
.list & {
color: var(--orange);
}
> span.main > span.emoji {
filter: sepia(90%) saturate(420%) hue-rotate(320deg) brightness(80%);
filter: grayscale(100%);
}
}
}
@@ -789,6 +779,11 @@
}
}
sup {
color: var(--off-color);
margin-left: 0.25rem;
}
small {
color: var(--off-color);
font-size: var(--font-size-xs);
@@ -823,7 +818,10 @@
}
&:hover {
color: var(--orange);
&,
* {
color: var(--orange) !important;
}
}
}
@@ -860,6 +858,7 @@
-webkit-user-select: none;
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
color: var(--off-color);
ul {
overflow: hidden;
@@ -870,16 +869,6 @@
padding-left: 12px;
border-left: 1px;
&[data-highlight] {
&::before {
border-color: var(--orange) !important;
}
> details > summary > span.marker {
color: var(--orange) !important;
}
}
&:not(:has(~ li:not([hidden]))) {
border-color: transparent !important;
}
@@ -895,22 +884,79 @@
border-color: var(--border-color);
border-width: 0 0 1px 1px;
border-radius: 0px 0px 0px 4px;
z-index: -10;
}
&[data-highlight] {
> details > summary {
&,
* {
color: var(--color) !important;
}
}
&::before,
> details > summary > span.marker {
border-color: var(--color) !important;
z-index: 10;
}
> details:not([open]) > summary > span.marker {
background-color: var(--color) !important;
}
}
&:hover {
&::before,
> details > summary > span.marker {
border-color: var(--orange) !important;
z-index: 20;
}
> details:not([open]) > summary > span.marker {
background-color: var(--orange) !important;
}
}
&:has(*[data-highlight]) {
> details > summary::after {
border-color: var(--orange) !important;
color: var(--color) !important;
border-color: var(--color) !important;
}
}
&:has(*:hover) {
> details > summary {
&,
* {
color: var(--orange) !important;
}
&:not(:hover)::after {
border-color: var(--orange) !important;
}
}
}
&:has(~ *[data-highlight]) {
border-color: var(--orange) !important;
border-color: var(--color) !important;
}
&:has(~ *:hover) {
border-color: var(--orange) !important;
}
&:has(~ *[data-highlight]),
&:has(~ *:hover) {
&::before {
z-index: -10;
z-index: -10 !important;
}
}
&:has(*:hover)::before {
z-index: 10 !important;
}
> details > summary {
position: relative;
@@ -927,12 +973,17 @@
}
> span.marker {
color: var(--border-color);
font-size: var(--font-size-2xs);
line-height: var(--line-height-2xs);
border: 1px;
border-radius: 999px;
background-color: var(--border-color);
width: 9px;
height: 9px;
z-index: 10;
margin-left: -4px;
margin-bottom: 0.0625rem;
details[open] > summary > & {
background-color: var(--background-color);
}
}
> small {
@@ -1798,45 +1849,41 @@
for="folders-filter-all"
title="Chart"
>
<span class="absolute" id="folders-filter-all-count"></span>
<input
type="radio"
name="folders-filter"
id="folders-filter-all"
value="chart"
/>
All
<span>All<sup id="folders-filter-all-count"></sup> </span>
</label>
<label
id="folders-filter-favorites-label"
for="folders-filter-favorites"
title="Chart"
>
<span
class="absolute"
id="folders-filter-favorites-count"
></span>
<input
type="radio"
name="folders-filter"
id="folders-filter-favorites"
value="chart"
/>
Favorites
<span
>Favorites<sup id="folders-filter-favorites-count"></sup>
</span>
</label>
<label
id="folders-filter-new-label"
for="folders-filter-new"
title="Chart"
>
<span class="absolute" id="folders-filter-new-count"></span>
<input
type="radio"
name="folders-filter"
id="folders-filter-new"
value="chart"
/>
New
<span>New<sup id="folders-filter-new-count"></sup> </span>
</label>
</div>
</div>
-309
View File
@@ -1,309 +0,0 @@
/**
* @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]);
}
+30 -71
View File
@@ -1,7 +1,7 @@
// @ts-check
/**
* @import { OptionPath, PartialOption, PartialOptionsGroup, PartialOptionsTree, Option, OptionsGroup, Series, PriceSeriesType, ResourceDataset, TimeScale, SerializedHistory, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, SettingsTheme, DatasetCandlestickData, FoldersFilter, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, DashboardOption, OptionsTree, AnyPath } from "./types/self"
* @import { OptionPath, PartialOption, PartialOptionsGroup, PartialOptionsTree, Option, OptionsGroup, Series, PriceSeriesType, ResourceDataset, TimeScale, SerializedHistory, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, SettingsTheme, DatasetCandlestickData, FoldersFilter, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, AnyPath } from "./types/self"
* @import {createChart as CreateClassicChart, createChartEx as CreateCustomChart, LineStyleOptions} from "./packages/lightweight-charts/v4.2.0/types";
* @import * as _ from "./packages/ufuzzy/v1.0.14/types"
* @import { DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, SingleValueData, ISeriesApi, Time, LogicalRange, SeriesMarker, CandlestickData, SeriesType, BaselineStyleOptions, SeriesOptionsCommon } from "./packages/lightweight-charts/v4.2.0/types"
@@ -535,11 +535,6 @@ function initPackages() {
),
);
},
async flexmasonry() {
return import("./packages/flexmasonry/v0.2.3-modified/script.js").then(
({ default: d }) => d,
);
},
async leanQr() {
return import("./packages/lean-qr/v2.3.4/script.js").then((d) => d);
},
@@ -553,7 +548,6 @@ function initPackages() {
/**
* @typedef {ReturnType<typeof imports.signals>} SignalsPromise
* @typedef {ReturnType<typeof imports.lightweightCharts>} LightweightChartsPromise
* @typedef {ReturnType<typeof imports.flexmasonry>} FlexmasonryPromise
* @typedef {ReturnType<typeof imports.leanQr>} LeanQrPromise
* @typedef {ReturnType<typeof imports.ufuzzy>} uFuzzyPromise
*/
@@ -579,7 +573,6 @@ function initPackages() {
return {
signals: importPackage("signals"),
lightweightCharts: importPackage("lightweightCharts"),
flexmasonry: importPackage("flexmasonry"),
leanQr: importPackage("leanQr"),
ufuzzy: importPackage("ufuzzy"),
};
@@ -588,7 +581,6 @@ const packages = initPackages();
/**
* @typedef {Awaited<ReturnType<typeof packages.signals>>} Signals
* @typedef {Awaited<ReturnType<typeof packages.lightweightCharts>>} LightweightCharts
* @typedef {Awaited<ReturnType<typeof packages.flexmasonry>>} Flexmasonry
*/
const options = import("./options.js");
@@ -1626,8 +1618,6 @@ function createDatasets(signals) {
const baseURL = `${URL}/${path}`;
console.log({ baseURL });
const backupURL = `${BACKUP_URL}/${path}`;
const fetchedJSONs = new Array(
@@ -2110,49 +2100,50 @@ packages.signals().then((signals) =>
}
const lastHeight = createLastHeightResource();
const lastValues = signals.createSignal(
/** @type {Record<LastPath, number> | null} */ (null),
);
function createFetchLastValuesWhenNeededEffect() {
let previousHeight = -1;
signals.createEffect(() => {
if (previousHeight !== lastHeight()) {
fetch("/api/last").then((response) => {
response.json().then((json) => {
if (typeof json === "object") {
lastValues.set(json);
previousHeight = lastHeight();
}
});
});
}
});
}
createFetchLastValuesWhenNeededEffect();
const webSockets = initWebSockets(signals);
const colors = createColors(dark);
const options = initOptions({ signals, colors, ids, env, utils });
const options = initOptions({
colors,
env,
ids,
lastValues,
signals,
utils,
webSockets,
});
function initSelected() {
function initSelectedFrame() {
console.log("selected: init");
const selectedKind = signals.createMemo(() => options.selected().kind);
const datasets = createDatasets(signals);
const lastValues = signals.createSignal(
/** @type {Record<LastPath, number> | null} */ (null),
);
function createFetchLastValuesWhenNeededEffect() {
let previousHeight = -1;
signals.createEffect(() => {
if (selectedKind() === "dashboard") {
if (previousHeight !== lastHeight()) {
fetch("/api/last").then((response) => {
response.json().then((json) => {
if (typeof json === "object") {
lastValues.set(json);
previousHeight = lastHeight();
}
});
});
}
}
});
}
createFetchLastValuesWhenNeededEffect();
function createApplyOptionEffect() {
const lastChartOption = signals.createSignal(
/** @type {ChartOption | null} */ (null),
);
const lastDashboardOption = signals.createSignal(
/** @type {DashboardOption | null} */ (null),
);
const owner = signals.getOwner();
@@ -2189,38 +2180,6 @@ packages.signals().then((signals) =>
element = elements.home;
break;
}
case "dashboard": {
element = elements.dashboard;
lastDashboardOption.set(option);
if (firstDashboardOption) {
const flexmasonry = packages.flexmasonry();
const dashboardScript = import("./dashboard.js");
utils.dom.importStyleAndThen("/styles/dashboard.css", () =>
dashboardScript.then(({ initDashboardElement }) =>
flexmasonry.then((flexmasonry) =>
signals.runWithOwner(owner, () =>
initDashboardElement({
elements,
flexmasonry,
lastValues,
options,
selected: /** @type {any} */ (
lastDashboardOption
),
signals,
utils,
}),
),
),
),
);
}
firstDashboardOption = false;
break;
}
case "chart": {
element = elements.charts;
+120 -423
View File
@@ -1,3 +1,6 @@
const DATE_TO_PREFIX = "date-to-";
const HEIGHT_TO_PREFIX = "height-to-";
/**
* @param {Colors} colors
* @returns {PartialOptionsTree}
@@ -703,9 +706,6 @@ function createPartialOptions(colors) {
]
: []),
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -725,9 +725,6 @@ function createPartialOptions(colors) {
datasetPath: keyMax,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -747,9 +744,6 @@ function createPartialOptions(colors) {
datasetPath: key90p,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -769,9 +763,6 @@ function createPartialOptions(colors) {
datasetPath: key75p,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -791,9 +782,6 @@ function createPartialOptions(colors) {
datasetPath: keyMedian,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -813,9 +801,6 @@ function createPartialOptions(colors) {
datasetPath: key25p,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -835,9 +820,6 @@ function createPartialOptions(colors) {
datasetPath: key10p,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -857,9 +839,6 @@ function createPartialOptions(colors) {
datasetPath: keyMin,
},
],
dashboard: {
skip: true,
},
},
]
: []),
@@ -884,9 +863,6 @@ function createPartialOptions(colors) {
}) {
return {
name: "Ratio",
dashboard: {
skip: true,
},
tree: [
{
scale,
@@ -1127,10 +1103,6 @@ function createPartialOptions(colors) {
function createAllTimeHighOptions(scale) {
return {
name: "All Time High",
dashboard: {
separate: true,
defaultOpen: true,
},
tree: [
{
scale,
@@ -1171,11 +1143,6 @@ function createPartialOptions(colors) {
},
...(scale === "date"
? /** @type {PartialChartOption[]} */ ([
{
name: "Date",
path: "all-time-high-date",
unit: "Date",
},
{
scale,
icon: "🗓️",
@@ -1193,9 +1160,6 @@ function createPartialOptions(colors) {
},
{
name: "Max Between",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1285,9 +1249,6 @@ function createPartialOptions(colors) {
function createAverageOptions({ scale, color, name, title, key }) {
return {
name,
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1303,9 +1264,6 @@ function createPartialOptions(colors) {
datasetPath: `${scale}-to-price-${key}-sma`,
},
],
dashboard: {
ignoreName: true,
},
},
createRatioOptions({
scale,
@@ -1394,16 +1352,9 @@ function createPartialOptions(colors) {
return {
name: "Market",
dashboard: {
defaultOpen: true,
},
tree: [
{
name: "Price",
dashboard: {
// defaultOpen: true,
flatten: true,
},
tree: [
{
scale,
@@ -1482,9 +1433,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Mined",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1610,9 +1558,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Size",
dashboard: {
flatten: true,
},
tree: createRecapOptions({
scale,
title: "Block Size",
@@ -1632,9 +1577,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Weight",
dashboard: {
flatten: true,
},
tree: createRecapOptions({
scale,
title: "Block Weight",
@@ -1653,9 +1595,6 @@ function createPartialOptions(colors) {
{
scale,
name: "VBytes",
dashboard: {
flatten: true,
},
tree: createRecapOptions({
scale,
title: "Block VBytes",
@@ -1674,9 +1613,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Interval",
dashboard: {
flatten: true,
},
tree: createRecapOptions({
scale,
title: "Block Interval",
@@ -1789,9 +1725,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
name: "Last",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1828,9 +1761,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Daily Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1867,9 +1797,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Yearly Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1906,9 +1833,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Cumulative",
dashboard: {
skip: true,
},
tree: [
{
scale,
@@ -1954,9 +1878,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
name: "Last",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -1993,9 +1914,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Daily Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -2032,9 +1950,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Yearly Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -2071,9 +1986,7 @@ function createPartialOptions(colors) {
{
scale,
name: "Cumulative",
dashboard: {
skip: true,
},
tree: [
{
scale,
@@ -2119,9 +2032,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
name: "Last",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -2158,9 +2068,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Daily Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -2197,9 +2104,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Yearly Sum",
dashboard: {
flatten: true,
},
tree: [
{
scale,
@@ -2236,9 +2140,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Cumulative",
dashboard: {
skip: true,
},
tree: [
{
scale,
@@ -3676,9 +3577,7 @@ function createPartialOptions(colors) {
function createCohortOptionsGroup({ scale, color, name, datasetId, title }) {
return {
name,
dashboard: {
separate: true,
},
tree: createCohortOptions({
title,
name,
@@ -3696,9 +3595,6 @@ function createPartialOptions(colors) {
function createHodlersOptions(scale) {
return {
name: "Hodlers",
dashboard: {
hopOver: true,
},
tree: [
{
scale,
@@ -3740,9 +3636,6 @@ function createPartialOptions(colors) {
),
{
name: "Up To X",
dashboard: {
flatten: true,
},
tree: groups.upTo.map(({ key, id, name }) =>
createCohortOptionsGroup({
scale,
@@ -3755,9 +3648,6 @@ function createPartialOptions(colors) {
},
{
name: "From X To Y",
dashboard: {
flatten: true,
},
tree: groups.fromXToY.map(({ key, id, name }) =>
createCohortOptionsGroup({
scale,
@@ -3770,9 +3660,6 @@ function createPartialOptions(colors) {
},
{
name: "From X",
dashboard: {
flatten: true,
},
tree: groups.fromX.map(({ key, id, name }) =>
createCohortOptionsGroup({
scale,
@@ -3785,9 +3672,6 @@ function createPartialOptions(colors) {
},
{
name: "Years",
dashboard: {
flatten: true,
},
tree: groups.year.map(({ key, id, name }) =>
createCohortOptionsGroup({
scale,
@@ -3846,9 +3730,6 @@ function createPartialOptions(colors) {
}) {
return {
name: filenameAddon ? `${name} - ${filenameAddon}` : name,
dashboard: {
separate: true,
},
tree: [
createAddressCountOption({ scale, name, datasetId, color }),
...createCohortOptions({
@@ -4846,289 +4727,6 @@ function createPartialOptions(colors) {
}
return [
// {
// icon: "🕊️",
// name: "Home",
// kind: "home",
// title: "Home",
// },
{
icon: "🌍",
name: "Dashboard",
title: "Global State Of The Network",
description: "",
groups: [
// {
// name: "Market",
// values: [
// {
// name: "Dollars Per Bitcoin",
// path: "close",
// unit: "US Dollars",
// },
// {
// name: "Satoshis Per Dollar",
// path: "sats-per-dollar",
// unit: "Satoshis",
// },
// {
// name: "Capitalization",
// path: "market-cap",
// unit: "US Dollars",
// },
// ],
// },
// {
// name: "All Time High",
// values: [
// {
// name: "Price",
// path: "all-time-high",
// unit: "US Dollars",
// },
// {
// name: "Drawdown",
// path: "drawdown",
// unit: "Percentage",
// },
// {
// name: "Date",
// path: "all-time-high-date",
// unit: "Date",
// },
// {
// name: "Days Since",
// path: "days-since-all-time-high",
// },
// {
// name: "Max Days Between",
// path: "max-days-between-all-time-highs",
// },
// {
// name: "Max Years Between",
// path: "max-years-between-all-time-highs",
// },
// ],
// },
// {
// name: "Averages",
// unit: "US Dollars",
// values: [
// {
// name: "1 Week",
// path: "price-1w-sma",
// },
// {
// name: "1 Month",
// path: "price-1m-sma",
// },
// {
// name: "1 Year",
// path: "price-1y-sma",
// },
// {
// name: "4 Year",
// path: "price-4y-sma",
// },
// ],
// },
// {
// name: "Returns",
// unit: "Percentage",
// values: [
// {
// name: "Today (UTC)",
// path: "price-1d-total-return",
// },
// {
// name: "1 Week",
// // path: "price-1m-total-return",
// },
// {
// name: "1 Month",
// path: "price-1m-total-return",
// },
// {
// name: "6 Month",
// path: "price-6m-total-return",
// },
// {
// name: "1 Year",
// path: "price-1y-total-return",
// },
// {
// name: "4 Year",
// path: "price-4y-total-return",
// },
// {
// name: "10 Year",
// path: "price-10y-total-return",
// },
// ],
// },
// {
// name: "Blockchain",
// values: [
// {
// name: "Height",
// path: "last-height",
// formatNumber: false,
// },
// {
// name: "Average Size",
// path: "block-size-1d-average",
// unit: "Megabytes",
// },
// {
// name: "Average Weight",
// path: "block-weight-1d-average",
// unit: "Weight",
// },
// {
// name: "Average VBytes",
// path: "block-vbytes-1d-average",
// unit: "Virtual Bytes",
// },
// {
// name: "Average Interval",
// path: "block-interval-1d-average",
// unit: "Seconds",
// },
// {
// name: "Cumulative size",
// path: "cumulative-block-size",
// unit: "Megabytes",
// },
// ],
// },
// {
// name: "Blocks Mined",
// values: [
// {
// name: "Since UTC",
// path: "blocks-mined",
// },
// {
// name: "Weekly Avg.",
// path: "blocks-mined-1w-sma",
// },
// {
// name: "Monthly Avg.",
// path: "blocks-mined-1m-sma",
// },
// {
// name: "Target",
// path: "blocks-mined-1d-target",
// },
// ],
// },
// {
// name: "Coinbases",
// values: [
// {
// name: "Last Block In Bitcoin",
// unit: "Bitcoin",
// path: "last-coinbase",
// },
// {
// name: "Last Block In Dollars",
// unit: "US Dollars",
// path: "last-coinbase-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "coinbase",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "coinbase-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "coinbase-1y-sum",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "coinbase-in-dollars-1y-sum",
// },
// ],
// },
// {
// name: "Subsidies",
// values: [
// {
// name: "Last Block In Bitcoin",
// unit: "Bitcoin",
// path: "last-subsidy",
// },
// {
// name: "Last Block In Dollars",
// unit: "US Dollars",
// path: "last-subsidy-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "subsidy",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "subsidy-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "subsidy-1y-sum",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "subsidy-in-dollars-1y-sum",
// },
// ],
// },
// {
// name: "Fees",
// values: [
// {
// name: "Last Block In Bitcoin",
// unit: "Bitcoin",
// path: "last-fees",
// },
// {
// name: "Last Block In Dollars",
// unit: "US Dollars",
// path: "last-fees-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "fees",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "fees-in-dollars",
// },
// {
// name: "Daily Sum In Bitcoin",
// unit: "Bitcoin",
// path: "fees-1y-sum",
// },
// {
// name: "Daily Sum In Dollars",
// unit: "US Dollars",
// path: "fees-in-dollars-1y-sum",
// },
// ],
// },
],
},
{
name: "Charts",
tree: [
@@ -5265,8 +4863,18 @@ function createPartialOptions(colors) {
* @param {Ids} args.ids
* @param {Env} args.env
* @param {Utilities} args.utils
* @param {Signal<Record<LastPath, number> | null>} args.lastValues
* @param {WebSockets} args.webSockets
*/
export function initOptions({ colors, signals, ids, env, utils }) {
export function initOptions({
colors,
signals,
ids,
env,
utils,
lastValues,
webSockets,
}) {
const urlSelected = utils.url.pathnameToSelectedId();
const savedSelectedId = localStorage.getItem(ids.selectedId);
@@ -5345,6 +4953,70 @@ export function initOptions({ colors, signals, ids, env, utils }) {
return `${option.id}-favorite`;
}
/**
* @param {SeriesBlueprint[]} array
*/
function getMainValueFromBlueprints(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 undefined;
const id = blueprint.datasetPath
.replace(DATE_TO_PREFIX, "")
.replace(HEIGHT_TO_PREFIX, "");
return /** @type {number | undefined} */ (
lastValues()?.[/** @type {LastPath} */ (id)]
);
}
/**
* @param {Number | undefined} value
* @param {Unit} unit
*/
function formatValue(value, unit) {
if (!value) return "";
const s =
unit !== "Count"
? utils.locale.numberToShortUSFormat(value)
: utils.locale.numberToUSFormat(
value,
unit === "Count" ? 0 : undefined,
);
switch (unit) {
case "US Dollars": {
return `$${s}`;
}
case "Bitcoin": {
return `${s}`;
}
case "Percentage": {
return `${s}%`;
}
case "Seconds": {
return `${s} sec`;
}
case "Megabytes": {
return `${s} MB`;
}
default: {
return s;
}
}
}
/**
* @param {Object} args
* @param {Option} args.option
@@ -5375,6 +5047,39 @@ export function initOptions({ colors, signals, ids, env, utils }) {
spanEmoji.innerHTML = option.icon;
spanMain.prepend(spanEmoji);
if (option.kind === "chart") {
const spanValue = window.document.createElement("span");
spanValue.classList.add("value");
spanMain.append(spanValue);
if (!option.top?.length && !option.bottom?.length) {
signals.createEffect(() => {
const close =
webSockets.krakenCandle.latest()?.close ?? lastValues()?.close;
if (close) {
spanValue.innerHTML = formatValue(close, "US Dollars");
}
});
} else if (option.bottom?.length) {
const bottom = option.bottom;
signals.createEffect(() => {
spanValue.innerHTML = formatValue(
getMainValueFromBlueprints(bottom),
option.unit,
);
});
} else if (option.top?.length) {
const top = option.top;
signals.createEffect(() => {
spanValue.innerHTML = formatValue(
getMainValueFromBlueprints(top),
option.unit,
);
});
}
}
/** @type {HTMLSpanElement | undefined} */
let spanNew;
@@ -5548,30 +5253,25 @@ export function initOptions({ colors, signals, ids, env, utils }) {
const spanMarker = window.document.createElement("span");
spanMarker.classList.add("marker");
spanMarker.innerHTML = "●";
summary.append(spanMarker);
const spanName = utils.dom.createSpanName(anyPartial.name);
summary.append(spanName);
const smallCount = window.document.createElement("small");
smallCount.hidden = details.open;
const supCount = window.document.createElement("sup");
signals.createEffect(() => {
smallCount.innerHTML = childOptionsCount().toLocaleString();
supCount.innerHTML = childOptionsCount().toLocaleString();
});
summary.append(smallCount);
spanName.append(supCount);
details.addEventListener("toggle", () => {
const open = details.open;
smallCount.hidden = open;
if (open) {
spanMarker.innerHTML = "○";
localStorage.setItem(folderOpenLocalStorageKey, "1");
passedDetails.set(details);
} else {
spanMarker.innerHTML = "●";
localStorage.removeItem(folderOpenLocalStorageKey);
passedDetails.set(null);
}
@@ -5593,7 +5293,7 @@ export function initOptions({ colors, signals, ids, env, utils }) {
/** @type {string} */
let title;
if ("kind" in anyPartial) {
if ("kind" in anyPartial && anyPartial.kind === "home") {
kind = anyPartial.kind;
id = anyPartial.kind;
title = anyPartial.title;
@@ -5601,10 +5301,6 @@ export function initOptions({ colors, signals, ids, env, utils }) {
kind = "pdf";
id = `${ids.fromString(anyPartial.name)}-pdf`;
title = anyPartial.name;
} else if ("groups" in anyPartial) {
kind = "dashboard";
id = `dashboard-${ids.fromString(anyPartial.title)}`;
title = anyPartial.title;
} else if ("scale" in anyPartial) {
kind = "chart";
id = `chart-${anyPartial.scale}-to-${ids.fromString(
@@ -5612,7 +5308,8 @@ export function initOptions({ colors, signals, ids, env, utils }) {
)}`;
title = anyPartial.title;
} else {
return;
console.log(anyPartial);
throw "Unreachable";
}
/** @type {ProcessedOptionAddons} */
@@ -1,3 +0,0 @@
URL + Version:
https://unpkg.com/browse/flexmasonry@latest/
@@ -1,198 +0,0 @@
const defaultOptions = {
/*
* If `responsive` is `true`, `breakpointCols` will be used to determine
* how many columns a grid should have at a given responsive breakpoint.
*/
responsive: true,
/*
* A list of how many columns should be shown at different responsive
* breakpoints, defined by media queries.
*/
breakpointCols: {
1500: 5,
1200: 4,
992: 3,
768: 2,
576: 1,
},
/*
* If `responsive` is `false`, this number of columns will always be shown,
* no matter the width of the screen.
*/
numCols: 4,
};
let _resizeId = null;
let _options = {};
let _targets = [];
function init(targets, options = {}) {
if (typeof targets === "string") {
_targets = document.querySelectorAll(targets);
} else {
_targets = targets;
}
_options = Object.assign(defaultOptions, options);
_targets.forEach(function (target) {
setUp(target);
// setHeight(target);
});
addEventListeners();
return this;
}
function setUp(target) {
target.classList.add("flexmasonry");
if (_options.responsive) {
target.classList.add("flexmasonry-responsive");
}
setColsClass(target);
Array.from(target.children).forEach(function (item) {
item.classList.add("flexmasonry-item");
});
addBreakElements(target);
}
// function onLoad() {
// _targets.forEach(function (target) {
// setHeight(target);
// });
// }
function onResize() {
if (_resizeId) {
window.cancelAnimationFrame(_resizeId);
}
_resizeId = window.requestAnimationFrame(function () {
refreshAll();
});
}
function addEventListeners() {
// window.addEventListener("load", onLoad);
window.addEventListener("resize", onResize);
}
function removeEventListeners() {
// window.removeEventListener("load", onLoad);
window.removeEventListener("resize", onResize);
}
// function setHeight(target) {
// if (getCurrentCols(target) < 2) {
// target.style.removeProperty("height");
// return;
// }
// let heights = [];
// Array.from(target.children).forEach(function (item) {
// if (item.classList.contains("flexmasonry-break")) {
// return;
// }
// const comp = window.getComputedStyle(item);
// const order = comp.getPropertyValue("order");
// const height = comp.getPropertyValue("height");
// if (!heights[order - 1]) {
// heights[order - 1] = 0;
// }
// heights[order - 1] += Math.ceil(parseFloat(height));
// });
// const maxHeight = Math.max(...heights);
// target.style.height = maxHeight + "px";
// }
function addBreakElements(target) {
const breakEls = target.querySelectorAll(".flexmasonry-break");
if (Array.from(breakEls).length === getCurrentCols(target) - 1) {
return;
}
for (let i = 1; i < getCurrentCols(target); i++) {
const breakDiv = document.createElement("div");
breakDiv.classList.add("flexmasonry-break");
breakDiv.classList.add("flexmasonry-break-" + i);
target.appendChild(breakDiv);
}
}
function removeBreakElements(target) {
const breakEls = target.querySelectorAll(".flexmasonry-break");
if (Array.from(breakEls).length === getCurrentCols(target) - 1) {
return;
}
Array.from(breakEls).forEach(function (breakEl) {
breakEl.parentNode.removeChild(breakEl);
});
}
function setColsClass(target) {
if (target.classList.contains("flexmasonry-cols-" + getCurrentCols(target))) {
return;
}
target.className = target.className.replace(/(flexmasonry-cols-\d+)/, "");
target.classList.add("flexmasonry-cols-" + getCurrentCols(target));
}
function getCurrentCols(target) {
if (!_options.responsive) {
return _options.numCols;
}
const descendingMinWidths = Object.keys(_options.breakpointCols)
.map((key) => Number(key))
.sort()
.reverse();
for (const minWidth of descendingMinWidths) {
if (target.clientWidth >= minWidth) {
return _options.breakpointCols[minWidth];
}
}
return 1;
}
function refresh(target, options = {}) {
_options = Object.assign(defaultOptions, options);
setColsClass(target);
removeBreakElements(target);
addBreakElements(target);
// setHeight(target);
return this;
}
function refreshAll(options = {}) {
_targets.forEach(function (target) {
refresh(target, options);
});
return this;
}
function destroyAll() {
removeEventListeners();
}
export default {
init,
refresh,
refreshAll,
destroyAll,
};
@@ -1,170 +0,0 @@
.flexmasonry {
display: flex;
flex-flow: column wrap;
align-content: space-between;
}
.flexmasonry-item {
width: 100%;
}
.flexmasonry-cols-2 .flexmasonry-item {
width: 50%;
}
.flexmasonry-cols-3 .flexmasonry-item {
width: 33.333%;
}
.flexmasonry-cols-4 .flexmasonry-item {
width: 25%;
}
.flexmasonry-cols-5 .flexmasonry-item {
width: 20%;
}
.flexmasonry-cols-6 .flexmasonry-item {
width: 16.666%;
}
.flexmasonry-cols-7 .flexmasonry-item {
width: 14.285%;
}
.flexmasonry-cols-8 .flexmasonry-item {
width: 12.5%;
}
.flexmasonry-cols-2 .flexmasonry-item:nth-child(2n + 1) {
order: 1;
}
.flexmasonry-cols-2 .flexmasonry-item:nth-child(2n) {
order: 2;
}
.flexmasonry-cols-3 .flexmasonry-item:nth-child(3n + 1) {
order: 1;
}
.flexmasonry-cols-3 .flexmasonry-item:nth-child(3n + 2) {
order: 2;
}
.flexmasonry-cols-3 .flexmasonry-item:nth-child(3n) {
order: 3;
}
.flexmasonry-cols-4 .flexmasonry-item:nth-child(4n + 1) {
order: 1;
}
.flexmasonry-cols-4 .flexmasonry-item:nth-child(4n + 2) {
order: 2;
}
.flexmasonry-cols-4 .flexmasonry-item:nth-child(4n + 3) {
order: 3;
}
.flexmasonry-cols-4 .flexmasonry-item:nth-child(4n) {
order: 4;
}
.flexmasonry-cols-5 .flexmasonry-item:nth-child(5n + 1) {
order: 1;
}
.flexmasonry-cols-5 .flexmasonry-item:nth-child(5n + 2) {
order: 2;
}
.flexmasonry-cols-5 .flexmasonry-item:nth-child(5n + 3) {
order: 3;
}
.flexmasonry-cols-5 .flexmasonry-item:nth-child(5n + 4) {
order: 4;
}
.flexmasonry-cols-5 .flexmasonry-item:nth-child(5n) {
order: 5;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n + 1) {
order: 1;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n + 2) {
order: 2;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n + 3) {
order: 3;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n + 4) {
order: 4;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n + 5) {
order: 5;
}
.flexmasonry-cols-6 .flexmasonry-item:nth-child(6n) {
order: 6;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 1) {
order: 1;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 2) {
order: 2;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 3) {
order: 3;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 4) {
order: 4;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 5) {
order: 5;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n + 6) {
order: 6;
}
.flexmasonry-cols-7 .flexmasonry-item:nth-child(7n) {
order: 7;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 1) {
order: 1;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 2) {
order: 2;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 3) {
order: 3;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 4) {
order: 4;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 5) {
order: 5;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 6) {
order: 6;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n + 7) {
order: 7;
}
.flexmasonry-cols-8 .flexmasonry-item:nth-child(8n) {
order: 8;
}
.flexmasonry-break {
content: "";
flex-basis: 100%;
width: 0 !important;
margin: 0;
}
.flexmasonry-break-1 {
order: 1;
}
.flexmasonry-break-2 {
order: 2;
}
.flexmasonry-break-3 {
order: 3;
}
.flexmasonry-break-4 {
order: 4;
}
.flexmasonry-break-5 {
order: 5;
}
.flexmasonry-break-6 {
order: 6;
}
.flexmasonry-break-7 {
order: 7;
}
-4
View File
@@ -14,12 +14,8 @@ self.addEventListener("install", (_event) => {
"/index.html",
"/assets/fonts/satoshi/2024-09/font.var.woff2",
"/scripts/main.js",
"/scripts/dashboard.js",
"/styles/dashboard.css",
"/scripts/chart.js",
"/styles/chart.css",
"/scripts/packages/flexmasonry/v0.2.3-modified/script.js",
"/scripts/packages/flexmasonry/v0.2.3-modified/style.css",
"/scripts/packages/lean-qr/v2.3.4/script.js",
"/scripts/packages/lightweight-charts/v4.2.0/script.js",
"/scripts/packages/solid-signals/2024-04-17/script.js",
+1 -31
View File
@@ -110,22 +110,6 @@ interface PartialHomeOption extends PartialOption {
name: "Home";
}
interface PartialDashboardOption extends PartialOption {
title: string;
description: string;
defaultOpen?: false;
groups: {
name: string;
unit?: Unit;
values: {
name: string;
path: LastPath;
unit?: Unit;
formatNumber?: false;
}[];
}[];
}
interface PartialChartOption extends PartialOption {
scale: TimeScale;
title: string;
@@ -147,19 +131,11 @@ interface PartialPdfOption extends PartialOption {
interface PartialOptionsGroup {
name: string;
tree: PartialOptionsTree;
dashboard?: {
skip?: true;
flatten?: true;
hopOver?: true;
separate?: true;
defaultOpen?: true;
};
}
type AnyPartialOption =
| PartialHomeOption
| PartialPdfOption
| PartialDashboardOption
| PartialChartOption;
type PartialOptionsTree = (AnyPartialOption | PartialOptionsGroup)[];
@@ -184,17 +160,11 @@ interface PdfOption extends PartialPdfOption, ProcessedOptionAddons {
title: string;
}
interface DashboardOption
extends PartialDashboardOption,
ProcessedOptionAddons {
kind: "dashboard";
}
interface ChartOption extends PartialChartOption, ProcessedOptionAddons {
kind: "chart";
}
type Option = HomeOption | PdfOption | DashboardOption | ChartOption;
type Option = HomeOption | PdfOption | ChartOption;
type OptionsTree = (Option | OptionsGroup)[];
-83
View File
@@ -1,83 +0,0 @@
#dashboard {
z-index: 50;
margin: -0.5px calc(-1.5rem - 1px);
display: flex;
> details {
> summary {
margin: -0.5px;
display: block;
padding: 0.5rem 1.5rem;
text-align: left;
border: 1px;
details[open] > & {
border-bottom-style: dashed !important;
border-bottom-width: 1px;
}
}
> div {
border: 1px;
border-top-width: 0px;
margin: -0.5px;
width: calc(100% + 1px);
padding: 0.375rem 1.5rem;
summary,
td {
padding: 0.125rem 0;
}
details {
summary {
color: var(--off-color);
&:hover {
color: var(--orange);
}
}
div {
width: 100%;
padding-left: 0.75rem;
border-left-width: 1px;
border-left-style: dashed !important;
}
}
table {
width: 100%;
table-layout: auto;
tr {
width: 100%;
&:not(:has(details)) {
&:hover,
&:hover * {
color: var(--orange) !important;
}
}
td {
text-align: right;
&:first-child {
text-align: left;
color: var(--off-color);
}
> a {
color: var(--off-color);
}
> i {
color: var(--off-color);
}
}
}
}
}
}
}