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..03e0de6d --- /dev/null +++ b/@codexteam/ui/dev/pages/components/Chart.vue @@ -0,0 +1,234 @@ + + + + + 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..3dd1a96e --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/Chart.colors.ts @@ -0,0 +1,46 @@ +import { ChartLineColor } from './Chart.types'; +import type { ChartLineColors } from './Chart.types'; + +/** + * Colors for dark color scheme. + */ +export const chartColorsDark: 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', + }, +]; + +/** + * Colors for light color scheme. + */ +export const chartColorsLight: ChartLineColors[] = [ + { + name: ChartLineColor.LightGrey, + strokeStart: 'rgba(75, 90, 121, 0.22)', + strokeEnd: 'rgba(71, 72, 85, 0.08)', + fillStart: 'rgba(225, 236, 255, 0.12)', + fillEnd: 'rgba(66, 78, 93, 0.02)', + pointerColor: '#717289', + }, + { + name: ChartLineColor.Red, + strokeStart: '#FF4A68', + strokeEnd: 'rgba(119, 136, 198, 0.4)', + fillStart: 'rgba(255, 94, 121, 0.46)', + fillEnd: 'rgba(255, 190, 198, 0)', + pointerColor: '#FF4A68', + }, +]; 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..d29562e1 --- /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 { + /** + * Timestamp of the data point + */ + timestamp: number; + + /** + * Value at the timestamp + */ + 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..d1d586b7 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/Chart.vue @@ -0,0 +1,664 @@ + + + + + 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..fedbc1c2 --- /dev/null +++ b/@codexteam/ui/src/vue/components/chart/ChartLine.vue @@ -0,0 +1,265 @@ + + + + + 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'; 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/throttle.ts b/@codexteam/ui/src/vue/utils/throttle.ts new file mode 100644 index 00000000..80d707bd --- /dev/null +++ b/@codexteam/ui/src/vue/utils/throttle.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); + } + }; +}