Various fixes for lovely-chart

This commit is contained in:
Alexander Zinchuk 2026-02-22 23:43:24 +01:00
parent fd5bcf6851
commit 03f163e528
16 changed files with 180 additions and 122 deletions

View File

@ -57,7 +57,9 @@ export function buildChannelMonetizationStatistics(
return {
// Graphs
topHoursGraph: stats.topHoursGraph ? buildGraph(stats.topHoursGraph) : undefined,
revenueGraph: buildGraph(stats.revenueGraph, undefined, true, stats.usdRate),
revenueGraph: buildGraph(stats.revenueGraph, undefined, {
label: 'USD ≈', multiplier: stats.usdRate, prefix: '$',
}),
// Statistics overview
balances: buildChannelMonetizationBalances(stats.status),
@ -156,7 +158,9 @@ export function buildStoryPublicForwards(
}
export function buildGraph(
result: GramJs.TypeStatsGraph, isPercentage?: boolean, isCurrency?: boolean, currencyRate?: number,
result: GramJs.TypeStatsGraph, isPercentage?: boolean, secondaryYAxis?: {
label: string; multiplier: number; prefix?: string; suffix?: string;
},
): TypeStatisticsGraph {
if (result instanceof GramJs.StatsGraphError) {
return {
@ -187,15 +191,15 @@ export function buildGraph(
hasSecondYAxis,
isStacked: data.stacked && !hasSecondYAxis,
isPercentage,
isCurrency,
currencyRate,
secondaryYAxis,
datasets: y.map((item: any) => {
const key = item[0];
const values = item.slice(1);
return {
name: data.names[key],
color: extractColor(data.colors[key]),
values: item.slice(1),
values: secondaryYAxis ? values.map((v: number) => v / 1e9) : values,
};
}),
...calculateMinimapRange(data.subchart.defaultZoom, x.slice(1)),

View File

@ -91,8 +91,12 @@ export interface StatisticsGraph {
labels: Array<string | number>;
isStacked: boolean;
isPercentage?: boolean;
isCurrency?: boolean;
currencyRate?: number;
secondaryYAxis?: {
label: string;
multiplier: number;
prefix?: string;
suffix?: string;
};
hideCaption: boolean;
hasSecondYAxis: boolean;
minimapRange: {

View File

@ -1,5 +1,5 @@
import { GUTTER, AXES_FONT, X_AXIS_HEIGHT, X_AXIS_SHIFT_START, PLOT_TOP_PADDING } from './constants.js';
import { formatCryptoValue, humanize } from './format.js';
import { humanize } from './format.js';
import { getCssColor } from './skin.js';
import { applyXEdgeOpacity, applyYEdgeOpacity, xScaleLevelToStep, yScaleLevelToStep } from './formulas.js';
import { toPixels } from './Projection.js';
@ -47,8 +47,25 @@ export function createAxes(context, data, plotSize, colors) {
if (data.isPercentage) {
_drawYAxisPercents(projection);
} else if (data.isCurrency) {
_drawYAxisCurrency(projection, data);
} else if (data.secondaryYAxis) {
_drawYAxisScaled(
state,
projection,
Math.round(yAxisScaleTo || yAxisScale),
yMinViewportTo !== undefined ? yMinViewportTo : yMinViewport,
yMaxViewportTo !== undefined ? yMaxViewportTo : yMaxViewport,
yAxisScaleFrom ? yAxisScaleProgress : 1,
);
_drawSecondaryYAxis(
state,
projection,
Math.round(yAxisScaleTo || yAxisScale),
yMinViewportTo !== undefined ? yMinViewportTo : yMinViewport,
yMaxViewportTo !== undefined ? yMaxViewportTo : yMaxViewport,
yAxisScaleFrom ? yAxisScaleProgress : 1,
data.secondaryYAxis,
);
} else {
_drawYAxisScaled(
state,
@ -125,10 +142,14 @@ export function createAxes(context, data, plotSize, colors) {
? getCssColor(colors, colorKey, textOpacity)
: getCssColor(colors, 'y-axis-text', textOpacity);
const label = isSecondary
? humanize(value)
: `${data.valuePrefix || ''}${humanize(value)}${data.valueSuffix || ''}`;
if (!isSecondary) {
context.fillText(humanize(value), GUTTER, yPx - GUTTER / 2);
context.fillText(label, GUTTER, yPx - GUTTER / 2);
} else {
context.fillText(humanize(value), plotSize.width - GUTTER, yPx - GUTTER / 2);
context.fillText(label, plotSize.width - GUTTER, yPx - GUTTER / 2);
}
if (isSecondary) {
@ -171,48 +192,24 @@ export function createAxes(context, data, plotSize, colors) {
context.stroke();
}
function _drawYAxisCurrency(projection, data) {
const formatValue = data.datasets[0].values.map(value => formatCryptoValue(value));
const total = formatValue.reduce((sum, value) => sum + value, 0);
const avg1 = total / formatValue.length;
const avg2 = total / (formatValue.length / 2);
const avg3 = total / (formatValue.length / 3);
const averageRate1 = avg1 * data.currencyRate;
const averageRate2 = avg2 * data.currencyRate;
const averageRate3 = avg3 * data.currencyRate;
const totalAvg = [0, avg1, avg2, avg3];
const totalRate = [0, averageRate1, averageRate2, averageRate3];
const [, height] = projection.getSize();
function _drawSecondaryYAxis(state, projection, scaleLevel, yMin, yMax, opacity = 1, secondaryYAxis) {
const { multiplier, prefix = '', suffix = '' } = secondaryYAxis;
const step = yScaleLevelToStep(scaleLevel);
const firstVisibleValue = Math.ceil(yMin / step) * step;
const lastVisibleValue = Math.floor(yMax / step) * step;
context.font = AXES_FONT;
context.textAlign = 'left';
context.textAlign = 'right';
context.textBaseline = 'bottom';
context.lineWidth = 1;
context.beginPath();
for (let value = firstVisibleValue; value <= lastVisibleValue; value += step) {
const [, yPx] = toPixels(projection, 0, value);
const textOpacity = applyXEdgeOpacity(opacity, yPx);
const secondaryValue = value * multiplier;
totalAvg.forEach((value, index) => {
const yPx = height - height * (value / Math.max(...formatValue)) + PLOT_TOP_PADDING;
context.fillStyle = getCssColor(colors, 'y-axis-text', 1);
context.fillText(`${value.toFixed(2)} TON`, GUTTER, yPx - GUTTER / 4);
context.textAlign = 'right';
context.fillText(`$${totalRate[index].toFixed(2)}`, plotSize.width - GUTTER, yPx - GUTTER / 4);
context.textAlign = 'left';
context.moveTo(GUTTER, yPx);
context.strokeStyle = getCssColor(colors, 'grid-lines', 1);
context.lineTo(plotSize.width - GUTTER, yPx);
});
context.stroke();
context.fillStyle = getCssColor(colors, 'y-axis-text', textOpacity);
context.fillText(`${prefix}${humanize(secondaryValue)}${suffix}`, plotSize.width - GUTTER, yPx - GUTTER / 2);
}
}
return { drawXAxis, drawYAxis };

View File

@ -1,5 +1,6 @@
import { createElement } from './minifiers.js';
import { captureEvents } from './captureEvents.js';
import { isColorCloseToWhite } from './skin.js';
export function createTools(container, data, filterCallback) {
let _element;
@ -35,7 +36,8 @@ export function createTools(container, data, filterCallback) {
const control = createElement('a');
control.href = '#';
control.dataset.key = key;
control.className = `lovely-chart--button lovely-chart--color-${data.colors[key].slice(1)} lovely-chart--state-checked`;
const darkContent = isColorCloseToWhite(data.colors[key]) ? ' lovely-chart--dark-content' : '';
control.className = `lovely-chart--button lovely-chart--color-${data.colors[key].slice(1)} lovely-chart--state-checked${darkContent}`;
control.innerHTML = `<span class="lovely-chart--button-check"></span><span class="lovely-chart--button-label">${name}</span>`;
control.addEventListener('click', (e) => {

View File

@ -1,8 +1,8 @@
import { setupCanvas, clearCanvas } from './canvas.js';
import { BALLOON_OFFSET, X_AXIS_HEIGHT } from './constants.js';
import { BALLOON_OFFSET, X_AXIS_HEIGHT, MAX_TOOLTIP_ITEMS } from './constants.js';
import { getPieRadius } from './formulas.js';
import {formatCryptoValue, formatInteger, getLabelDate, getLabelTime, statsFormatDayHourFull} from './format.js';
import { getCssColor } from './skin.js';
import { formatInteger, getLabelDate, getLabelTime, statsFormatDayHourFull } from './format.js';
import { getCssColor, isColorCloseToBackground } from './skin.js';
import { throttle, throttleWithRaf } from './utils.js';
import { addEventListener, createElement } from './minifiers.js';
import { toPixels } from './Projection.js';
@ -333,12 +333,14 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
}
function _insertNewDataSet(dataSetContainer, { name, key, value }, totalValue) {
const className = `lovely-chart--tooltip-dataset-value lovely-chart--position-right lovely-chart--color-${data.colors[key].slice(1)}`;
const colorHex = data.colors[key];
const colorClass = isColorCloseToBackground(colors, colorHex) ? '' : ` lovely-chart--color-${colorHex.slice(1)}`;
const className = `lovely-chart--tooltip-dataset-value lovely-chart--position-right${colorClass}`;
const newDataSet = createElement();
newDataSet.className = 'lovely-chart--tooltip-dataset';
newDataSet.setAttribute('data-present', 'true');
newDataSet.setAttribute('data-name', name);
newDataSet.innerHTML = `<span class="lovely-chart--dataset-title">${name}</span><span class="${className}">${formatInteger(value)}</span>`;
newDataSet.innerHTML = `<span class="lovely-chart--dataset-title">${name}</span><span class="${className}">${_formatValue(value)}</span>`;
_renderPercentageValue(newDataSet, value, totalValue);
const totalText = dataSetContainer.querySelector(`[data-total="true"]`);
@ -352,17 +354,19 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
function _updateDataSet(currentDataSet, { key, value } = {}, totalValue) {
currentDataSet.setAttribute('data-present', 'true');
const valueElement = currentDataSet.querySelector(`.lovely-chart--tooltip-dataset-value.lovely-chart--color-${data.colors[key].slice(1)}:not(.lovely-chart--state-hidden)`);
const valueElement = currentDataSet.querySelector(`.lovely-chart--tooltip-dataset-value`);
if (data.isCurrency) {
valueElement.innerHTML = formatCryptoValue(value);
} else {
valueElement.innerHTML = formatInteger(value);
if (valueElement) {
valueElement.innerHTML = _formatValue(value);
}
_renderPercentageValue(currentDataSet, value, totalValue);
}
function _formatValue(value) {
return `${data.valuePrefix || ''}${formatInteger(value)}${data.valueSuffix || ''}`;
}
function _renderPercentageValue(dataSet, value, totalValue) {
if (!data.isPercentage) {
return;
@ -402,7 +406,10 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
const totalValue = statistics.reduce((a, x) => a + x.value, 0);
const pointerVector = getPointerVector();
const finalStatistics = data.isPie ? statistics.filter(({ value }, index) => _isPieSectorSelected(statistics, value, totalValue, index, pointerVector)) : statistics;
const filteredStatistics = statistics.filter(({ value }) => value !== 0);
const sortedStatistics = filteredStatistics.sort((a, b) => b.value - a.value);
const limitedStatistics = sortedStatistics.slice(0, MAX_TOOLTIP_ITEMS);
const finalStatistics = data.isPie ? limitedStatistics.filter(({ value }, index) => _isPieSectorSelected(statistics, value, totalValue, index, pointerVector)) : limitedStatistics;
finalStatistics.forEach((statItem) => {
const currentDataSet = dataSetContainer.querySelector(`[data-name="${statItem.name}"]`);
@ -411,17 +418,22 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
_insertNewDataSet(dataSetContainer, statItem, totalValue);
} else {
_updateDataSet(currentDataSet, statItem, totalValue);
dataSetContainer.appendChild(currentDataSet);
}
});
if ((data.isBars || data.isSteps) && data.isStacked) {
_renderTotal(dataSetContainer, formatInteger(totalValue));
if ((data.isBars || data.isSteps || data.isAreas) && data.isStacked) {
_renderTotal(dataSetContainer, _formatValue(totalValue));
}
if (data.isCurrency) {
_renderCurrencyRate(dataSetContainer, formatCryptoValue(totalValue));
if (data.secondaryYAxis) {
_renderSecondaryTotal(dataSetContainer, totalValue);
}
// Re-append total rows to keep them at the bottom after sort reordering
Array.from(dataSetContainer.querySelectorAll('[data-total="true"]'))
.forEach((el) => dataSetContainer.appendChild(el));
Array.from(dataSetContainer.querySelectorAll('[data-present="false"]'))
.forEach((dataSet) => {
dataSet.remove();
@ -438,10 +450,10 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
const className = `lovely-chart--tooltip-dataset-value lovely-chart--position-right`;
if (!totalText) {
const newTotalText = createElement();
newTotalText.className = 'lovely-chart--tooltip-dataset';
newTotalText.className = 'lovely-chart--tooltip-dataset lovely-chart--tooltip-dataset-total';
newTotalText.setAttribute('data-present', 'true');
newTotalText.setAttribute('data-total', 'true');
newTotalText.innerHTML = `<span>All</span><span class="${className}">${totalValue}</span>`;
newTotalText.innerHTML = `<span>Total</span><span class="${className}">${totalValue}</span>`;
dataSetContainer.appendChild(newTotalText);
} else {
totalText.setAttribute('data-present', 'true');
@ -451,24 +463,25 @@ export function createTooltip(container, data, plotSize, colors, onZoom, onFocus
}
}
function _renderCurrencyRate(dataSetContainer, totalValue) {
function _renderSecondaryTotal(dataSetContainer, totalValue) {
const { label, multiplier, prefix = '', suffix = '' } = data.secondaryYAxis;
const totalText = dataSetContainer.querySelector(`[data-total="true"]`);
const className = `lovely-chart--tooltip-dataset-value lovely-chart--position-right`;
const totalUsd = (parseFloat(totalValue) * data.currencyRate).toFixed(2);
const secondaryValue = (totalValue * multiplier).toFixed(2);
if (!totalText) {
const newTotalText = createElement();
newTotalText.className = 'lovely-chart--tooltip-dataset';
newTotalText.className = 'lovely-chart--tooltip-dataset lovely-chart--tooltip-dataset-total';
newTotalText.setAttribute('data-present', 'true');
newTotalText.setAttribute('data-total', 'true');
newTotalText.innerHTML = `<span>USD ≈</span><span class="${className}">$${totalUsd}</span>`;
newTotalText.innerHTML = `<span>${label}</span><span class="${className}">${prefix}${secondaryValue}${suffix}</span>`;
dataSetContainer.appendChild(newTotalText);
} else {
totalText.setAttribute('data-present', 'true');
const valueElement = totalText.querySelector(`.lovely-chart--tooltip-dataset-value:not(.lovely-chart--state-hidden)`);
valueElement.innerHTML = `$${totalUsd}`;
valueElement.innerHTML = `${prefix}${secondaryValue}${suffix}`;
}
}

View File

@ -15,6 +15,7 @@ export const PLOT_BARS_WIDTH_SHIFT = 0.5;
export const PIE_MINIMUM_VISIBLE_PERCENT = 0.02;
export const BALLOON_OFFSET = 20;
export const MAX_TOOLTIP_ITEMS = 12;
export const AXES_FONT = '300 10px Helvetica, Arial, sans-serif';
export const AXES_MAX_COLUMN_WIDTH = 45;

View File

@ -1,8 +1,17 @@
import { getMaxMin } from './utils.js';
import { statsFormatDay, statsFormatDayHour, statsFormatText, statsFormatMin } from './format.js';
const LABEL_TYPE_TO_FORMATTER = {
'day': "statsFormat('day')",
'hour': "statsFormat('hour')",
'5min': "statsFormat('5min')",
'dayHour': 'statsFormatDayHour',
'text': undefined,
};
export function analyzeData(data) {
const { title, labelFormatter, tooltipFormatter, isStacked, isPercentage, isCurrency, currencyRate, hasSecondYAxis, onZoom, minimapRange, hideCaption, zoomOutLabel } = data;
const { title, labelFormatter: labelFormatterRaw, labelType, tooltipFormatter, isStacked, isPercentage, secondaryYAxis, hasSecondYAxis, onZoom, minimapRange, hideCaption, zoomOutLabel, valuePrefix, valueSuffix } = data;
const labelFormatter = labelFormatterRaw || (labelType && LABEL_TYPE_TO_FORMATTER[labelType]);
const { datasets, labels } = prepareDatasets(data);
const colors = {};
@ -20,13 +29,8 @@ export function analyzeData(data) {
}
});
let effectiveLabelFormatter = labelFormatter;
if (isCurrency) {
effectiveLabelFormatter = 'statsFormat(\'day\')';
}
let xLabels;
switch (effectiveLabelFormatter) {
switch (labelFormatter) {
case 'statsFormatDayHour':
xLabels = statsFormatDayHour(labels);
break;
@ -50,9 +54,10 @@ export function analyzeData(data) {
datasets,
isStacked,
isPercentage,
isCurrency,
currencyRate,
secondaryYAxis,
hasSecondYAxis,
valuePrefix,
valueSuffix,
onZoom,
isLines: data.type === 'line',
isBars: data.type === 'bar',

View File

@ -27,18 +27,14 @@ export function drawDatasets(
let datasetProjection = hasOwnYAxis ? secondaryProjection : projection;
if (datasetType === 'area') {
const { yMin, yMax } = projection.getParams();
const yHeight = yMax - yMin;
const bottomLine = [
{ labelIndex: range.from, stackValue: 0 },
{ labelIndex: range.to, stackValue: 0 },
];
const topLine = [
{ labelIndex: range.to, stackValue: yHeight },
{ labelIndex: range.from, stackValue: yHeight },
];
const lowerBoundary = points[i - 1] || bottomLine;
const upperBoundary = points[i].slice().reverse();
datasetPoints = mergeArrays([points[i - 1] || bottomLine, topLine]);
datasetPoints = mergeArrays([lowerBoundary, upperBoundary]);
}
if (datasetType === 'pie') {

View File

@ -59,11 +59,20 @@ function keepThreeDigits(value, decimals) {
}
export function formatInteger(n) {
return String(n).replace(/\d(?=(\d{3})+$)/g, '$& ');
if (!Number.isInteger(n)) {
const abs = Math.abs(n);
const decimals = (abs > 0 && abs < 1)
? Math.max(2, -Math.floor(Math.log10(abs)) + 1)
: 2;
const [intPart, decPart] = n.toFixed(decimals).split('.');
const trimmed = decPart.replace(/0+$/, '');
return trimmed ? addThousandSeparators(intPart) + '.' + trimmed : addThousandSeparators(intPart);
}
return addThousandSeparators(String(n));
}
export function formatCryptoValue(n) {
return Number(n / 10 ** 9);
function addThousandSeparators(s) {
return s.replace(/\d(?=(\d{3})+$)/g, '$& ');
}
export function getFullLabelDate(label, { isShort = false } = {}) {

View File

@ -59,7 +59,9 @@ export function createColors(datasetColors) {
addCssRule(styleSheet, `.lovely-chart--tooltip-dataset-value${baseClass}-${datasetColors[key].slice(1)}`, `color: ${datasetColors[key]}`);
addCssRule(styleSheet, `.lovely-chart--button${baseClass}-${datasetColors[key].slice(1)}`, `border-color: ${datasetColors[key]}; color: ${datasetColors[key]}`);
addCssRule(styleSheet, `.lovely-chart--button.lovely-chart--state-checked${baseClass}-${datasetColors[key].slice(1)}`, `background-color: ${datasetColors[key]}`);
const checkedBtnSelector = `.lovely-chart--button.lovely-chart--state-checked${baseClass}-${datasetColors[key].slice(1)}`;
addCssRule(styleSheet, checkedBtnSelector, `background-color: ${datasetColors[key]}`);
});
});
@ -85,6 +87,20 @@ function buildCssColor([r, g, b, a = 1], opacity = 1) {
return `rgba(${r}, ${g}, ${b}, ${a * opacity})`;
}
export function isColorCloseToBackground(colors, hex) {
const bg = colors[skin]['tooltip-background'];
const fg = hexToChannels(hex);
return colorDistance(bg, fg) < 70;
}
export function isColorCloseToWhite(hex) {
return colorDistance(hexToChannels(hex), [255, 255, 255]) < 70;
}
function colorDistance([r1, g1, b1], [r2, g2, b2]) {
return Math.sqrt((r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2);
}
function addCssRule(sheet, selector, rule) {
sheet.insertRule(`${selector} { ${rule} }`, sheet.cssRules.length);
}

View File

@ -15,6 +15,11 @@
text-decoration: none;
background-color: transparent;
transition: opacity 150ms ease;
&:hover {
opacity: 0.85;
}
&.lovely-chart--state-checked {
background-color: var(--text-color);
@ -28,6 +33,14 @@
transform: translateX(6px);
color: #ffffff;
}
&.lovely-chart--dark-content .lovely-chart--button-label {
color: #222222;
}
&.lovely-chart--dark-content .lovely-chart--button-check::after {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -256 1792 1792' version='1.1'%0A%3E%3Cg transform='matrix(1,0,0,-1,7.5932203,1217.0847)' id='g3003'%3E%3Cpath d='m 1671,970 q 0,-40 -28,-68 L 919,178 783,42 Q 755,14 715,14 675,14 647,42 L 511,178 149,540 q -28,28 -28,68 0,40 28,68 l 136,136 q 28,28 68,28 40,0 68,-28 l 294,-295 656,657 q 28,28 68,28 40,0 68,-28 l 136,-136 q 28,-28 28,-68 z' style='fill:%23222222'/%3E%3C/g%3E%3C/svg%3E");
}
}
&.lovely-chart--state-shake {
@ -64,6 +77,7 @@
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -256 1792 1792' version='1.1'%0A%3E%3Cg transform='matrix(1,0,0,-1,7.5932203,1217.0847)' id='g3003'%3E%3Cpath d='m 1671,970 q 0,-40 -28,-68 L 919,178 783,42 Q 755,14 715,14 675,14 647,42 L 511,178 149,540 q -28,28 -28,68 0,40 28,68 l 136,136 q 28,28 68,28 40,0 68,-28 l 294,-295 656,657 q 28,28 68,28 40,0 68,-28 l 136,-136 q 28,-28 28,-68 z' style='fill:white'/%3E%3C/g%3E%3C/svg%3E");
background-size: 100%;
}
}
.lovely-chart--button-label {

View File

@ -1,7 +1,27 @@
.lovely-chart--container {
--background-color: #ffffff;
--text-color: #222222;
--minimap-mask: #{rgba(#E2EEF9, 0.6)};
--minimap-slider: #C0D1E1;
--grid-lines: #{rgba(#182D3B, 0.1)};
--zoom-out-text: #108BE3;
--tooltip-background: #ffffff;
--tooltip-arrow: #D2D5D7;
-webkit-user-select: none;
user-select: none;
html.theme-dark & {
--background-color: #242F3E;
--text-color: #ffffff;
--minimap-mask: #{rgba(#304259, 0.6)};
--minimap-slider: #56626D;
--grid-lines: #{rgba(#FFFFFF, 0.1)};
--zoom-out-text: #48AAF0;
--tooltip-background: #1c2533;
--tooltip-arrow: #D2D5D7;
}
position: relative;
overflow: hidden;

View File

@ -16,13 +16,7 @@
&-title {
float: left;
margin: 0 1rem;
font-size: 16px;
text-transform: lowercase;
&:first-letter {
text-transform: uppercase;
}
}
&-caption {

View File

@ -59,7 +59,7 @@
.lovely-chart--tooltip-title {
position: relative;
padding-bottom: 5px;
padding-bottom: 6px;
font-size: 12px;
font-weight: bold;
@ -89,7 +89,12 @@
.lovely-chart--tooltip-dataset-value {
float: right;
margin-left: 5px;
margin-left: 12px;
font-weight: bold;
}
&.lovely-chart--tooltip-dataset-total {
margin-top: 6px;
font-weight: bold;
}
}

View File

@ -1,21 +0,0 @@
.lovely-chart--container {
--background-color: #ffffff;
--text-color: #222222;
--minimap-mask: #{rgba(#E2EEF9, 0.6)};
--minimap-slider: #C0D1E1;
--grid-lines: #{rgba(#182D3B, 0.1)};
--zoom-out-text: #108BE3;
--tooltip-background: #ffffff;
--tooltip-arrow: #D2D5D7;
}
html.theme-dark .lovely-chart--container {
--background-color: #242F3E;
--text-color: #ffffff;
--minimap-mask: #{rgba(#304259, 0.6)};
--minimap-slider: #56626D;
--grid-lines: #{rgba(#FFFFFF, 0.1)};
--zoom-out-text: #48AAF0;
--tooltip-background: #1c2533;
--tooltip-arrow: #D2D5D7;
}

View File

@ -1,4 +1,3 @@
@use 'variables';
@use 'animations';
@use 'common';
@use 'header';