@flux-ui/statistics 3.0.0-next.67 → 3.0.0-next.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/component/FluxStatisticsAreaChart.vue.d.ts +11 -4
- package/dist/component/FluxStatisticsBarChart.vue.d.ts +11 -4
- package/dist/component/FluxStatisticsBase.vue.d.ts +1 -0
- package/dist/component/FluxStatisticsBoxPlotChart.vue.d.ts +15 -0
- package/dist/component/FluxStatisticsBubbleChart.vue.d.ts +14 -0
- package/dist/component/FluxStatisticsCandlestickChart.vue.d.ts +15 -0
- package/dist/component/FluxStatisticsChart.vue.d.ts +7 -5
- package/dist/component/FluxStatisticsChartPane.vue.d.ts +1 -0
- package/dist/component/FluxStatisticsComparison.vue.d.ts +16 -0
- package/dist/component/FluxStatisticsDonutChart.vue.d.ts +8 -4
- package/dist/component/FluxStatisticsEmpty.vue.d.ts +19 -0
- package/dist/component/FluxStatisticsHeatmapChart.vue.d.ts +15 -0
- package/dist/component/FluxStatisticsLegendItem.vue.d.ts +1 -0
- package/dist/component/FluxStatisticsLineChart.vue.d.ts +11 -4
- package/dist/component/FluxStatisticsMixedChart.vue.d.ts +17 -0
- package/dist/component/FluxStatisticsPieChart.vue.d.ts +8 -4
- package/dist/component/FluxStatisticsPolarAreaChart.vue.d.ts +14 -0
- package/dist/component/FluxStatisticsRadarChart.vue.d.ts +12 -0
- package/dist/component/FluxStatisticsRadialBar.vue.d.ts +11 -0
- package/dist/component/FluxStatisticsScatterChart.vue.d.ts +14 -0
- package/dist/component/FluxStatisticsSparkline.vue.d.ts +13 -0
- package/dist/component/FluxStatisticsTreemapChart.vue.d.ts +11 -0
- package/dist/component/index.d.ts +13 -0
- package/dist/composable/index.d.ts +10 -0
- package/dist/composable/useChartHoverSync.d.ts +9 -0
- package/dist/composable/useChartLegend.d.ts +14 -0
- package/dist/composable/useChartSeriesSetup.d.ts +23 -0
- package/dist/composable/useECharts.d.ts +9 -0
- package/dist/composable/usePieSlicesSetup.d.ts +14 -0
- package/dist/echarts.d.ts +1 -0
- package/dist/index.css +230 -37
- package/dist/index.d.ts +5 -2
- package/dist/index.js +10919 -9041
- package/dist/index.js.map +1 -1
- package/dist/util/baseOptions.d.ts +15 -0
- package/dist/util/colors.d.ts +4 -0
- package/dist/util/convert.d.ts +22 -0
- package/dist/util/defaultOptions.d.ts +76 -0
- package/dist/util/iconSvg.d.ts +2 -0
- package/dist/util/index.d.ts +7 -0
- package/dist/util/seriesDefaults.d.ts +15 -0
- package/dist/util/sparklineOptions.d.ts +7 -0
- package/package.json +14 -15
- package/src/component/FluxStatisticsAreaChart.vue +38 -41
- package/src/component/FluxStatisticsBarChart.vue +38 -33
- package/src/component/FluxStatisticsBase.vue +14 -1
- package/src/component/FluxStatisticsBoxPlotChart.vue +69 -0
- package/src/component/FluxStatisticsBubbleChart.vue +56 -0
- package/src/component/FluxStatisticsCandlestickChart.vue +81 -0
- package/src/component/FluxStatisticsChart.vue +19 -169
- package/src/component/FluxStatisticsChartPane.vue +23 -11
- package/src/component/FluxStatisticsComparison.vue +113 -0
- package/src/component/FluxStatisticsDonutChart.vue +39 -18
- package/src/component/FluxStatisticsEmpty.vue +44 -0
- package/src/component/FluxStatisticsHeatmapChart.vue +80 -0
- package/src/component/FluxStatisticsLegend.vue +33 -1
- package/src/component/FluxStatisticsLegendItem.vue +3 -1
- package/src/component/FluxStatisticsLineChart.vue +38 -41
- package/src/component/FluxStatisticsMixedChart.vue +55 -0
- package/src/component/FluxStatisticsPieChart.vue +39 -18
- package/src/component/FluxStatisticsPolarAreaChart.vue +53 -0
- package/src/component/FluxStatisticsRadarChart.vue +108 -0
- package/src/component/FluxStatisticsRadialBar.vue +48 -0
- package/src/component/FluxStatisticsScatterChart.vue +56 -0
- package/src/component/FluxStatisticsSparkline.vue +67 -0
- package/src/component/FluxStatisticsTreemapChart.vue +39 -0
- package/src/component/index.ts +13 -0
- package/src/composable/index.ts +10 -0
- package/src/composable/useChartHoverSync.ts +92 -0
- package/src/composable/useChartLegend.ts +23 -0
- package/src/composable/useChartSeriesSetup.ts +75 -0
- package/src/composable/useECharts.ts +55 -0
- package/src/composable/usePieSlicesSetup.ts +58 -0
- package/src/css/Base.module.scss +28 -1
- package/src/css/Chart.module.scss +66 -32
- package/src/css/ChartPane.module.scss +24 -9
- package/src/css/Comparison.module.scss +52 -0
- package/src/css/Empty.module.scss +39 -0
- package/src/css/Grid.module.scss +1 -0
- package/src/css/Legend.module.scss +11 -1
- package/src/css/Metric.module.scss +6 -0
- package/src/css/Sparkline.module.scss +13 -0
- package/src/echarts.ts +47 -0
- package/src/index.ts +7 -3
- package/src/util/baseOptions.ts +74 -0
- package/src/util/colors.ts +86 -0
- package/src/util/convert.ts +360 -0
- package/src/util/defaultOptions.ts +398 -0
- package/src/util/iconSvg.ts +20 -0
- package/src/util/index.ts +7 -0
- package/src/util/seriesDefaults.ts +210 -0
- package/src/util/sparklineOptions.ts +67 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { onBeforeUnmount, watch, type Ref } from 'vue';
|
|
2
|
+
import type { ChartLegendContext } from './useChartLegend';
|
|
3
|
+
import type { EChartsInstance } from './useECharts';
|
|
4
|
+
|
|
5
|
+
export type ChartHoverSyncMode = 'series' | 'data';
|
|
6
|
+
|
|
7
|
+
export interface UseChartHoverSyncOptions {
|
|
8
|
+
readonly mode: ChartHoverSyncMode;
|
|
9
|
+
readonly seriesIndex?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useChartHoverSync(
|
|
13
|
+
chartInstance: Ref<EChartsInstance | null>,
|
|
14
|
+
legendContext: ChartLegendContext | null,
|
|
15
|
+
options: UseChartHoverSyncOptions
|
|
16
|
+
): void {
|
|
17
|
+
if (!legendContext) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { mode, seriesIndex: forcedSeriesIndex = 0 } = options;
|
|
22
|
+
|
|
23
|
+
let attached: EChartsInstance | null = null;
|
|
24
|
+
let syncing = false;
|
|
25
|
+
|
|
26
|
+
const onMouseOver = (params: { seriesIndex?: number; dataIndex?: number }) => {
|
|
27
|
+
if (syncing) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const index = mode === 'series'
|
|
32
|
+
? params.seriesIndex ?? null
|
|
33
|
+
: params.dataIndex ?? null;
|
|
34
|
+
|
|
35
|
+
legendContext.hoveredIndex.value = index;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const onMouseOut = () => {
|
|
39
|
+
if (syncing) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
legendContext.hoveredIndex.value = null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const dispatchHighlight = (instance: EChartsInstance, index: number | null) => {
|
|
47
|
+
syncing = true;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
instance.dispatchAction({ type: 'downplay' });
|
|
51
|
+
|
|
52
|
+
if (index !== null) {
|
|
53
|
+
if (mode === 'series') {
|
|
54
|
+
instance.dispatchAction({ type: 'highlight', seriesIndex: index });
|
|
55
|
+
} else {
|
|
56
|
+
instance.dispatchAction({ type: 'highlight', seriesIndex: forcedSeriesIndex, dataIndex: index });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} finally {
|
|
60
|
+
syncing = false;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
watch(chartInstance, instance => {
|
|
65
|
+
if (attached) {
|
|
66
|
+
attached.off('mouseover', onMouseOver as never);
|
|
67
|
+
attached.off('mouseout', onMouseOut as never);
|
|
68
|
+
attached = null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (instance) {
|
|
72
|
+
instance.on('mouseover', onMouseOver as never);
|
|
73
|
+
instance.on('mouseout', onMouseOut as never);
|
|
74
|
+
attached = instance;
|
|
75
|
+
dispatchHighlight(instance, legendContext.hoveredIndex.value);
|
|
76
|
+
}
|
|
77
|
+
}, { immediate: true });
|
|
78
|
+
|
|
79
|
+
watch(() => legendContext.hoveredIndex.value, index => {
|
|
80
|
+
if (chartInstance.value) {
|
|
81
|
+
dispatchHighlight(chartInstance.value, index);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
onBeforeUnmount(() => {
|
|
86
|
+
if (attached) {
|
|
87
|
+
attached.off('mouseover', onMouseOver as never);
|
|
88
|
+
attached.off('mouseout', onMouseOut as never);
|
|
89
|
+
attached = null;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FluxIconName } from '@flux-ui/types';
|
|
2
|
+
import { ref, type InjectionKey, type Ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
export interface ChartLegendItem {
|
|
5
|
+
readonly color?: string;
|
|
6
|
+
readonly icon?: FluxIconName;
|
|
7
|
+
readonly label: string;
|
|
8
|
+
readonly value?: string | number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ChartLegendContext {
|
|
12
|
+
readonly items: Ref<readonly ChartLegendItem[]>;
|
|
13
|
+
readonly hoveredIndex: Ref<number | null>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const FluxStatisticsChartLegendInjectionKey: InjectionKey<ChartLegendContext> = Symbol('flux-statistics-chart-legend');
|
|
17
|
+
|
|
18
|
+
export function createChartLegendContext(): ChartLegendContext {
|
|
19
|
+
return {
|
|
20
|
+
items: ref<readonly ChartLegendItem[]>([]),
|
|
21
|
+
hoveredIndex: ref<number | null>(null)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { FluxIconName, FluxStatisticsChartColor } from '@flux-ui/types';
|
|
2
|
+
import { computed, inject, useTemplateRef, watchEffect, type ComputedRef } from 'vue';
|
|
3
|
+
import { useI18n } from 'vue-i18n';
|
|
4
|
+
import { CHART_DEFAULT_COLORS, resolveChartColor } from '~flux/statistics/util';
|
|
5
|
+
import { type ChartHoverSyncMode, useChartHoverSync } from './useChartHoverSync';
|
|
6
|
+
import { type ChartLegendContext, type ChartLegendItem, FluxStatisticsChartLegendInjectionKey } from './useChartLegend';
|
|
7
|
+
import type { EChartsInstance } from './useECharts';
|
|
8
|
+
|
|
9
|
+
export interface ChartSeriesShape {
|
|
10
|
+
readonly name?: string;
|
|
11
|
+
readonly icon?: FluxIconName;
|
|
12
|
+
readonly color?: FluxStatisticsChartColor;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ChartLegendItemBuilder<S> = (
|
|
16
|
+
series: S,
|
|
17
|
+
color: string,
|
|
18
|
+
index: number,
|
|
19
|
+
t: ReturnType<typeof useI18n>['t']
|
|
20
|
+
) => ChartLegendItem | readonly ChartLegendItem[];
|
|
21
|
+
|
|
22
|
+
export interface UseChartSeriesSetupOptions<S extends ChartSeriesShape> {
|
|
23
|
+
readonly mode?: ChartHoverSyncMode;
|
|
24
|
+
readonly getLegendItem?: ChartLegendItemBuilder<S>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface UseChartSeriesSetupReturn {
|
|
28
|
+
readonly t: ReturnType<typeof useI18n>['t'];
|
|
29
|
+
readonly palette: ComputedRef<readonly string[]>;
|
|
30
|
+
readonly legendContext: ChartLegendContext | null;
|
|
31
|
+
readonly chartInstance: ComputedRef<EChartsInstance | null>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const defaultLegendItem = <S extends ChartSeriesShape>(
|
|
35
|
+
s: S,
|
|
36
|
+
color: string,
|
|
37
|
+
_index: number,
|
|
38
|
+
t: ReturnType<typeof useI18n>['t']
|
|
39
|
+
): ChartLegendItem => ({
|
|
40
|
+
color,
|
|
41
|
+
icon: s.icon,
|
|
42
|
+
label: s.name ? t(String(s.name)) : ''
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export function useChartSeriesSetup<S extends ChartSeriesShape>(
|
|
46
|
+
seriesGetter: () => readonly S[],
|
|
47
|
+
options: UseChartSeriesSetupOptions<S> = {}
|
|
48
|
+
): UseChartSeriesSetupReturn {
|
|
49
|
+
const { mode = 'series', getLegendItem = defaultLegendItem } = options;
|
|
50
|
+
const { t } = useI18n({ useScope: 'parent' });
|
|
51
|
+
const legendContext = inject(FluxStatisticsChartLegendInjectionKey, null);
|
|
52
|
+
const chartRef = useTemplateRef<{ chartInstance: EChartsInstance | null } | null>('chartRef');
|
|
53
|
+
const chartInstance = computed<EChartsInstance | null>(() => chartRef.value?.chartInstance ?? null);
|
|
54
|
+
|
|
55
|
+
useChartHoverSync(chartInstance, legendContext, { mode });
|
|
56
|
+
|
|
57
|
+
const palette = computed<readonly string[]>(() =>
|
|
58
|
+
seriesGetter().map((s, i) => resolveChartColor(s.color) ?? CHART_DEFAULT_COLORS[i % CHART_DEFAULT_COLORS.length])
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const legendItems = computed<readonly ChartLegendItem[]>(() =>
|
|
62
|
+
seriesGetter().flatMap((s, i) => {
|
|
63
|
+
const item = getLegendItem(s, palette.value[i], i, t);
|
|
64
|
+
return Array.isArray(item) ? item : [item as ChartLegendItem];
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
watchEffect(() => {
|
|
69
|
+
if (legendContext) {
|
|
70
|
+
legendContext.items.value = legendItems.value;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return { t, palette, legendContext, chartInstance };
|
|
75
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useResizeObserver } from '@basmilius/common';
|
|
2
|
+
import { init, type EChartsCoreOption } from 'echarts/core';
|
|
3
|
+
import { markRaw, onBeforeUnmount, onMounted, ref, toValue, type MaybeRefOrGetter, type Ref } from 'vue';
|
|
4
|
+
import '~flux/statistics/echarts';
|
|
5
|
+
|
|
6
|
+
export type EChartsOption = EChartsCoreOption;
|
|
7
|
+
export type EChartsInstance = ReturnType<typeof init>;
|
|
8
|
+
|
|
9
|
+
export interface UseEChartsReturn {
|
|
10
|
+
readonly chartInstance: Ref<EChartsInstance | null>;
|
|
11
|
+
resize(): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useECharts(
|
|
15
|
+
target: Ref<HTMLElement | null>,
|
|
16
|
+
options: MaybeRefOrGetter<EChartsOption>
|
|
17
|
+
): UseEChartsReturn {
|
|
18
|
+
const chartInstance = ref<EChartsInstance | null>(null);
|
|
19
|
+
let pendingResize: number | null = null;
|
|
20
|
+
|
|
21
|
+
onMounted(() => {
|
|
22
|
+
if (!target.value) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
chartInstance.value = markRaw(init(target.value));
|
|
27
|
+
chartInstance.value.setOption(toValue(options));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
onBeforeUnmount(() => {
|
|
31
|
+
if (pendingResize !== null) {
|
|
32
|
+
cancelAnimationFrame(pendingResize);
|
|
33
|
+
pendingResize = null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
chartInstance.value?.dispose();
|
|
37
|
+
chartInstance.value = null;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
useResizeObserver(target as any, () => {
|
|
41
|
+
if (pendingResize !== null) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pendingResize = requestAnimationFrame(() => {
|
|
46
|
+
pendingResize = null;
|
|
47
|
+
chartInstance.value?.resize();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
chartInstance: chartInstance as Ref<EChartsInstance | null>,
|
|
53
|
+
resize: () => chartInstance.value?.resize()
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { FluxStatisticsChartPieSlice } from '@flux-ui/types';
|
|
2
|
+
import { computed, inject, useTemplateRef, watchEffect, type ComputedRef } from 'vue';
|
|
3
|
+
import { useI18n } from 'vue-i18n';
|
|
4
|
+
import { CHART_DEFAULT_COLORS, resolveChartColor, type SharedTooltipItem } from '~flux/statistics/util';
|
|
5
|
+
import { useChartHoverSync } from './useChartHoverSync';
|
|
6
|
+
import { type ChartLegendContext, type ChartLegendItem, FluxStatisticsChartLegendInjectionKey } from './useChartLegend';
|
|
7
|
+
import type { EChartsInstance } from './useECharts';
|
|
8
|
+
|
|
9
|
+
export interface UsePieSlicesSetupReturn {
|
|
10
|
+
readonly t: ReturnType<typeof useI18n>['t'];
|
|
11
|
+
readonly palette: ComputedRef<readonly string[]>;
|
|
12
|
+
readonly tooltipItems: ComputedRef<readonly SharedTooltipItem[]>;
|
|
13
|
+
readonly legendContext: ChartLegendContext | null;
|
|
14
|
+
readonly chartInstance: ComputedRef<EChartsInstance | null>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function usePieSlicesSetup(
|
|
18
|
+
slicesGetter: () => readonly FluxStatisticsChartPieSlice[]
|
|
19
|
+
): UsePieSlicesSetupReturn {
|
|
20
|
+
const { t } = useI18n({ useScope: 'parent' });
|
|
21
|
+
const legendContext = inject(FluxStatisticsChartLegendInjectionKey, null);
|
|
22
|
+
const chartRef = useTemplateRef<{ chartInstance: EChartsInstance | null } | null>('chartRef');
|
|
23
|
+
const chartInstance = computed<EChartsInstance | null>(() => chartRef.value?.chartInstance ?? null);
|
|
24
|
+
|
|
25
|
+
useChartHoverSync(chartInstance, legendContext, { mode: 'data' });
|
|
26
|
+
|
|
27
|
+
const palette = computed<readonly string[]>(() =>
|
|
28
|
+
slicesGetter().map((slice, i) => resolveChartColor(slice.color) ?? CHART_DEFAULT_COLORS[i % CHART_DEFAULT_COLORS.length])
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const tooltipItems = computed<readonly SharedTooltipItem[]>(() =>
|
|
32
|
+
slicesGetter().map((slice, i) => ({
|
|
33
|
+
name: slice.label,
|
|
34
|
+
value: slice.formatted ?? slice.value,
|
|
35
|
+
color: palette.value[i],
|
|
36
|
+
icon: slice.icon,
|
|
37
|
+
seriesIndex: 0,
|
|
38
|
+
dataIndex: i
|
|
39
|
+
}))
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const legendItems = computed<readonly ChartLegendItem[]>(() =>
|
|
43
|
+
slicesGetter().map((slice, i) => ({
|
|
44
|
+
color: palette.value[i],
|
|
45
|
+
icon: slice.icon,
|
|
46
|
+
label: slice.label ? t(String(slice.label)) : '',
|
|
47
|
+
value: slice.formatted ?? slice.value
|
|
48
|
+
}))
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
watchEffect(() => {
|
|
52
|
+
if (legendContext) {
|
|
53
|
+
legendContext.items.value = legendItems.value;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return { t, palette, tooltipItems, legendContext, chartInstance };
|
|
58
|
+
}
|
package/src/css/Base.module.scss
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
.statisticsBaseHeader {
|
|
19
19
|
display: flex;
|
|
20
20
|
padding: 18px 18px 0;
|
|
21
|
+
gap: 9px;
|
|
21
22
|
align-items: flex-start;
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -29,10 +30,31 @@
|
|
|
29
30
|
word-break: break-word;
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
.statisticsBaseHeaderIcon,
|
|
34
|
+
.statisticsBaseHeaderInfo {
|
|
35
|
+
font-size: 20px;
|
|
36
|
+
line-height: 24px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.statisticsBaseHeaderInfo {
|
|
40
|
+
margin-left: auto;
|
|
41
|
+
color: var(--foreground-secondary);
|
|
42
|
+
cursor: help;
|
|
43
|
+
scale: .75;
|
|
44
|
+
transition: color .2s var(--swift-out);
|
|
45
|
+
|
|
46
|
+
&:hover {
|
|
47
|
+
color: var(--foreground-prominent);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.statisticsBaseHeaderInfo + .statisticsBaseHeaderIcon {
|
|
52
|
+
margin-left: 6px;
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
.statisticsBaseHeaderIcon {
|
|
33
56
|
margin-left: auto;
|
|
34
57
|
color: var(--primary-600);
|
|
35
|
-
font-size: 20px;
|
|
36
58
|
}
|
|
37
59
|
|
|
38
60
|
.statisticsBaseSmall .statisticsBaseHeaderTitle {
|
|
@@ -41,6 +63,11 @@
|
|
|
41
63
|
line-height: 18px;
|
|
42
64
|
}
|
|
43
65
|
|
|
66
|
+
.statisticsBaseSmall .statisticsBaseHeaderInfo {
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
line-height: 18px;
|
|
69
|
+
}
|
|
70
|
+
|
|
44
71
|
.statisticsBaseSmall .statisticsBaseHeaderIcon {
|
|
45
72
|
font-size: 18px;
|
|
46
73
|
}
|
|
@@ -20,42 +20,10 @@
|
|
|
20
20
|
position: absolute;
|
|
21
21
|
display: block;
|
|
22
22
|
inset: 0;
|
|
23
|
-
//inset: -3px -2px -4px -2px;
|
|
24
23
|
height: unset;
|
|
25
24
|
width: unset;
|
|
26
25
|
|
|
27
|
-
:global(svg) {
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
26
|
--stroke: rgb(from var(--surface-stroke) r g b / .5);
|
|
32
|
-
|
|
33
|
-
:global(.apexcharts-canvas) {
|
|
34
|
-
:global(.apexcharts-grid-borders) {
|
|
35
|
-
display: none;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
:global(.apexcharts-yaxis-texts-g) {
|
|
39
|
-
display: none;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
:global(.apexcharts-tooltip) {
|
|
43
|
-
background: rgb(from var(--surface) r g b / .975);
|
|
44
|
-
background-clip: padding-box;
|
|
45
|
-
backdrop-filter: blur(3px) saturate(180%);
|
|
46
|
-
border: 1px solid var(--surface-stroke-out-hover);
|
|
47
|
-
border-radius: var(--radius-double);
|
|
48
|
-
box-shadow: var(--shadow-lg);
|
|
49
|
-
color: var(--foreground);
|
|
50
|
-
contain: paint;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.statisticsChartElement {
|
|
56
|
-
position: absolute;
|
|
57
|
-
display: block;
|
|
58
|
-
inset: 0;
|
|
59
27
|
}
|
|
60
28
|
|
|
61
29
|
.statisticsChartTooltipTitle {
|
|
@@ -81,13 +49,79 @@
|
|
|
81
49
|
border-radius: 6px;
|
|
82
50
|
}
|
|
83
51
|
|
|
52
|
+
.statisticsChartTooltipSeriesIcon {
|
|
53
|
+
display: flex;
|
|
54
|
+
height: 14px;
|
|
55
|
+
width: 14px;
|
|
56
|
+
color: var(--danger-600);
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
|
|
60
|
+
& > svg {
|
|
61
|
+
height: 100%;
|
|
62
|
+
width: 100%;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
84
66
|
.statisticsChartTooltipSeriesName {
|
|
67
|
+
color: var(--foreground-secondary);
|
|
85
68
|
font-size: 14px;
|
|
86
69
|
font-weight: 700;
|
|
70
|
+
transition: color .15s ease-out;
|
|
87
71
|
}
|
|
88
72
|
|
|
89
73
|
.statisticsChartTooltipSeriesValue {
|
|
74
|
+
color: var(--foreground-secondary);
|
|
90
75
|
font-size: 14px;
|
|
91
76
|
font-weight: 500;
|
|
92
77
|
text-align: right;
|
|
78
|
+
transition: color .15s ease-out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.statisticsChartTooltipSeriesName.isActive,
|
|
82
|
+
.statisticsChartTooltipSeriesValue.isActive {
|
|
83
|
+
color: var(--foreground-prominent);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.statisticsChartTooltipSection {
|
|
87
|
+
padding: 12px 18px;
|
|
88
|
+
transition: opacity .15s ease-out;
|
|
89
|
+
|
|
90
|
+
& + & {
|
|
91
|
+
border-top: 1px solid var(--surface-stroke);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.statisticsChartTooltipSection.isDimmed {
|
|
96
|
+
opacity: .55;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.statisticsChartTooltipSectionTitle {
|
|
100
|
+
color: var(--foreground-prominent);
|
|
101
|
+
font-size: 14px;
|
|
102
|
+
font-weight: 700;
|
|
103
|
+
line-height: 1;
|
|
104
|
+
margin-bottom: 9px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.statisticsChartTooltipSectionBody {
|
|
108
|
+
display: grid;
|
|
109
|
+
align-items: center;
|
|
110
|
+
gap: 6px 15px;
|
|
111
|
+
grid-template-columns: repeat(3, auto);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
:global(.flux-statistics-tooltip) {
|
|
115
|
+
background: rgb(from var(--surface) r g b / .975) !important;
|
|
116
|
+
background-clip: padding-box;
|
|
117
|
+
backdrop-filter: blur(3px) saturate(180%);
|
|
118
|
+
border: 1px solid var(--surface-stroke-out-hover) !important;
|
|
119
|
+
border-radius: var(--radius-double) !important;
|
|
120
|
+
box-shadow: var(--shadow-lg) !important;
|
|
121
|
+
color: var(--foreground);
|
|
122
|
+
contain: paint;
|
|
123
|
+
|
|
124
|
+
&:empty {
|
|
125
|
+
display: none;
|
|
126
|
+
}
|
|
93
127
|
}
|
|
@@ -3,36 +3,51 @@
|
|
|
3
3
|
.statisticsChartPane {
|
|
4
4
|
--aspect-ratio: unset;
|
|
5
5
|
|
|
6
|
+
container: chart-pane / inline-size;
|
|
6
7
|
max-width: 100%;
|
|
7
|
-
aspect-ratio: var(--aspect-ratio);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
.statisticsChartPaneBody {
|
|
11
11
|
display: grid;
|
|
12
|
+
align-content: start;
|
|
12
13
|
flex-grow: 1;
|
|
13
14
|
grid-template-columns: 1fr;
|
|
14
15
|
grid-template-rows: 1fr;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
.statisticsChartPaneContainer {
|
|
18
|
+
height: calc(100cqw / var(--aspect-ratio, 1));
|
|
18
19
|
}
|
|
19
|
-
}
|
|
20
20
|
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
&:has(.statisticsLegend) {
|
|
22
|
+
grid-template-columns: .4fr .6fr;
|
|
23
|
+
|
|
24
|
+
@container chart-pane (max-width: 390px) {
|
|
25
|
+
grid-template-columns: 1fr;
|
|
26
|
+
grid-template-rows: auto auto;
|
|
27
|
+
}
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
.statisticsChartPaneContainer {
|
|
30
|
+
height: calc(40cqw / var(--aspect-ratio, 1));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&:first-child :global(canvas) {
|
|
26
35
|
border-top-left-radius: var(--radius);
|
|
27
36
|
border-top-right-radius: var(--radius);
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
&:last-child :global(
|
|
39
|
+
&:last-child :global(canvas) {
|
|
31
40
|
border-bottom-left-radius: var(--radius);
|
|
32
41
|
border-bottom-right-radius: var(--radius);
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
44
|
|
|
45
|
+
.statisticsChartPaneContainer {
|
|
46
|
+
position: relative;
|
|
47
|
+
display: block;
|
|
48
|
+
align-self: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
:local(.paneHeader) + .statisticsChartPaneContainer {
|
|
37
52
|
margin-top: 18px;
|
|
38
53
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.statisticsComparison {
|
|
2
|
+
display: grid;
|
|
3
|
+
margin-top: 18px;
|
|
4
|
+
gap: 12px;
|
|
5
|
+
grid-template-columns: 1fr auto 1fr;
|
|
6
|
+
align-items: center;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.statisticsComparisonDivider {
|
|
10
|
+
width: 1px;
|
|
11
|
+
height: 36px;
|
|
12
|
+
background: var(--stroke);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.statisticsComparisonItem {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-flow: column;
|
|
18
|
+
gap: 3px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.statisticsComparisonItemLabel {
|
|
22
|
+
color: var(--foreground-secondary);
|
|
23
|
+
font-size: 13px;
|
|
24
|
+
font-weight: 500;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.statisticsComparisonItemValue {
|
|
28
|
+
color: var(--foreground-prominent);
|
|
29
|
+
font-size: 21px;
|
|
30
|
+
font-weight: 800;
|
|
31
|
+
line-height: 28px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.statisticsComparisonItemValueMuted {
|
|
35
|
+
color: var(--foreground-secondary);
|
|
36
|
+
font-size: 18px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
line-height: 28px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.statisticsComparisonBottom {
|
|
42
|
+
display: flex;
|
|
43
|
+
margin-top: 9px;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: 9px;
|
|
46
|
+
line-height: 18px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.statisticsComparisonFooter {
|
|
50
|
+
color: var(--foreground-secondary);
|
|
51
|
+
font-size: 14px;
|
|
52
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.statisticsEmpty {
|
|
2
|
+
position: absolute;
|
|
3
|
+
display: flex;
|
|
4
|
+
inset: 0;
|
|
5
|
+
padding: 24px 18px;
|
|
6
|
+
flex-flow: column;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
text-align: center;
|
|
10
|
+
gap: 9px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.statisticsEmptyIcon {
|
|
14
|
+
color: var(--foreground-secondary);
|
|
15
|
+
font-size: 32px;
|
|
16
|
+
opacity: 0.5;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.statisticsEmptyTitle {
|
|
20
|
+
color: var(--foreground-prominent);
|
|
21
|
+
font-size: 16px;
|
|
22
|
+
font-weight: 700;
|
|
23
|
+
line-height: 24px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.statisticsEmptyDescription {
|
|
27
|
+
max-width: 320px;
|
|
28
|
+
color: var(--foreground-secondary);
|
|
29
|
+
font-size: 14px;
|
|
30
|
+
font-weight: 400;
|
|
31
|
+
line-height: 20px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.statisticsEmptyActions {
|
|
35
|
+
display: flex;
|
|
36
|
+
margin-top: 9px;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: 9px;
|
|
39
|
+
}
|
package/src/css/Grid.module.scss
CHANGED
|
@@ -2,24 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
.statisticsLegend {
|
|
4
4
|
display: flex;
|
|
5
|
+
max-height: 360px;
|
|
5
6
|
min-width: 0;
|
|
6
7
|
padding: 15px 18px 15px;
|
|
7
8
|
align-self: center;
|
|
8
9
|
flex-flow: column;
|
|
9
10
|
flex-grow: 1;
|
|
11
|
+
overflow: auto;
|
|
12
|
+
user-select: none;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
.statisticsLegendItem {
|
|
13
16
|
--color: var(--primary-600);
|
|
14
17
|
|
|
15
18
|
display: flex;
|
|
16
|
-
padding: 6px
|
|
19
|
+
padding: 6px 9px;
|
|
20
|
+
margin: 0 -9px;
|
|
17
21
|
align-items: flex-start;
|
|
18
22
|
flex-flow: row nowrap;
|
|
19
23
|
gap: 9px;
|
|
20
24
|
font-size: 14px;
|
|
21
25
|
line-height: 20px;
|
|
22
26
|
white-space: nowrap;
|
|
27
|
+
border-radius: var(--radius-small);
|
|
28
|
+
transition: background var(--swift-out);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.statisticsLegendItem.isHovered {
|
|
32
|
+
background: var(--surface-active);
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
.statisticsLegendItemColor {
|