From b1d9f613304690ea758fe194b06f5dc78c99105a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D1=83=D0=B0=D0=BD?= Date: Wed, 17 Dec 2025 16:56:08 +0300 Subject: [PATCH 1/5] feat: add componets chart and animatedCounter --- @codexteam/ui/dev/Playground.vue | 10 + @codexteam/ui/dev/pages/components/Chart.vue | 97 +++ .../ui/dev/pages/components/Counter.vue | 61 ++ @codexteam/ui/dev/routes.ts | 10 + .../src/vue/components/chart/Chart.colors.ts | 24 + .../src/vue/components/chart/Chart.types.ts | 80 ++ .../ui/src/vue/components/chart/Chart.vue | 714 ++++++++++++++++++ .../ui/src/vue/components/chart/ChartLine.vue | 250 ++++++ .../ui/src/vue/components/chart/index.ts | 5 + .../ui/src/vue/components/counter/Counter.vue | 98 +++ .../ui/src/vue/components/counter/index.ts | 3 + @codexteam/ui/src/vue/index.ts | 2 + 12 files changed, 1354 insertions(+) create mode 100644 @codexteam/ui/dev/pages/components/Chart.vue create mode 100644 @codexteam/ui/dev/pages/components/Counter.vue create mode 100644 @codexteam/ui/src/vue/components/chart/Chart.colors.ts create mode 100644 @codexteam/ui/src/vue/components/chart/Chart.types.ts create mode 100644 @codexteam/ui/src/vue/components/chart/Chart.vue create mode 100644 @codexteam/ui/src/vue/components/chart/ChartLine.vue create mode 100644 @codexteam/ui/src/vue/components/chart/index.ts create mode 100644 @codexteam/ui/src/vue/components/counter/Counter.vue create mode 100644 @codexteam/ui/src/vue/components/counter/index.ts diff --git a/@codexteam/ui/dev/Playground.vue b/@codexteam/ui/dev/Playground.vue index d459ed9b..f34b2d7e 100644 --- a/@codexteam/ui/dev/Playground.vue +++ b/@codexteam/ui/dev/Playground.vue @@ -223,6 +223,16 @@ const pages = computed(() => [ onActivate: () => router.push('/components/confirm'), isActive: route.path === '/components/confirm', }, + { + title: 'Counter', + onActivate: () => router.push('/components/counter'), + isActive: route.path === '/components/counter', + }, + { + title: 'Chart', + onActivate: () => router.push('/components/chart'), + isActive: route.path === '/components/chart', + }, ], }, ]); diff --git a/@codexteam/ui/dev/pages/components/Chart.vue b/@codexteam/ui/dev/pages/components/Chart.vue new file mode 100644 index 00000000..4e73eecb --- /dev/null +++ b/@codexteam/ui/dev/pages/components/Chart.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/@codexteam/ui/dev/pages/components/Counter.vue b/@codexteam/ui/dev/pages/components/Counter.vue new file mode 100644 index 00000000..f445e4da --- /dev/null +++ b/@codexteam/ui/dev/pages/components/Counter.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/@codexteam/ui/dev/routes.ts b/@codexteam/ui/dev/routes.ts index 2b9f8420..b3e09686 100644 --- a/@codexteam/ui/dev/routes.ts +++ b/@codexteam/ui/dev/routes.ts @@ -30,6 +30,8 @@ import Editor from './pages/components/Editor.vue'; import ThemePreview from './pages/components/ThemePreview.vue'; import Popup from './pages/components/Popup.vue'; import Confirm from './pages/components/Confirm.vue'; +import Counter from './pages/components/Counter.vue'; +import Chart from './pages/components/Chart.vue'; import Navbar from './pages/layout/Navbar.vue'; import PageBlock from './pages/layout/PageBlock.vue'; @@ -157,6 +159,14 @@ const routes: RouteRecordRaw[] = [ path: '/components/confirm', component: Confirm as Component, }, + { + path: '/components/counter', + component: Counter as Component, + }, + { + path: '/components/chart', + component: Chart as Component, + }, { path: '/layout/navbar', component: Navbar as Component, diff --git a/@codexteam/ui/src/vue/components/chart/Chart.colors.ts b/@codexteam/ui/src/vue/components/chart/Chart.colors.ts new file mode 100644 index 00000000..58135e84 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/Chart.colors.ts @@ -0,0 +1,24 @@ +import { ChartLineColor } from './Chart.types'; +import type { ChartLineColors } from './Chart.types'; + +/** + * Colors set for several chart lines + */ +export const chartColors: ChartLineColors[] = [ + { + name: ChartLineColor.LightGrey, + strokeStart: 'rgba(75, 90, 121, 0.33)', + strokeEnd: 'rgba(71, 72, 85, 0.16)', + fillStart: 'rgba(63, 136, 255, 0.01)', + fillEnd: 'rgba(66, 78, 93, 0.05)', + pointerColor: '#717289', + }, + { + name: ChartLineColor.Red, + strokeStart: '#FF2E51', + strokeEnd: '#424565', + fillStart: 'rgba(255, 46, 81, 0.3)', + fillEnd: 'rgba(66, 69, 101, 0)', + pointerColor: '#FF2E51', + }, +]; diff --git a/@codexteam/ui/src/vue/components/chart/Chart.types.ts b/@codexteam/ui/src/vue/components/chart/Chart.types.ts new file mode 100644 index 00000000..25a4fc03 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/Chart.types.ts @@ -0,0 +1,80 @@ +/** + * Name of the color for the chart line stroke and fill. + */ +export enum ChartLineColor { + /** + * Accent color for primary line + */ + Red = 'red', + + /** + * Accent color for secondary line + */ + LightGrey = 'light-grey' +} + +/** + * Chart element in common case + */ +export interface ChartItem { + /** + * Day midnight + */ + timestamp: number; + + /** + * How many events occurred in that day + */ + count: number; +} + +/** + * Chart line with label and data points + */ +export interface ChartLine { + /** + * Series label (e.g., "accepted", "rate-limited") + */ + label: string; + + /** + * Data points for the series + */ + data: ChartItem[]; + + /** + * Name of the color for the line stroke and fill. + */ + color?: ChartLineColor; +} + +/** + * A particular color params + */ +export interface ChartLineColors { + /** + * Name of the color + */ + name: ChartLineColor; + /** + * Starting color for stroke gradient (top) + */ + strokeStart: string; + /** + * Ending color for stroke gradient (bottom) + */ + strokeEnd: string; + /** + * Starting color for fill gradient (top, with opacity) + */ + fillStart: string; + /** + * Ending color for fill gradient (bottom, usually transparent) + */ + fillEnd: string; + + /** + * Pointer + legend color + */ + pointerColor: string; +} diff --git a/@codexteam/ui/src/vue/components/chart/Chart.vue b/@codexteam/ui/src/vue/components/chart/Chart.vue new file mode 100644 index 00000000..eebf0604 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/Chart.vue @@ -0,0 +1,714 @@ + + + + + diff --git a/@codexteam/ui/src/vue/components/chart/ChartLine.vue b/@codexteam/ui/src/vue/components/chart/ChartLine.vue new file mode 100644 index 00000000..f83afb88 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/ChartLine.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/@codexteam/ui/src/vue/components/chart/index.ts b/@codexteam/ui/src/vue/components/chart/index.ts new file mode 100644 index 00000000..31f6e4e1 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/index.ts @@ -0,0 +1,5 @@ +import Chart from './Chart.vue'; + +export { Chart }; +export * from './Chart.types'; +export * from './Chart.colors'; diff --git a/@codexteam/ui/src/vue/components/counter/Counter.vue b/@codexteam/ui/src/vue/components/counter/Counter.vue new file mode 100644 index 00000000..af18f82e --- /dev/null +++ b/@codexteam/ui/src/vue/components/counter/Counter.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/@codexteam/ui/src/vue/components/counter/index.ts b/@codexteam/ui/src/vue/components/counter/index.ts new file mode 100644 index 00000000..31356f90 --- /dev/null +++ b/@codexteam/ui/src/vue/components/counter/index.ts @@ -0,0 +1,3 @@ +import Counter from './Counter.vue'; + +export { Counter }; diff --git a/@codexteam/ui/src/vue/index.ts b/@codexteam/ui/src/vue/index.ts index 1a2de67d..4cd7c227 100644 --- a/@codexteam/ui/src/vue/index.ts +++ b/@codexteam/ui/src/vue/index.ts @@ -21,6 +21,8 @@ export * from './components/confirm'; export * from './composables/useTheme'; export * from './components/checkbox'; export * from './components/select'; +export * from './components/chart'; +export * from './components/counter'; export * from './layout/navbar'; export * from './layout/page-block'; From d0f116b35f952c77ba2cf1738524d595123b5aa0 Mon Sep 17 00:00:00 2001 From: quangtuanitmo18 Date: Thu, 18 Dec 2025 17:37:12 +0300 Subject: [PATCH 2/5] feat: describe detalization param (component chart) and illustrate how it works --- @codexteam/ui/dev/pages/components/Chart.vue | 397 +++++++++++++++++- .../src/vue/components/chart/Chart.types.ts | 4 +- .../ui/src/vue/components/chart/Chart.vue | 55 +-- @codexteam/ui/src/vue/utils/app/index.ts | 37 ++ 4 files changed, 416 insertions(+), 77 deletions(-) create mode 100644 @codexteam/ui/src/vue/utils/app/index.ts diff --git a/@codexteam/ui/dev/pages/components/Chart.vue b/@codexteam/ui/dev/pages/components/Chart.vue index 4e73eecb..2cd6ac64 100644 --- a/@codexteam/ui/dev/pages/components/Chart.vue +++ b/@codexteam/ui/dev/pages/components/Chart.vue @@ -12,9 +12,24 @@
+
+ +
@@ -25,9 +40,24 @@
+
+ +
@@ -35,49 +65,356 @@ diff --git a/@codexteam/ui/src/vue/components/chart/Chart.types.ts b/@codexteam/ui/src/vue/components/chart/Chart.types.ts index 25a4fc03..d29562e1 100644 --- a/@codexteam/ui/src/vue/components/chart/Chart.types.ts +++ b/@codexteam/ui/src/vue/components/chart/Chart.types.ts @@ -18,12 +18,12 @@ export enum ChartLineColor { */ export interface ChartItem { /** - * Day midnight + * Timestamp of the data point */ timestamp: number; /** - * How many events occurred in that day + * Value at the timestamp */ count: number; } diff --git a/@codexteam/ui/src/vue/components/chart/Chart.vue b/@codexteam/ui/src/vue/components/chart/Chart.vue index eebf0604..0495ff20 100644 --- a/@codexteam/ui/src/vue/components/chart/Chart.vue +++ b/@codexteam/ui/src/vue/components/chart/Chart.vue @@ -94,6 +94,7 @@ import { ChartItem, ChartLineColors, ChartLine as ChartLineInterface } from './C import { chartColors } from './Chart.colors'; import AnimatedCounter from '../counter/Counter.vue'; import ChartLine from './ChartLine.vue'; +import { throttle } from '../../utils/app'; interface Props { /** @@ -281,44 +282,6 @@ function windowResized(): void { computeWrapperSize(); } -/** - * Throttle function to limit the rate of execution - * - * @param callback - Function to be throttled - * @param delay - Delay in milliseconds - */ -function throttle(callback: () => void, delay: number): () => void { - let lastExecTime = 0; - let timeoutId: ReturnType | null = null; - - return function (...args): void { - const currentTime = Date.now(); - const timeSinceLastExec = currentTime - lastExecTime; - - if (timeSinceLastExec >= delay) { - /* Execute immediately if enough time has passed */ - lastExecTime = currentTime; - // @ts-ignore - callback.apply(this, args); - } else { - /* Schedule execution for the remaining time */ - if (timeoutId !== null) { - clearTimeout(timeoutId); - } - - const remainingTime = delay - timeSinceLastExec; - - timeoutId = setTimeout(() => { - lastExecTime = Date.now(); - - // @ts-ignore - callback.apply(this, args); - timeoutId = null; - }, remainingTime); - } - }; -} - /** * Handler of window resize */ @@ -526,21 +489,7 @@ function formatTimestamp(timestamp: number): string { * @param value - number value */ function formatSpacedNumber(value: number): string { - const count = value.toString(); - const thousandRank = 3; - const negativeThousandRank = -3; - - if (count.length < thousandRank) { - return count; - } - - let result = ''; - - for (let i = 1; i <= Math.ceil(count.length / thousandRank); i++) { - result = `${count.slice(negativeThousandRank * i, negativeThousandRank * (i - 1) || undefined)} ` + result; - } - - return result.trim(); + return new Intl.NumberFormat('ru-RU').format(value); } onMounted(() => { diff --git a/@codexteam/ui/src/vue/utils/app/index.ts b/@codexteam/ui/src/vue/utils/app/index.ts new file mode 100644 index 00000000..80d707bd --- /dev/null +++ b/@codexteam/ui/src/vue/utils/app/index.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/** + * Throttle function to limit the rate of execution + * @param callback - Function to be throttled + * @param delay - Delay in milliseconds + */ +export function throttle(callback: () => void, delay: number): () => void { + let lastExecTime = 0; + let timeoutId: ReturnType | null = null; + + return function (...args): void { + const currentTime = Date.now(); + const timeSinceLastExec = currentTime - lastExecTime; + + if (timeSinceLastExec >= delay) { + /* Execute immediately if enough time has passed */ + lastExecTime = currentTime; + // @ts-ignore + callback.apply(this, args); + } else { + /* Schedule execution for the remaining time */ + if (timeoutId !== null) { + clearTimeout(timeoutId); + } + + const remainingTime = delay - timeSinceLastExec; + + timeoutId = setTimeout(() => { + lastExecTime = Date.now(); + + // @ts-ignore + callback.apply(this, args); + timeoutId = null; + }, remainingTime); + } + }; +} From 6496b6996f54856eddb4777333c24ffdda69d381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D1=83=D0=B0=D0=BD?= Date: Fri, 19 Dec 2025 19:52:18 +0300 Subject: [PATCH 3/5] fix: address review feedback --- @codexteam/ui/dev/pages/components/Chart.vue | 75 ++++--- .../ui/src/vue/components/chart/Chart.vue | 200 ++++++++---------- @codexteam/ui/src/vue/utils/index.ts | 3 + .../vue/utils/{app/index.ts => throttle.ts} | 0 4 files changed, 137 insertions(+), 141 deletions(-) create mode 100644 @codexteam/ui/src/vue/utils/index.ts rename @codexteam/ui/src/vue/utils/{app/index.ts => throttle.ts} (100%) diff --git a/@codexteam/ui/dev/pages/components/Chart.vue b/@codexteam/ui/dev/pages/components/Chart.vue index 2cd6ac64..e1692b40 100644 --- a/@codexteam/ui/dev/pages/components/Chart.vue +++ b/@codexteam/ui/dev/pages/components/Chart.vue @@ -5,28 +5,31 @@ A component for displaying line charts with smooth curves and interactive tooltips. - +

+ Select a time period using the first dropdown (e.g., last hour, day, week, or month). + The second dropdown controls how data is grouped within that period (by minutes, hours, or days). +

Single Line Chart
+
+ +
-
- -
+
+ +
-
- -
{ grid-template-columns: 1fr; gap: var(--spacing-l); margin-bottom: var(--spacing-xl); + position: relative; &__showcase { - position: relative; width: 100%; - height: 250px; background-color: var(--base--bg-secondary); border-radius: var(--radius-m); - padding: var(--spacing-m); } &__controls { @@ -446,5 +447,11 @@ watch(multiChartRange, (newRange) => { display: flex; gap: var(--spacing-s); } + + &__description { + margin-bottom: var(--spacing-m); + color: var(--base--text-secondary); + + } } diff --git a/@codexteam/ui/src/vue/components/chart/Chart.vue b/@codexteam/ui/src/vue/components/chart/Chart.vue index 0495ff20..dbc2b47a 100644 --- a/@codexteam/ui/src/vue/components/chart/Chart.vue +++ b/@codexteam/ui/src/vue/components/chart/Chart.vue @@ -9,16 +9,16 @@ class="chart__body" >
@@ -94,7 +94,17 @@ import { ChartItem, ChartLineColors, ChartLine as ChartLineInterface } from './C import { chartColors } from './Chart.colors'; import AnimatedCounter from '../counter/Counter.vue'; import ChartLine from './ChartLine.vue'; -import { throttle } from '../../utils/app'; +import { throttle } from '../../utils'; + +/** + * Prepared line with precomputed min/max/allZeros + */ +interface PreparedLine { + line: ChartLineInterface; + min: number; + max: number; + allZeros: boolean; +} interface Props { /** @@ -133,6 +143,45 @@ const hoveredIndex = ref(-1); */ const chart = ref(null); +/** + * Cached chart left position for performance + */ +const chartLeft = ref(0); + +/** + * Precomputed line data with min/max/allZeros + * This avoids recalculating O(n_data) on every render/mousemove + */ +const preparedLines = computed((): PreparedLine[] => { + return props.lines.map((line) => { + let min = Infinity; + let max = 0; + let allZeros = true; + + for (const item of line.data ?? []) { + const v = item.count ?? 0; + + if (v < min) { + min = v; + } + if (v > max) { + max = v; + } + if (v !== 0) { + allZeros = false; + } + } + + const safeMin = min === Infinity ? 0 : min; + const safeMax = max * 1.5; + + return { line, + min: safeMin, + max: safeMax, + allZeros }; + }); +}); + /** * Width of x-legend item */ @@ -267,12 +316,14 @@ function computeWrapperSize(): void { if (!svg) { chartWidth.value = 0; chartHeight.value = 0; + chartLeft.value = 0; return; } chartWidth.value = svg.clientWidth; chartHeight.value = svg.clientHeight - strokeWidth; + chartLeft.value = svg.getBoundingClientRect().left; } /** @@ -305,7 +356,7 @@ function moveTooltip(event: MouseEvent): void { return; } - const chartX = (event.currentTarget as HTMLElement).getBoundingClientRect().left; + const chartX = chartLeft.value; const cursorX = event.clientX - chartX; const newIndex = Math.round(cursorX / stepX.value); @@ -316,29 +367,28 @@ function moveTooltip(event: MouseEvent): void { /** * Get the Y coordinate for a line's pointer cursor at the hovered index + * Uses precomputed min/max from PreparedLine * - * @param line - the chart line + * @param prepared - the prepared line with precomputed values */ -function getLinePointerTop(line: ChartLineInterface): number { - if (hoveredIndex.value === -1 || !line || !line.data || line.data.length === 0) { +function getLinePointerTop(prepared: PreparedLine): number { + if (hoveredIndex.value === -1 || !prepared.line.data || prepared.line.data.length === 0) { return 0; } - const point = line.data[hoveredIndex.value]; + const point = prepared.line.data[hoveredIndex.value]; if (!point) { return 0; } - const lineMinValue = getLineMinValue(line); - const lineMaxValue = getLineMaxValue(line); - const lineKY = lineMaxValue === lineMinValue + const lineKY = prepared.max === prepared.min ? 1 - : chartHeight.value / (lineMaxValue - lineMinValue); + : chartHeight.value / (prepared.max - prepared.min); const currentValue = point.count ?? 0; - return chartHeight.value - (currentValue - lineMinValue) * lineKY; + return chartHeight.value - (currentValue - prepared.min) * lineKY; } /** @@ -389,72 +439,6 @@ function getCursorColor(line: ChartLineInterface): string { return color.pointerColor; } -/** - * Get minimum value for a specific line - * - * @param line - the chart line - */ -function getLineMinValue(line: ChartLineInterface): number { - if (!line || !line.data || line.data.length === 0) { - return 0; - } - - let min = Infinity; - - for (const item of line.data) { - if (item.count < min) { - min = item.count; - } - } - - return min === Infinity ? 0 : min; -} - -/** - * Check if all data counters of a line are 0 - * - * @param line - the chart line - */ -function isLineAllZeros(line: ChartLineInterface): boolean { - if (!line || !line.data || line.data.length === 0) { - return true; - } - - for (const item of line.data) { - if (item.count !== 0) { - return false; - } - } - - return true; -} - -/** - * Get maximum value for a specific line - * - * @param line - the chart line - */ -function getLineMaxValue(line: ChartLineInterface): number { - if (!line || !line.data || line.data.length === 0) { - return 0; - } - - let max = 0; - - for (const item of line.data) { - if (item.count > max) { - max = item.count; - } - } - - /** - * We will increment max value for 50% for adding some offset from the top - */ - const incrementForOffset = 1.5; - - return max * incrementForOffset; -} - /** * Formats timestamp based on detalization prop * @@ -514,7 +498,7 @@ onBeforeUnmount(() => { flex-direction: column; height: 215px; background-color: var(--base--bg-secondary); - border-radius: 3px; + border-radius: var(--radius-s); --legend-height: 40px; --legend-line-height: 11px; @@ -522,21 +506,21 @@ onBeforeUnmount(() => { &__info { position: absolute; - top: 15px; - right: 15px; - padding: 5px 10px; + top: var(--spacing-ml); + right: var(--spacing-ml); + padding: var(--spacing-xs) var(--spacing-ms); color: var(--base--text); font-size: 13px; white-space: nowrap; - background: color-mod(var(--base--bg) alpha(50%)); - border-radius: 5px; + background: color-mod(var(--base--bg-primary) alpha(50%)); + border-radius: var(--radius-s); &-today { color: var(--base--text-secondary); } &-highlight { - margin-left: 6px; + margin-left: var(--spacing-xs); font-weight: bold; } } @@ -548,6 +532,7 @@ onBeforeUnmount(() => { &__ox { height: var(--legend-height); padding-block: var(--legend-block-padding); + box-sizing: border-box; &-inner { position: relative; @@ -564,6 +549,7 @@ onBeforeUnmount(() => { text-align: center; transform-origin: center; opacity: 0.3; + white-space: nowrap; &:first-of-type, &:last-of-type { @@ -597,22 +583,22 @@ onBeforeUnmount(() => { } &-tooltip { - --tooltip-block-padding: 6px; + --tooltip-block-padding: var(--spacing-xs); position: absolute; top: calc(100% - var(--legend-height) + var(--legend-block-padding) - var(--tooltip-block-padding) - 1px); left: 50%; z-index: 500; padding-block: var(--tooltip-block-padding); - padding-inline: 8px; + padding-inline: var(--spacing-s); color: var(--base--text); font-size: 12px; line-height: 1.4; letter-spacing: 0.2px; white-space: nowrap; text-align: center; - background: #191C25; - border-radius: 7px; + background: var(--base--bg-primary); + border-radius: var(--radius-m); box-shadow: 0 7px 12px 0 rgba(0, 0, 0, 0.12); transform: translateX(-50%); transition: min-width 150ms ease; @@ -629,7 +615,7 @@ onBeforeUnmount(() => { } &-date { - margin-bottom: 2px; + margin-bottom: var(--spacing-very-x); color: var(--base--text-secondary); font-size: 11px; } diff --git a/@codexteam/ui/src/vue/utils/index.ts b/@codexteam/ui/src/vue/utils/index.ts new file mode 100644 index 00000000..073ec4a2 --- /dev/null +++ b/@codexteam/ui/src/vue/utils/index.ts @@ -0,0 +1,3 @@ +import { throttle } from './throttle'; + +export { throttle }; diff --git a/@codexteam/ui/src/vue/utils/app/index.ts b/@codexteam/ui/src/vue/utils/throttle.ts similarity index 100% rename from @codexteam/ui/src/vue/utils/app/index.ts rename to @codexteam/ui/src/vue/utils/throttle.ts From 5cd75ddffa22018f96f5e4310b9be84c0b3707d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D1=83=D0=B0=D0=BD?= Date: Mon, 22 Dec 2025 18:02:03 +0300 Subject: [PATCH 4/5] fix: address reviews feedback --- @codexteam/ui/dev/pages/components/Chart.vue | 485 +++++------------- .../src/vue/components/chart/Chart.colors.ts | 26 +- .../ui/src/vue/components/chart/Chart.vue | 19 +- .../ui/src/vue/components/chart/ChartLine.vue | 19 +- 4 files changed, 189 insertions(+), 360 deletions(-) diff --git a/@codexteam/ui/dev/pages/components/Chart.vue b/@codexteam/ui/dev/pages/components/Chart.vue index e1692b40..03e0de6d 100644 --- a/@codexteam/ui/dev/pages/components/Chart.vue +++ b/@codexteam/ui/dev/pages/components/Chart.vue @@ -5,150 +5,97 @@ A component for displaying line charts with smooth curves and interactive tooltips. -

- Select a time period using the first dropdown (e.g., last hour, day, week, or month). - The second dropdown controls how data is grouped within that period (by minutes, hours, or days). -

- - Single Line Chart - -
-
- +
+
+

+ lines +

+

+ An array of line objects to display on the chart. +

-
+ +
+

+ detalization +

+

+ Controls how timestamps are formatted on the X-axis legend and tooltip. + Does not affect data aggregation — only the display format. +

+
    +
  • 'days' — shows day and month (e.g., "19 dec")
  • +
  • 'hours' — shows day, month, and time (e.g., "19 dec, 14:00")
  • +
  • 'minutes' — shows day, month, and time (e.g., "19 dec, 14:30")
  • +
+
+ Try it: + -