mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-20 03:34:21 -07:00
global: snapshot
This commit is contained in:
@@ -653,7 +653,10 @@ export function createChartElement({
|
||||
({ count, active }) => {
|
||||
showLine = count > 500;
|
||||
candlestickISeries.applyOptions({ visible: active && !showLine });
|
||||
lineISeries.applyOptions({ visible: active && showLine });
|
||||
lineISeries.applyOptions({
|
||||
visible: active && showLine,
|
||||
priceLineVisible: active && showLine,
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
* @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint
|
||||
* @typedef {Brk.AnyMetricData} AnyMetricData
|
||||
* @typedef {Brk.AddrCountPattern} AddrCountPattern
|
||||
* @typedef {Brk.MetricsTree_Blocks_Interval} IntervalPattern
|
||||
* @typedef {FullnessPattern<any>} IntervalPattern
|
||||
* @typedef {Brk.MetricsTree_Supply_Circulating} SupplyPattern
|
||||
* @typedef {Brk.RelativePattern} GlobalRelativePattern
|
||||
* @typedef {Brk.RelativePattern2} OwnRelativePattern
|
||||
|
||||
@@ -545,6 +545,11 @@ signals.createRoot(() => {
|
||||
function initShare() {
|
||||
const shareDiv = getElementById("share-div");
|
||||
const shareContentDiv = getElementById("share-content-div");
|
||||
const shareButton = getElementById("share-button");
|
||||
|
||||
shareButton.addEventListener("click", () => {
|
||||
qrcode.set(window.location.href);
|
||||
});
|
||||
|
||||
shareDiv.addEventListener("click", () => {
|
||||
qrcode.set(null);
|
||||
|
||||
@@ -12,6 +12,7 @@ export function createChainSection(ctx) {
|
||||
colors,
|
||||
brk,
|
||||
line,
|
||||
baseline,
|
||||
dots,
|
||||
createPriceLine,
|
||||
fromSizePattern,
|
||||
@@ -638,6 +639,17 @@ export function createChainSection(ctx) {
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Adjustment",
|
||||
title: "Difficulty Adjustment",
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: blocks.difficulty.adjustment,
|
||||
name: "Difficulty Change",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Hash Price",
|
||||
title: "Hash Price",
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ltAmountColors,
|
||||
amountRangeColors,
|
||||
spendableTypeColors,
|
||||
yearColors,
|
||||
} from "../colors/index.js";
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,7 @@ export function buildCohortData(colors, brk) {
|
||||
LT_AMOUNT_NAMES,
|
||||
AMOUNT_RANGE_NAMES,
|
||||
SPENDABLE_TYPE_NAMES,
|
||||
YEAR_NAMES,
|
||||
} = brk;
|
||||
|
||||
// Base cohort representing "all" - CohortAll (adjustedSopr + percentiles but no RelToMarketCap)
|
||||
@@ -210,6 +212,18 @@ export function buildCohortData(colors, brk) {
|
||||
};
|
||||
});
|
||||
|
||||
// Year cohorts - CohortBasic (neither adjustedSopr nor percentiles)
|
||||
/** @type {readonly CohortBasic[]} */
|
||||
const year = entries(utxoCohorts.year).map(([key, tree]) => {
|
||||
const names = YEAR_NAMES[key];
|
||||
return {
|
||||
name: names.short,
|
||||
title: names.long,
|
||||
color: colors[yearColors[key]],
|
||||
tree,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
cohortAll,
|
||||
termShort,
|
||||
@@ -225,5 +239,6 @@ export function buildCohortData(colors, brk) {
|
||||
utxosAmountRanges,
|
||||
addressesAmountRanges,
|
||||
type,
|
||||
year,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,28 +139,102 @@ function createCointimePriceWithRatioOptions(
|
||||
},
|
||||
{
|
||||
name: "ZScores",
|
||||
tree: sdPatterns.map(({ nameAddon, titleAddon, sd }) => ({
|
||||
name: nameAddon,
|
||||
title: `${title} ${titleAddon} Z-Score`,
|
||||
top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
),
|
||||
bottom: [
|
||||
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
|
||||
createPriceLine({ unit: Unit.sd, number: 3 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 0 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -3 }),
|
||||
],
|
||||
})),
|
||||
tree: [
|
||||
// Compare all Z-Scores
|
||||
{
|
||||
name: "Compare",
|
||||
title: `Compare ${title} Z-Scores`,
|
||||
top: [
|
||||
line({ metric: price, name: legend, color, unit: Unit.usd }),
|
||||
line({
|
||||
metric: ratio.ratio1ySd._0sdUsd,
|
||||
name: "1y 0sd",
|
||||
color: colors.fuchsia,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio2ySd._0sdUsd,
|
||||
name: "2y 0sd",
|
||||
color: colors.purple,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd._0sdUsd,
|
||||
name: "4y 0sd",
|
||||
color: colors.violet,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratioSd._0sdUsd,
|
||||
name: "0sd",
|
||||
color: colors.indigo,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
],
|
||||
bottom: [
|
||||
line({
|
||||
metric: ratio.ratioSd.zscore,
|
||||
name: "All",
|
||||
color: colors.default,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd.zscore,
|
||||
name: "4y",
|
||||
color: colors.lime,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio2ySd.zscore,
|
||||
name: "2y",
|
||||
color: colors.avocado,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1ySd.zscore,
|
||||
name: "1y",
|
||||
color: colors.yellow,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.sd, number: 4 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 3 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 0 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -3 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -4 }),
|
||||
],
|
||||
},
|
||||
// Individual Z-Score charts
|
||||
...sdPatterns.map(({ nameAddon, titleAddon, sd }) => ({
|
||||
name: nameAddon,
|
||||
title: `${title} ${titleAddon} Z-Score`,
|
||||
top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
),
|
||||
bottom: [
|
||||
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
|
||||
createPriceLine({ unit: Unit.sd, number: 3 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: 0 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -1 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -2 }),
|
||||
createPriceLine({ unit: Unit.sd, number: -3 }),
|
||||
],
|
||||
})),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -150,3 +150,25 @@ export const spendableTypeColors = {
|
||||
unknown: "violet",
|
||||
empty: "fuchsia",
|
||||
};
|
||||
|
||||
/** @type {Readonly<Record<string, ColorName>>} */
|
||||
export const yearColors = {
|
||||
_2009: "red",
|
||||
_2010: "orange",
|
||||
_2011: "amber",
|
||||
_2012: "yellow",
|
||||
_2013: "lime",
|
||||
_2014: "green",
|
||||
_2015: "teal",
|
||||
_2016: "cyan",
|
||||
_2017: "sky",
|
||||
_2018: "blue",
|
||||
_2019: "indigo",
|
||||
_2020: "violet",
|
||||
_2021: "purple",
|
||||
_2022: "fuchsia",
|
||||
_2023: "pink",
|
||||
_2024: "rose",
|
||||
_2025: "red",
|
||||
_2026: "orange",
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ export {
|
||||
ltAmountColors,
|
||||
amountRangeColors,
|
||||
spendableTypeColors,
|
||||
yearColors,
|
||||
} from "./cohorts.js";
|
||||
|
||||
export { averageColors, dcaColors } from "./misc.js";
|
||||
|
||||
+187
-242
@@ -1,6 +1,5 @@
|
||||
/** Partial options - Main entry point */
|
||||
|
||||
import { localhost } from "../utils/env.js";
|
||||
import { createContext } from "./context.js";
|
||||
import {
|
||||
buildCohortData,
|
||||
@@ -45,6 +44,7 @@ export function createPartialOptions({ colors, brk }) {
|
||||
utxosAmountRanges,
|
||||
addressesAmountRanges,
|
||||
type,
|
||||
year,
|
||||
} = buildCohortData(colors, brk);
|
||||
|
||||
// Helpers to map cohorts by capability type
|
||||
@@ -58,16 +58,16 @@ export function createPartialOptions({ colors, brk }) {
|
||||
const mapAddressCohorts = (cohort) => createAddressCohortFolder(ctx, cohort);
|
||||
|
||||
return [
|
||||
// Debug explorer (localhost only)
|
||||
...(localhost
|
||||
? [
|
||||
{
|
||||
kind: /** @type {const} */ ("explorer"),
|
||||
name: "Explorer",
|
||||
title: "Debug explorer",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
// Debug explorer (disabled)
|
||||
// ...(localhost
|
||||
// ? [
|
||||
// {
|
||||
// kind: /** @type {const} */ ("explorer"),
|
||||
// name: "Explorer",
|
||||
// title: "Debug explorer",
|
||||
// },
|
||||
// ]
|
||||
// : []),
|
||||
|
||||
// Charts section
|
||||
{
|
||||
@@ -88,7 +88,7 @@ export function createPartialOptions({ colors, brk }) {
|
||||
|
||||
// Terms (STH/LTH) - Short is Full, Long is WithPercentiles
|
||||
{
|
||||
name: "terms",
|
||||
name: "Terms",
|
||||
tree: [
|
||||
// Individual cohorts with their specific capabilities
|
||||
createCohortFolderFull(ctx, termShort),
|
||||
@@ -96,7 +96,149 @@ export function createPartialOptions({ colors, brk }) {
|
||||
],
|
||||
},
|
||||
|
||||
// Epochs - CohortBasic (neither adjustedSopr nor percentiles)
|
||||
// Types - CohortBasic
|
||||
{
|
||||
name: "Types",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Type",
|
||||
list: type,
|
||||
}),
|
||||
...type.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// Age cohorts
|
||||
{
|
||||
name: "Age",
|
||||
tree: [
|
||||
// Up To (< X old)
|
||||
{
|
||||
name: "Up To",
|
||||
tree: [
|
||||
createCohortFolderWithAdjusted(ctx, {
|
||||
name: "Compare",
|
||||
title: "Age Up To",
|
||||
list: upToDate,
|
||||
}),
|
||||
...upToDate.map(mapWithAdjusted),
|
||||
],
|
||||
},
|
||||
// At Least (≥ X old)
|
||||
{
|
||||
name: "At Least",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Age At Least",
|
||||
list: fromDate,
|
||||
}),
|
||||
...fromDate.map(mapBasic),
|
||||
],
|
||||
},
|
||||
// Range
|
||||
{
|
||||
name: "Range",
|
||||
tree: [
|
||||
createCohortFolderWithPercentiles(ctx, {
|
||||
name: "Compare",
|
||||
title: "Age Range",
|
||||
list: dateRange,
|
||||
}),
|
||||
...dateRange.map(mapWithPercentiles),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Amount cohorts (UTXO size)
|
||||
{
|
||||
name: "Amount",
|
||||
tree: [
|
||||
// Under (< X sats)
|
||||
{
|
||||
name: "Under",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Amount Under",
|
||||
list: utxosUnderAmount,
|
||||
}),
|
||||
...utxosUnderAmount.map(mapBasic),
|
||||
],
|
||||
},
|
||||
// Above (≥ X sats)
|
||||
{
|
||||
name: "Above",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Amount Above",
|
||||
list: utxosAboveAmount,
|
||||
}),
|
||||
...utxosAboveAmount.map(mapBasic),
|
||||
],
|
||||
},
|
||||
// Range
|
||||
{
|
||||
name: "Range",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Amount Range",
|
||||
list: utxosAmountRanges,
|
||||
}),
|
||||
...utxosAmountRanges.map(mapBasic),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Balance cohorts (Address balance)
|
||||
{
|
||||
name: "Balance",
|
||||
tree: [
|
||||
// Under (< X sats)
|
||||
{
|
||||
name: "Under",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Balance Under",
|
||||
list: addressesUnderAmount,
|
||||
}),
|
||||
...addressesUnderAmount.map(mapAddressCohorts),
|
||||
],
|
||||
},
|
||||
// Above (≥ X sats)
|
||||
{
|
||||
name: "Above",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Balance Above",
|
||||
list: addressesAboveAmount,
|
||||
}),
|
||||
...addressesAboveAmount.map(mapAddressCohorts),
|
||||
],
|
||||
},
|
||||
// Range
|
||||
{
|
||||
name: "Range",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Balance Range",
|
||||
list: addressesAmountRanges,
|
||||
}),
|
||||
...addressesAmountRanges.map(mapAddressCohorts),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Epochs - CohortBasic
|
||||
{
|
||||
name: "Epochs",
|
||||
tree: [
|
||||
@@ -109,133 +251,16 @@ export function createPartialOptions({ colors, brk }) {
|
||||
],
|
||||
},
|
||||
|
||||
// Types - CohortBasic
|
||||
// Years - CohortBasic
|
||||
{
|
||||
name: "types",
|
||||
name: "Years",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "Type",
|
||||
list: type,
|
||||
title: "Year",
|
||||
list: year,
|
||||
}),
|
||||
...type.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs Up to age - CohortWithAdjusted (adjustedSopr only)
|
||||
{
|
||||
name: "UTXOs Up to age",
|
||||
tree: [
|
||||
createCohortFolderWithAdjusted(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs Up To Age",
|
||||
list: upToDate,
|
||||
}),
|
||||
...upToDate.map(mapWithAdjusted),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs from age - CohortBasic
|
||||
{
|
||||
name: "UTXOs from age",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs from age",
|
||||
list: fromDate,
|
||||
}),
|
||||
...fromDate.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs age ranges - CohortWithPercentiles (percentiles only)
|
||||
{
|
||||
name: "UTXOs age Ranges",
|
||||
tree: [
|
||||
createCohortFolderWithPercentiles(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs Age Range",
|
||||
list: dateRange,
|
||||
}),
|
||||
...dateRange.map(mapWithPercentiles),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs under amounts - CohortBasic
|
||||
{
|
||||
name: "UTXOs under amounts",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs under amount",
|
||||
list: utxosUnderAmount,
|
||||
}),
|
||||
...utxosUnderAmount.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs above amounts - CohortBasic
|
||||
{
|
||||
name: "UTXOs Above Amounts",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs Above Amount",
|
||||
list: utxosAboveAmount,
|
||||
}),
|
||||
...utxosAboveAmount.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// UTXOs between amounts - CohortBasic
|
||||
{
|
||||
name: "UTXOs between amounts",
|
||||
tree: [
|
||||
createCohortFolderBasic(ctx, {
|
||||
name: "Compare",
|
||||
title: "UTXOs between amounts",
|
||||
list: utxosAmountRanges,
|
||||
}),
|
||||
...utxosAmountRanges.map(mapBasic),
|
||||
],
|
||||
},
|
||||
|
||||
// Addresses under amount (TYPE SAFE - uses createAddressCohortFolder!)
|
||||
{
|
||||
name: "Addresses under amount",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Addresses under Amount",
|
||||
list: addressesUnderAmount,
|
||||
}),
|
||||
...addressesUnderAmount.map(mapAddressCohorts),
|
||||
],
|
||||
},
|
||||
|
||||
// Addresses above amount (TYPE SAFE - uses createAddressCohortFolder!)
|
||||
{
|
||||
name: "Addresses above amount",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Addresses above amount",
|
||||
list: addressesAboveAmount,
|
||||
}),
|
||||
...addressesAboveAmount.map(mapAddressCohorts),
|
||||
],
|
||||
},
|
||||
|
||||
// Addresses between amounts (TYPE SAFE - uses createAddressCohortFolder!)
|
||||
{
|
||||
name: "Addresses between amounts",
|
||||
tree: [
|
||||
createAddressCohortFolder(ctx, {
|
||||
name: "Compare",
|
||||
title: "Addresses between amounts",
|
||||
list: addressesAmountRanges,
|
||||
}),
|
||||
...addressesAmountRanges.map(mapAddressCohorts),
|
||||
...year.map(mapBasic),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -246,117 +271,37 @@ export function createPartialOptions({ colors, brk }) {
|
||||
],
|
||||
},
|
||||
|
||||
// Table section
|
||||
// Table section (disabled)
|
||||
// {
|
||||
// kind: /** @type {const} */ ("table"),
|
||||
// title: "Table",
|
||||
// name: "Table",
|
||||
// },
|
||||
|
||||
// Simulations section (disabled)
|
||||
// {
|
||||
// name: "Simulations",
|
||||
// tree: [
|
||||
// {
|
||||
// kind: /** @type {const} */ ("simulation"),
|
||||
// name: "Save In Bitcoin",
|
||||
// title: "Save In Bitcoin",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// API documentation
|
||||
{
|
||||
kind: /** @type {const} */ ("table"),
|
||||
title: "Table",
|
||||
name: "Table",
|
||||
name: "API",
|
||||
url: () => "/api",
|
||||
title: "API documentation",
|
||||
},
|
||||
|
||||
// Simulations section
|
||||
// Project link
|
||||
{
|
||||
name: "Simulations",
|
||||
tree: [
|
||||
{
|
||||
kind: /** @type {const} */ ("simulation"),
|
||||
name: "Save In Bitcoin",
|
||||
title: "Save In Bitcoin",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Tools section
|
||||
{
|
||||
name: "Tools",
|
||||
tree: [
|
||||
{
|
||||
name: "Documentation",
|
||||
tree: [
|
||||
{
|
||||
name: "API",
|
||||
url: () => "/api",
|
||||
title: "API documentation",
|
||||
},
|
||||
{
|
||||
name: "MCP",
|
||||
url: () =>
|
||||
"https://github.com/bitcoinresearchkit/brk/blob/main/crates/brk_mcp/README.md#brk_mcp",
|
||||
title: "Model Context Protocol documentation",
|
||||
},
|
||||
{
|
||||
name: "Crate",
|
||||
url: () => "/crate",
|
||||
title: "View on crates.io",
|
||||
},
|
||||
{
|
||||
name: "Source",
|
||||
url: () => "/github",
|
||||
title: "Source code and issues",
|
||||
},
|
||||
{
|
||||
name: "Changelog",
|
||||
url: () => "/changelog",
|
||||
title: "Release notes and changelog",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Hosting",
|
||||
tree: [
|
||||
{
|
||||
name: "Status",
|
||||
url: () => "/status",
|
||||
title: "Service status and uptime",
|
||||
},
|
||||
{
|
||||
name: "Self-host",
|
||||
url: () => "/install",
|
||||
title: "Install and run yourself",
|
||||
},
|
||||
{
|
||||
name: "Service",
|
||||
url: () => "/service",
|
||||
title: "Hosted service offering",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Community",
|
||||
tree: [
|
||||
{
|
||||
name: "Discord",
|
||||
url: () => "/discord",
|
||||
title: "Join the Discord server",
|
||||
},
|
||||
{
|
||||
name: "GitHub",
|
||||
url: () => "/github",
|
||||
title: "Source code and issues",
|
||||
},
|
||||
{
|
||||
name: "Nostr",
|
||||
url: () => "/nostr",
|
||||
title: "Follow on Nostr",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Donate
|
||||
{
|
||||
name: "Donate",
|
||||
qrcode: true,
|
||||
url: () => "bitcoin:bc1q098zsm89m7kgyze338vfejhpdt92ua9p3peuve",
|
||||
title: "Bitcoin address for donations",
|
||||
},
|
||||
|
||||
// Share
|
||||
{
|
||||
name: "Share",
|
||||
qrcode: true,
|
||||
url: () => window.location.href,
|
||||
title: "Share",
|
||||
name: "Source",
|
||||
url: () => "https://bitcoinresearchkit.org",
|
||||
title: "Bitcoin Research Kit",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Unit } from "../../utils/units.js";
|
||||
import signals from "../../signals.js";
|
||||
import { createChartElement } from "../../chart/index.js";
|
||||
import { webSockets } from "../../utils/ws.js";
|
||||
import { screenshot } from "./screenshot.js";
|
||||
|
||||
const keyPrefix = "chart";
|
||||
const ONE_BTC_IN_SATS = 100_000_000;
|
||||
@@ -82,21 +83,20 @@ export function init({ colors, option, brk }) {
|
||||
});
|
||||
|
||||
if (!(ios && !canShare)) {
|
||||
const chartBottomRightCanvas = Array.from(
|
||||
chart.inner.chartElement().getElementsByTagName("tr"),
|
||||
).at(-1)?.lastChild?.firstChild?.firstChild;
|
||||
if (chartBottomRightCanvas) {
|
||||
const domain = window.document.createElement("p");
|
||||
domain.innerText = `${window.location.host}`;
|
||||
domain.id = "domain";
|
||||
const screenshotButton = window.document.createElement("button");
|
||||
screenshotButton.id = "screenshot";
|
||||
const camera = "[ ◉¯]";
|
||||
screenshotButton.innerHTML = camera;
|
||||
screenshotButton.title = "Screenshot";
|
||||
chartBottomRightCanvas.replaceWith(screenshotButton);
|
||||
screenshotButton.addEventListener("click", () => {
|
||||
import("./screenshot").then(async ({ screenshot }) => {
|
||||
const domain = window.document.createElement("p");
|
||||
domain.innerText = `${window.location.host}`;
|
||||
domain.id = "domain";
|
||||
|
||||
chart.addFieldsetIfNeeded({
|
||||
id: "capture",
|
||||
paneIndex: 0,
|
||||
position: "ne",
|
||||
createChild() {
|
||||
const button = window.document.createElement("button");
|
||||
button.id = "capture";
|
||||
button.innerText = "capture";
|
||||
button.title = "Capture chart as image";
|
||||
button.addEventListener("click", async () => {
|
||||
chartElement.dataset.screenshot = "true";
|
||||
chartElement.append(domain);
|
||||
try {
|
||||
@@ -109,8 +109,9 @@ export function init({ colors, option, brk }) {
|
||||
chartElement.removeChild(domain);
|
||||
chartElement.dataset.screenshot = "false";
|
||||
});
|
||||
});
|
||||
}
|
||||
return button;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
chart.inner.timeScale().subscribeVisibleLogicalRangeChange(
|
||||
|
||||
Reference in New Issue
Block a user