mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-19 19:26:12 -07:00
website: chart style changes
This commit is contained in:
+167
-94
@@ -190,11 +190,8 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
|
||||
setup() {
|
||||
elements.root.classList.add("chart");
|
||||
elements.chart.classList.add("lightweight-chart");
|
||||
parent.append(elements.root);
|
||||
elements.root.append(legends.top.element);
|
||||
elements.root.append(elements.chart);
|
||||
elements.root.append(legends.bottom.element);
|
||||
},
|
||||
};
|
||||
elements.setup();
|
||||
@@ -220,6 +217,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
borderVisible: false,
|
||||
},
|
||||
timeScale: {
|
||||
// borderColor: colors.border(),
|
||||
borderVisible: false,
|
||||
enableConflation: true,
|
||||
...(fitContent
|
||||
@@ -306,6 +304,9 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
separatorColor: borderColor,
|
||||
},
|
||||
},
|
||||
timeScale: {
|
||||
// borderColor: colors.border(),
|
||||
},
|
||||
crosshair: {
|
||||
horzLine: {
|
||||
color: offColor,
|
||||
@@ -415,28 +416,6 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
seriesByHome: new Map(),
|
||||
pendingVisibilityCheck: false,
|
||||
|
||||
/** @param {number} homePane */
|
||||
isAllHidden(homePane) {
|
||||
const map = this.seriesByHome.get(homePane);
|
||||
return !map || [...map.keys()].every((s) => !s.active.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} homePane
|
||||
* @param {number} targetPane
|
||||
*/
|
||||
moveTo(homePane, targetPane) {
|
||||
const map = this.seriesByHome.get(homePane);
|
||||
if (!map) return;
|
||||
for (const iseries of map.values()) {
|
||||
for (const is of iseries) {
|
||||
if (is.getPane().paneIndex() !== targetPane) {
|
||||
is.moveToPane(targetPane);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} paneIndex
|
||||
* @param {VoidFunction} callback
|
||||
@@ -454,26 +433,55 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
}
|
||||
},
|
||||
|
||||
updateVisibility() {
|
||||
const pane0Hidden = this.isAllHidden(0);
|
||||
const pane1Hidden = this.isAllHidden(1);
|
||||
const bothVisible = !pane0Hidden && !pane1Hidden;
|
||||
/** @param {number} targetPaneIndex @param {Legend} legend */
|
||||
injectLegend(targetPaneIndex, legend) {
|
||||
const pane = ichart.panes().at(targetPaneIndex);
|
||||
const parent = pane?.getHTMLElement()?.children?.item(1)?.firstChild;
|
||||
if (!parent) return;
|
||||
parent.appendChild(legend.element);
|
||||
},
|
||||
|
||||
this.moveTo(1, bothVisible ? 1 : 0);
|
||||
initialized: false,
|
||||
|
||||
if (bothVisible) {
|
||||
setup() {
|
||||
if (this.initialized) return;
|
||||
this.initialized = true;
|
||||
|
||||
this.whenReady(0, () => {
|
||||
const pane0 = ichart.panes().at(0);
|
||||
fieldsets.createForPane(0);
|
||||
this.injectLegend(0, legends.top);
|
||||
if (pane0) injectScaleSelector(0, pane0);
|
||||
this.updateSize(0);
|
||||
});
|
||||
|
||||
if (this.seriesByHome.has(1)) {
|
||||
this.whenReady(1, () => {
|
||||
fieldsets.createForPane(0);
|
||||
const pane1 = ichart.panes().at(1);
|
||||
fieldsets.createForPane(1);
|
||||
this.injectLegend(1, legends.bottom);
|
||||
if (pane1) injectScaleSelector(1, pane1);
|
||||
this.updateSize(1);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/** @param {number} homePane */
|
||||
isAllHidden(homePane) {
|
||||
const map = this.seriesByHome.get(homePane);
|
||||
return !map || [...map.keys()].every((s) => !s.active.value);
|
||||
},
|
||||
|
||||
/** @param {number} paneIndex */
|
||||
updateSize(paneIndex) {
|
||||
const pane = ichart.panes().at(paneIndex);
|
||||
if (!pane) return;
|
||||
const hidden = this.isAllHidden(paneIndex);
|
||||
if (hidden) {
|
||||
const chartHeight = ichart.chartElement().clientHeight;
|
||||
pane.setStretchFactor(chartHeight > 0 ? 32 / (chartHeight - 32) : 0);
|
||||
} else {
|
||||
this.whenReady(0, () => {
|
||||
if (pane0Hidden && !pane1Hidden) {
|
||||
fieldsets.createForPane(1, 0);
|
||||
} else {
|
||||
fieldsets.createForPane(0);
|
||||
}
|
||||
});
|
||||
pane.setStretchFactor(1);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -494,7 +502,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
this.pendingVisibilityCheck = true;
|
||||
requestAnimationFrame(() => {
|
||||
this.pendingVisibilityCheck = false;
|
||||
this.updateVisibility();
|
||||
this.setup();
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -588,7 +596,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
if (value && !wasActive) {
|
||||
state.fetch?.();
|
||||
}
|
||||
panes.updateVisibility();
|
||||
panes.updateSize(paneIndex);
|
||||
},
|
||||
setOrder,
|
||||
show,
|
||||
@@ -759,7 +767,11 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
function tryProcess() {
|
||||
if (seriesGeneration !== generation) return;
|
||||
if (!timeData || !valuesData) return;
|
||||
if (valuesStamp === state.lastStamp && timeData.stamp === state.lastTimeStamp) return;
|
||||
if (
|
||||
valuesStamp === state.lastStamp &&
|
||||
timeData.stamp === state.lastTimeStamp
|
||||
)
|
||||
return;
|
||||
state.lastStamp = valuesStamp;
|
||||
state.lastTimeStamp = timeData.stamp;
|
||||
if (timeData.data.length && valuesData.length) {
|
||||
@@ -1490,47 +1502,76 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} paneIndex
|
||||
*/
|
||||
/**
|
||||
* @param {number} paneIndex
|
||||
*/
|
||||
function applyScaleForUnit(paneIndex) {
|
||||
const pane = ichart.panes().at(paneIndex);
|
||||
if (!pane) return;
|
||||
const persisted = scalePersistedValues[paneIndex];
|
||||
if (!persisted) return;
|
||||
try {
|
||||
pane.priceScale("right").applyOptions({
|
||||
mode: persisted.value === "lin" ? 0 : 1,
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** @type {Record<number, ReturnType<typeof createPersistedValue<"lin" | "log">>>} */
|
||||
const scalePersistedValues = {};
|
||||
|
||||
/**
|
||||
* @param {number} paneIndex
|
||||
* @param {IPaneApi<Time>} pane
|
||||
*/
|
||||
function injectScaleSelector(paneIndex, pane) {
|
||||
const id = `${storageId}-scale`;
|
||||
const defaultValue = paneIndex === 0 ? "log" : "lin";
|
||||
|
||||
const persisted = createPersistedValue({
|
||||
defaultValue: /** @type {"lin" | "log"} */ (defaultValue),
|
||||
storageKey: `${storageId}-p${paneIndex}-scale`,
|
||||
urlKey: paneIndex === 0 ? "price_scale" : "unit_scale",
|
||||
serialize: (v) => v,
|
||||
deserialize: (s) => /** @type {"lin" | "log"} */ (s),
|
||||
});
|
||||
let persisted = scalePersistedValues[paneIndex];
|
||||
if (!persisted) {
|
||||
persisted = createPersistedValue({
|
||||
defaultValue: /** @type {"lin" | "log"} */ (defaultValue),
|
||||
storageKey: `${storageId}-p${paneIndex}-scale`,
|
||||
urlKey: paneIndex === 0 ? "price_scale" : "unit_scale",
|
||||
serialize: (v) => v,
|
||||
deserialize: (s) => /** @type {"lin" | "log"} */ (s),
|
||||
});
|
||||
scalePersistedValues[paneIndex] = persisted;
|
||||
}
|
||||
|
||||
/** @param {IPaneApi<Time>} pane @param {"lin" | "log"} value */
|
||||
const applyScale = (pane, value) => {
|
||||
try {
|
||||
pane.priceScale("right").applyOptions({
|
||||
mode: value === "lin" ? 0 : 1,
|
||||
});
|
||||
} catch {}
|
||||
};
|
||||
// Inject into the price scale td (last td in the pane's tr)
|
||||
const paneEl = pane.getHTMLElement();
|
||||
const tr = paneEl?.closest("tr");
|
||||
const td = tr?.querySelector("td:last-child");
|
||||
if (!td) return;
|
||||
|
||||
fieldsets.addIfNeeded({
|
||||
id,
|
||||
paneIndex,
|
||||
position: "sw",
|
||||
createChild(pane) {
|
||||
applyScale(pane, persisted.value);
|
||||
return createRadios({
|
||||
choices: /** @type {const} */ (["lin", "log"]),
|
||||
id: stringToId(`${id} ${paneIndex}`),
|
||||
initialValue: persisted.value,
|
||||
onChange(value) {
|
||||
persisted.set(value);
|
||||
applyScale(pane, value);
|
||||
},
|
||||
});
|
||||
// Remove previous if any
|
||||
td.querySelector(".scale-selector")?.remove();
|
||||
|
||||
/** @type {HTMLTableCellElement} */ (td).style.position = "relative";
|
||||
|
||||
const wrapper = window.document.createElement("div");
|
||||
wrapper.classList.add("scale-selector");
|
||||
|
||||
const radios = createRadios({
|
||||
choices: /** @type {const} */ (["lin", "log"]),
|
||||
id: stringToId(`${id} ${paneIndex}`),
|
||||
initialValue: persisted.value,
|
||||
onChange(value) {
|
||||
persisted.set(value);
|
||||
try {
|
||||
pane.priceScale("right").applyOptions({
|
||||
mode: value === "lin" ? 0 : 1,
|
||||
});
|
||||
} catch {}
|
||||
},
|
||||
});
|
||||
wrapper.append(radios);
|
||||
td.append(wrapper);
|
||||
}
|
||||
|
||||
const blueprints = {
|
||||
@@ -1675,13 +1716,13 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
// Remove old series AFTER adding new ones to prevent pane collapse
|
||||
oldSeries.forEach((s) => s.remove());
|
||||
|
||||
// Store scale config - it will be applied when createForPane runs after updateVisibility
|
||||
applyScaleForUnit(paneIndex);
|
||||
},
|
||||
|
||||
rebuild() {
|
||||
generation++;
|
||||
initialLoadComplete = false; // Reset to prevent saving stale ranges during load
|
||||
panes.initialized = false;
|
||||
time.setIndex(index.get());
|
||||
time.fetch();
|
||||
this.rebuildPane(0);
|
||||
@@ -1692,9 +1733,46 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
// Rebuild when index changes
|
||||
index.onChange.add(() => blueprints.rebuild());
|
||||
|
||||
// Index selector — injected into the last tr of the chart table
|
||||
let preferredIndex = index.name.value;
|
||||
/** @type {HTMLElement | null} */
|
||||
let indexField = null;
|
||||
|
||||
const indexWrapper = window.document.createElement("div");
|
||||
indexWrapper.classList.add("index-selector");
|
||||
|
||||
const lastTr = ichart.chartElement().querySelector("table > tr:last-child");
|
||||
if (lastTr) {
|
||||
lastTr.append(indexWrapper);
|
||||
}
|
||||
|
||||
const chart = {
|
||||
index,
|
||||
|
||||
/** @param {ChartableIndexName[]} choices */
|
||||
setIndexChoices(choices) {
|
||||
if (indexField) indexField.remove();
|
||||
|
||||
let currentValue = choices.includes(preferredIndex)
|
||||
? preferredIndex
|
||||
: (choices[0] ?? "date");
|
||||
|
||||
if (currentValue !== index.name.value) {
|
||||
index.name.set(currentValue);
|
||||
}
|
||||
|
||||
indexField = createSelect({
|
||||
initialValue: currentValue,
|
||||
onChange: (v) => {
|
||||
preferredIndex = v;
|
||||
index.name.set(v);
|
||||
},
|
||||
choices,
|
||||
id: "index",
|
||||
});
|
||||
indexWrapper.append(indexField);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
@@ -1730,27 +1808,22 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
units.find((u) => u.id === persistedUnit.value) ?? defaultUnit;
|
||||
blueprints.panes[paneIndex].unit = initialUnit;
|
||||
|
||||
fieldsets.addIfNeeded({
|
||||
id: `${chartId}-unit`,
|
||||
paneIndex,
|
||||
position: "nw",
|
||||
createChild() {
|
||||
return createSelect({
|
||||
choices: units,
|
||||
id: `pane-${paneIndex}-unit`,
|
||||
initialValue: blueprints.panes[paneIndex].unit ?? defaultUnit,
|
||||
toKey: (u) => u.id,
|
||||
toLabel: (u) => u.name,
|
||||
sorted: true,
|
||||
onChange(unit) {
|
||||
generation++;
|
||||
persistedUnit.set(unit.id);
|
||||
blueprints.panes[paneIndex].unit = unit;
|
||||
blueprints.rebuildPane(paneIndex);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
blueprints.panes[paneIndex].legend.setPrefix(
|
||||
createSelect({
|
||||
choices: units,
|
||||
id: `pane-${paneIndex}-unit`,
|
||||
initialValue: blueprints.panes[paneIndex].unit ?? defaultUnit,
|
||||
toKey: (u) => u.id,
|
||||
toLabel: (u) => u.name,
|
||||
sorted: true,
|
||||
onChange(unit) {
|
||||
generation++;
|
||||
persistedUnit.set(unit.id);
|
||||
blueprints.panes[paneIndex].unit = unit;
|
||||
blueprints.rebuildPane(paneIndex);
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
blueprints.rebuild();
|
||||
|
||||
@@ -3,6 +3,15 @@ import { stringToId } from "../utils/format.js";
|
||||
|
||||
export function createLegend() {
|
||||
const element = window.document.createElement("legend");
|
||||
const scroller = window.document.createElement("div");
|
||||
const items = window.document.createElement("div");
|
||||
|
||||
scroller.append(items);
|
||||
element.append(scroller);
|
||||
|
||||
scroller.addEventListener("wheel", (e) => e.stopPropagation());
|
||||
scroller.addEventListener("touchstart", (e) => e.stopPropagation());
|
||||
scroller.addEventListener("touchmove", (e) => e.stopPropagation());
|
||||
|
||||
/** @type {AnySeries | null} */
|
||||
let hoveredSeries = null;
|
||||
@@ -24,9 +33,22 @@ export function createLegend() {
|
||||
|
||||
/** @type {HTMLElement[]} */
|
||||
const legends = [];
|
||||
/** @type {HTMLElement | null} */
|
||||
let prefix = null;
|
||||
const separator = window.document.createElement("span");
|
||||
separator.textContent = "|";
|
||||
|
||||
return {
|
||||
element,
|
||||
/**
|
||||
* @param {HTMLElement} el
|
||||
*/
|
||||
setPrefix(el) {
|
||||
if (prefix) prefix.replaceWith(el);
|
||||
else scroller.insertBefore(el, items);
|
||||
prefix = el;
|
||||
el.after(separator);
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {AnySeries} args.series
|
||||
@@ -41,11 +63,11 @@ export function createLegend() {
|
||||
if (prev) {
|
||||
prev.replaceWith(div);
|
||||
} else {
|
||||
const elementAtOrder = Array.from(element.children).at(order);
|
||||
const elementAtOrder = Array.from(items.children).at(order);
|
||||
if (elementAtOrder) {
|
||||
elementAtOrder.before(div);
|
||||
} else {
|
||||
element.append(div);
|
||||
items.append(div);
|
||||
}
|
||||
}
|
||||
legends[order] = div;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BrkClient } from "./modules/brk-client/index.js";
|
||||
|
||||
// const brk = new BrkClient("https://next.bitview.space");
|
||||
const brk = new BrkClient("/");
|
||||
const brk = new BrkClient("https://bitview.space");
|
||||
// const brk = new BrkClient("/");
|
||||
|
||||
console.log(`VERSION = ${brk.VERSION}`);
|
||||
|
||||
|
||||
@@ -387,9 +387,9 @@ export function initOptions() {
|
||||
details.append(summary);
|
||||
summary.append(node.name);
|
||||
|
||||
const supCount = window.document.createElement("sup");
|
||||
supCount.innerHTML = node.count.toLocaleString("en-us");
|
||||
summary.append(supCount);
|
||||
const count = window.document.createElement("small");
|
||||
count.textContent = `(${node.count.toLocaleString("en-us")})`;
|
||||
summary.append(count);
|
||||
|
||||
let built = false;
|
||||
details.addEventListener("toggle", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createShadow, createRadios, createHeader } from "../utils/dom.js";
|
||||
import { createShadow, createHeader } from "../utils/dom.js";
|
||||
import { chartElement } from "../utils/elements.js";
|
||||
import { serdeChartableIndex } from "../utils/serde.js";
|
||||
import { Unit } from "../utils/units.js";
|
||||
@@ -33,9 +33,7 @@ export function init() {
|
||||
brk,
|
||||
});
|
||||
|
||||
// Create index selector
|
||||
const { fieldset, setChoices } = createIndexSelector(chart);
|
||||
chartElement.append(fieldset);
|
||||
const setChoices = chart.setIndexChoices;
|
||||
|
||||
/**
|
||||
* Build top blueprints with price series prepended for each unit
|
||||
@@ -147,46 +145,3 @@ function computeChoices(opt) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chart} chart
|
||||
*/
|
||||
function createIndexSelector(chart) {
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.id = "interval";
|
||||
fieldset.dataset.size = "sm";
|
||||
|
||||
// Track user's preferred index (only updated on explicit selection)
|
||||
let preferredIndex = chart.index.name.value;
|
||||
|
||||
/** @type {HTMLElement | null} */
|
||||
let field = null;
|
||||
|
||||
/**
|
||||
* @param {ChartableIndexName[]} newChoices
|
||||
*/
|
||||
function setChoices(newChoices) {
|
||||
if (field) field.remove();
|
||||
|
||||
// Use preferred index if available, otherwise fall back to first choice
|
||||
let currentValue = newChoices.includes(preferredIndex)
|
||||
? preferredIndex
|
||||
: (newChoices[0] ?? "date");
|
||||
|
||||
if (currentValue !== chart.index.name.value) {
|
||||
chart.index.name.set(currentValue);
|
||||
}
|
||||
|
||||
field = createRadios({
|
||||
initialValue: currentValue,
|
||||
onChange: (v) => {
|
||||
preferredIndex = v; // User explicitly selected, update preference
|
||||
chart.index.name.set(v);
|
||||
},
|
||||
choices: newChoices,
|
||||
id: "index",
|
||||
});
|
||||
fieldset.append(field);
|
||||
}
|
||||
|
||||
return { fieldset, setChoices };
|
||||
}
|
||||
|
||||
@@ -287,6 +287,9 @@ export function createSelect({
|
||||
const small = window.document.createElement("small");
|
||||
small.textContent = `+${remaining}`;
|
||||
field.append(small);
|
||||
const arrow = window.document.createElement("span");
|
||||
arrow.textContent = "↓";
|
||||
field.append(arrow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+222
-98
@@ -19,6 +19,10 @@ nav {
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
> details > summary > small {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
> a::after,
|
||||
> details:not([open]) > summary::after {
|
||||
color: var(--orange) !important;
|
||||
@@ -66,6 +70,7 @@ nav {
|
||||
position: relative;
|
||||
padding-left: 0.75rem;
|
||||
border-left: 1px;
|
||||
/*border-style: dotted !important;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,7 +242,6 @@ fieldset {
|
||||
}
|
||||
}
|
||||
|
||||
.chart > legend,
|
||||
#chart > fieldset {
|
||||
text-transform: lowercase;
|
||||
flex-shrink: 0;
|
||||
@@ -257,97 +261,251 @@ fieldset {
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
> legend {
|
||||
gap: 1.5rem;
|
||||
legend {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 20;
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
text-transform: lowercase;
|
||||
pointer-events: none;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: var(--main-padding);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
background-image: linear-gradient(
|
||||
to left,
|
||||
transparent,
|
||||
var(--background-color)
|
||||
);
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: 0;
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
var(--background-color)
|
||||
);
|
||||
}
|
||||
|
||||
> div {
|
||||
flex: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
padding: 0 var(--main-padding);
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.75rem;
|
||||
pointer-events: auto;
|
||||
|
||||
> label {
|
||||
margin: -0.375rem 0;
|
||||
color: var(--color);
|
||||
|
||||
> span {
|
||||
display: flex !important;
|
||||
> div:has(> select) {
|
||||
> select {
|
||||
width: auto;
|
||||
background: none;
|
||||
}
|
||||
|
||||
&:has(input:not(:checked)) {
|
||||
color: var(--off-color);
|
||||
|
||||
> span.main > span.name {
|
||||
text-decoration-thickness: 1.5px;
|
||||
text-decoration-color: var(--color);
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
* {
|
||||
color: var(--off-color) !important;
|
||||
}
|
||||
|
||||
> span.main > span.name {
|
||||
text-decoration-color: var(--orange) !important;
|
||||
}
|
||||
}
|
||||
small {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> a {
|
||||
padding-left: 0.375rem;
|
||||
padding-right: 0.375rem;
|
||||
margin-left: -0.375rem;
|
||||
margin-right: -0.375rem;
|
||||
margin-top: 0.1rem;
|
||||
> div:last-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
> div:last-child > div {
|
||||
flex: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> label {
|
||||
margin: -0.375rem 0;
|
||||
color: var(--color);
|
||||
|
||||
> span {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
&:has(input:not(:checked)) {
|
||||
color: var(--off-color);
|
||||
|
||||
> span.main > span.name {
|
||||
text-decoration-thickness: 1.5px;
|
||||
text-decoration-color: var(--color);
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
* {
|
||||
color: var(--off-color) !important;
|
||||
}
|
||||
|
||||
> span.main > span.name {
|
||||
text-decoration-color: var(--orange) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> a {
|
||||
padding-left: 0.375rem;
|
||||
padding-right: 0.375rem;
|
||||
margin-left: -0.375rem;
|
||||
margin-right: -0.375rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightweight-chart {
|
||||
> div {
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
margin-right: var(--negative-main-padding);
|
||||
margin-left: var(--negative-main-padding);
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
|
||||
fieldset {
|
||||
padding: 0.5rem;
|
||||
z-index: 10;
|
||||
div:has(> select) {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
table > tr:first-child {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: var(--main-padding);
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
var(--background-color),
|
||||
transparent
|
||||
);
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
table > tr:last-child {
|
||||
position: relative;
|
||||
|
||||
> td {
|
||||
border-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.scale-selector {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
pointer-events: none;
|
||||
|
||||
&[data-position="nw"] {
|
||||
&::before {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
var(--background-color)
|
||||
);
|
||||
}
|
||||
|
||||
> div:has(label) {
|
||||
display: flex;
|
||||
font-size: var(--font-size-xs);
|
||||
gap: 0.25rem;
|
||||
background-color: var(--background-color);
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
text-transform: uppercase;
|
||||
padding-left: 0.625rem;
|
||||
padding-top: 0.125rem;
|
||||
padding-bottom: 0.25rem;
|
||||
|
||||
label {
|
||||
margin: -0.25rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
> fieldset {
|
||||
pointer-events: auto;
|
||||
background-color: var(--background-color);
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
padding-bottom: 0.25rem;
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.index-selector {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
pointer-events: auto;
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
text-transform: uppercase;
|
||||
|
||||
> div {
|
||||
background-color: var(--background-color);
|
||||
padding-left: var(--main-padding);
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding-right: 0.25rem;
|
||||
height: 100%;
|
||||
margin-top: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> select {
|
||||
width: auto;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-position="ne"] {
|
||||
top: 0;
|
||||
right: 0;
|
||||
&::after {
|
||||
content: "";
|
||||
height: 100%;
|
||||
margin-top: 1px;
|
||||
width: var(--main-padding);
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
var(--background-color),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
&[data-position="se"] {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&[data-position="sw"] {
|
||||
padding-left: var(--main-padding);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
button.capture {
|
||||
@@ -360,38 +518,4 @@ fieldset {
|
||||
color: var(--off-color);
|
||||
}
|
||||
}
|
||||
|
||||
> .panes {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
> .pane {
|
||||
position: relative;
|
||||
min-height: 0px;
|
||||
width: 100%;
|
||||
cursor: crosshair;
|
||||
height: 100%;
|
||||
|
||||
&:has(+ .chart-wrapper:not([hidden])) {
|
||||
height: calc(100% - 62px);
|
||||
}
|
||||
|
||||
> fieldset {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
> .shadow-bottom {
|
||||
bottom: 1.75rem;
|
||||
width: 80px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,6 @@ html {
|
||||
scrollbar-color: var(--off-color) var(--background-color);
|
||||
scrollbar-width: thin;
|
||||
overflow: hidden;
|
||||
interpolate-size: allow-keywords;
|
||||
}
|
||||
|
||||
input {
|
||||
@@ -218,7 +217,6 @@ label {
|
||||
gap: 0.25rem;
|
||||
|
||||
> span.colors {
|
||||
margin-top: 0.15rem;
|
||||
display: flex;
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
@@ -375,6 +373,12 @@ sup {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
summary > small {
|
||||
margin-left: 0.375rem;
|
||||
opacity: 0.5;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
small {
|
||||
color: var(--off-color);
|
||||
font-weight: var(--font-weight-base);
|
||||
@@ -387,7 +391,13 @@ small {
|
||||
select + & {
|
||||
font-weight: var(--font-weight-base);
|
||||
font-size: var(--font-size-xs);
|
||||
margin-left: -0.5rem !important;
|
||||
|
||||
+ span {
|
||||
color: var(--off-color);
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,42 +7,27 @@
|
||||
padding: var(--main-padding);
|
||||
background-color: var(--background-color);
|
||||
|
||||
p#domain {
|
||||
position: absolute;
|
||||
left: 2rem;
|
||||
top: 0.75rem;
|
||||
color: var(--gray);
|
||||
font-size: var(--font-size-sm);
|
||||
line-height: var(--line-height-sm);
|
||||
}
|
||||
|
||||
header {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: -1.5rem;
|
||||
margin-bottom: -1.25rem;
|
||||
padding-left: var(--main-padding);
|
||||
margin-left: var(--negative-main-padding);
|
||||
padding-right: var(--main-padding);
|
||||
margin-right: var(--negative-main-padding);
|
||||
margin-top: -0.5rem;
|
||||
|
||||
& > * {
|
||||
flex: 1;
|
||||
h1 {
|
||||
font-size: 1.375rem;
|
||||
letter-spacing: 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
.chart {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
> .chart > legend,
|
||||
> fieldset {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.lightweight-chart {
|
||||
z-index: 40;
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
flex: none;
|
||||
height: 400px;
|
||||
|
||||
.lightweight-chart {
|
||||
> div {
|
||||
margin-left: calc(var(--negative-main-padding) * 0.75);
|
||||
|
||||
fieldset {
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
color-scheme: light dark;
|
||||
|
||||
/*--white: oklch(90% 0 0);*/
|
||||
--white: oklch(95% 0.01 44);
|
||||
--light-gray: oklch(90% 0.01 44);
|
||||
--white: oklch(93.3% 0.006 75);
|
||||
/*oklch(0.9333 0.0059 59.65)*/
|
||||
--light-gray: oklch(85% 0.01 75);
|
||||
--gray: oklch(60% 0.01 44);
|
||||
--dark-gray: oklch(30% 0.01 44);
|
||||
--black: oklch(16% 0.005 44);
|
||||
--black: oklch(16.5% 0.006 90);
|
||||
/*oklch(0.2038 0.0076 196.57)*/
|
||||
--red: oklch(0.607 0.241 26.328);
|
||||
--orange: oklch(67.64% 0.191 44.41);
|
||||
--amber: oklch(0.7175 0.1835 64.199);
|
||||
|
||||
Reference in New Issue
Block a user