mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-27 01:54:47 -07:00
297 lines
7.6 KiB
TypeScript
297 lines
7.6 KiB
TypeScript
import { createRWS } from "/src/solid/rws";
|
|
|
|
import { colors } from "../utils/colors";
|
|
import { replaceHistory } from "../utils/history";
|
|
import { stringToId } from "../utils/id";
|
|
import { resetURLParams } from "../utils/urlParams";
|
|
import { createPresets as createAddressesPresets } from "./addresses";
|
|
import { createPresets as createBlocksPresets } from "./blocks";
|
|
import { createPresets as createCoinblocksPresets } from "./coinblocks";
|
|
import { createPresets as createHodlersPresets } from "./hodlers";
|
|
import { createPresets as createMarketPresets } from "./market";
|
|
import { createPresets as createMinersPresets } from "./miners";
|
|
import { createCohortPresetList } from "./templates/cohort";
|
|
import { createPresets as createTransactionsPresets } from "./transactions";
|
|
|
|
export const LOCAL_STORAGE_FAVORITES_KEY = "favorites";
|
|
export const LOCAL_STORAGE_FOLDERS_KEY = "folders";
|
|
export const LOCAL_STORAGE_HISTORY_KEY = "history";
|
|
export const LOCAL_STORAGE_SELECTED_KEY = "preset";
|
|
export const LOCAL_STORAGE_VISITED_KEY = "visited";
|
|
|
|
export function createPresets(datasets: Datasets): Presets {
|
|
const partialTree = [
|
|
{
|
|
name: "Dashboards (Coming soon)",
|
|
tree: [],
|
|
},
|
|
{
|
|
name: "Charts",
|
|
tree: [
|
|
{
|
|
name: "By Date",
|
|
tree: [
|
|
createMarketPresets({ scale: "date", datasets }),
|
|
createBlocksPresets(),
|
|
createMinersPresets("date"),
|
|
createTransactionsPresets("date"),
|
|
...createCohortPresetList({
|
|
datasets,
|
|
scale: "date",
|
|
color: colors.bitcoin,
|
|
datasetKey: "",
|
|
name: "",
|
|
title: "",
|
|
}),
|
|
createHodlersPresets({ scale: "date", datasets }),
|
|
createAddressesPresets({ scale: "date", datasets }),
|
|
createCoinblocksPresets({ scale: "date", datasets }),
|
|
],
|
|
} satisfies PartialPresetFolder,
|
|
{
|
|
name: "By Height (Coming soon)",
|
|
tree: [
|
|
// createMarketPresets({ scale: "height", datasets }),
|
|
// createMinersPresets("height"),
|
|
// createTransactionsPresets("height"),
|
|
// ...createCohortPresetList({
|
|
// datasets,
|
|
// scale: "height",
|
|
// color: colors.bitcoin,
|
|
// name: "",
|
|
// datasetKey: "",
|
|
// title: "",
|
|
// }),
|
|
// createHodlersPresets({ scale: "height", datasets }),
|
|
// createAddressesPresets({ scale: "height", datasets }),
|
|
// createCoinblocksPresets({ scale: "height", datasets }),
|
|
],
|
|
} satisfies PartialPresetFolder,
|
|
],
|
|
},
|
|
];
|
|
|
|
const { list, ids, tree } = flatten(partialTree);
|
|
|
|
checkIfDuplicateIds(ids);
|
|
|
|
setIsFavorites(list);
|
|
|
|
setVisited(list);
|
|
|
|
const favorites = createMemo(() =>
|
|
list.filter((preset) => preset.isFavorite()),
|
|
);
|
|
|
|
createEffect(() => {
|
|
localStorage.setItem(
|
|
LOCAL_STORAGE_FAVORITES_KEY,
|
|
JSON.stringify(favorites().map((p) => p.id)),
|
|
);
|
|
});
|
|
|
|
const visited = createMemo(() => list.filter((preset) => preset.visited()));
|
|
|
|
createEffect(() => {
|
|
localStorage.setItem(
|
|
LOCAL_STORAGE_VISITED_KEY,
|
|
JSON.stringify(visited().map((p) => p.id)),
|
|
);
|
|
});
|
|
|
|
createEffect(() => {
|
|
const serializedHistory: SerializedPresetsHistory = history().map(
|
|
({ preset, date }) => ({
|
|
p: preset.id,
|
|
d: date.valueOf(),
|
|
}),
|
|
);
|
|
|
|
localStorage.setItem(
|
|
LOCAL_STORAGE_HISTORY_KEY,
|
|
JSON.stringify(serializedHistory),
|
|
);
|
|
});
|
|
|
|
const history: PresetsHistorySignal = createRWS(getHistory(list), {
|
|
equals: false,
|
|
});
|
|
|
|
const selected = createRWS(findInitialPreset(list), {
|
|
equals: false,
|
|
});
|
|
|
|
createEffect((previousPreset: Preset) => {
|
|
if (previousPreset && previousPreset !== selected()) {
|
|
resetURLParams();
|
|
}
|
|
return selected();
|
|
}, selected());
|
|
|
|
createEffect(() => selected().visited.set(true));
|
|
|
|
const select = (preset: Preset) => {
|
|
if (selected().id === preset.id) {
|
|
return;
|
|
}
|
|
|
|
history.set((l) => {
|
|
l.unshift({
|
|
date: new Date(),
|
|
preset,
|
|
});
|
|
return l;
|
|
});
|
|
|
|
_select(preset, selected.set);
|
|
};
|
|
|
|
const openedFolders = createRWS(
|
|
new Set(
|
|
JSON.parse(
|
|
localStorage.getItem(LOCAL_STORAGE_FOLDERS_KEY) || "[]",
|
|
) as string[],
|
|
),
|
|
{
|
|
equals: false,
|
|
},
|
|
);
|
|
|
|
createEffect(() => {
|
|
localStorage.setItem(
|
|
LOCAL_STORAGE_FOLDERS_KEY,
|
|
JSON.stringify(Array.from(openedFolders())),
|
|
);
|
|
});
|
|
|
|
return {
|
|
tree,
|
|
list,
|
|
selected,
|
|
favorites,
|
|
history,
|
|
select,
|
|
openedFolders,
|
|
};
|
|
}
|
|
|
|
function _select(preset: Preset, set: Setter<Preset>) {
|
|
const key = LOCAL_STORAGE_SELECTED_KEY;
|
|
const value = preset.id;
|
|
|
|
localStorage.setItem(key, value);
|
|
|
|
replaceHistory({ pathname: `/${value}` });
|
|
|
|
set(preset);
|
|
}
|
|
|
|
function flatten(partialTree: PartialPresetTree) {
|
|
const result: { list: Preset[]; ids: string[] } = { list: [], ids: [] };
|
|
|
|
const _flatten = (partialTree: PartialPresetTree, path?: FilePath) => {
|
|
partialTree.forEach((anyPreset) => {
|
|
if ("tree" in anyPreset) {
|
|
const id = stringToId(
|
|
`${(path || [])?.map(({ name }) => name).join(" ")} ${anyPreset.name} folder`,
|
|
);
|
|
|
|
const presetFolder: PresetFolder = {
|
|
...anyPreset,
|
|
tree: anyPreset.tree as PresetTree,
|
|
id,
|
|
};
|
|
|
|
Object.assign(anyPreset, presetFolder);
|
|
|
|
result.ids.push(presetFolder.id);
|
|
|
|
return _flatten(presetFolder.tree, [
|
|
...(path || []),
|
|
{
|
|
name: presetFolder.name,
|
|
id: presetFolder.id,
|
|
},
|
|
]);
|
|
} else {
|
|
const preset = {
|
|
...anyPreset,
|
|
path: path || [],
|
|
isFavorite: createRWS(false),
|
|
visited: createRWS(false),
|
|
id: `${anyPreset.scale}-to-${stringToId(anyPreset.title)}`,
|
|
} satisfies Preset;
|
|
|
|
result.list.push(Object.assign(anyPreset, preset));
|
|
result.ids.push(preset.id);
|
|
}
|
|
});
|
|
};
|
|
|
|
_flatten(partialTree);
|
|
|
|
return { ...result, tree: partialTree as PresetTree };
|
|
}
|
|
|
|
function checkIfDuplicateIds(ids: string[]) {
|
|
if (ids.length !== new Set(ids).size) {
|
|
const m = new Map<string, number>();
|
|
|
|
ids.forEach((id) => {
|
|
m.set(id, (m.get(id) || 0) + 1);
|
|
});
|
|
|
|
console.log(
|
|
[...m.entries()].filter(([_, value]) => value > 1).map(([key, _]) => key),
|
|
);
|
|
|
|
throw Error("ID duplicate");
|
|
}
|
|
}
|
|
|
|
function findInitialPreset(presets: Preset[]): Preset {
|
|
const urlPreset = document.location.pathname.substring(1);
|
|
|
|
return (
|
|
(urlPreset &&
|
|
(presets.find((preset) => preset.id === urlPreset) ||
|
|
presets.find(
|
|
(preset) =>
|
|
preset.id === localStorage.getItem(LOCAL_STORAGE_SELECTED_KEY),
|
|
))) ||
|
|
presets[0]
|
|
);
|
|
}
|
|
|
|
function setIsFavorites(list: Preset[]) {
|
|
(
|
|
JSON.parse(
|
|
localStorage.getItem(LOCAL_STORAGE_FAVORITES_KEY) || "[]",
|
|
) as string[]
|
|
).forEach((id) => {
|
|
list.find((preset) => preset.id === id)?.isFavorite.set(true);
|
|
});
|
|
}
|
|
|
|
function setVisited(list: Preset[]) {
|
|
(
|
|
JSON.parse(
|
|
localStorage.getItem(LOCAL_STORAGE_VISITED_KEY) || "[]",
|
|
) as string[]
|
|
).forEach((id) => {
|
|
list.find((preset) => preset.id === id)?.visited.set(true);
|
|
});
|
|
}
|
|
|
|
function getHistory(list: Preset[]): PresetsHistory {
|
|
return (
|
|
JSON.parse(
|
|
localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY) || "[]",
|
|
) as SerializedPresetsHistory
|
|
).flatMap(({ p, d }) => {
|
|
const preset = list.find((preset) => preset.id === p);
|
|
|
|
return preset ? [{ preset, date: new Date(d) }] : [];
|
|
});
|
|
}
|