Skip to content

Commit 0ae353e

Browse files
Merge pull request #332 from codex-team/feat/chart-component
feat: add componets chart and animatedCounter
2 parents 83002cf + ba6bd6d commit 0ae353e

File tree

14 files changed

+1518
-0
lines changed

14 files changed

+1518
-0
lines changed

@codexteam/ui/dev/Playground.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ const pages = computed(() => [
223223
onActivate: () => router.push('/components/confirm'),
224224
isActive: route.path === '/components/confirm',
225225
},
226+
{
227+
title: 'Counter',
228+
onActivate: () => router.push('/components/counter'),
229+
isActive: route.path === '/components/counter',
230+
},
231+
{
232+
title: 'Chart',
233+
onActivate: () => router.push('/components/chart'),
234+
isActive: route.path === '/components/chart',
235+
},
226236
],
227237
},
228238
]);
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
<template>
2+
<PageHeader>
3+
Chart
4+
<template #description>
5+
A component for displaying line charts with smooth curves and interactive tooltips.
6+
</template>
7+
</PageHeader>
8+
9+
<div class="chart-props">
10+
<div class="chart-props__item">
11+
<h4 class="chart-props__name">
12+
lines
13+
</h4>
14+
<p class="chart-props__description">
15+
An array of line objects to display on the chart.
16+
</p>
17+
</div>
18+
19+
<div class="chart-props__item">
20+
<h4 class="chart-props__name">
21+
detalization
22+
</h4>
23+
<p class="chart-props__description">
24+
Controls how timestamps are formatted on the X-axis legend and tooltip.
25+
Does not affect data aggregation — only the display format.
26+
</p>
27+
<ul class="chart-props__list">
28+
<li><code>'days'</code> — shows day and month (e.g., "19 dec")</li>
29+
<li><code>'hours'</code> — shows day, month, and time (e.g., "19 dec, 14:00")</li>
30+
<li><code>'minutes'</code> — shows day, month, and time (e.g., "19 dec, 14:30")</li>
31+
</ul>
32+
<div class="chart-props__control">
33+
<span class="chart-props__control-label">Try it:</span>
34+
<Select
35+
v-model="detalizationSelected"
36+
:align="{ vertically: 'below', horizontally: 'left' }"
37+
:is-disabled="false"
38+
:items="detalizationItems"
39+
/>
40+
</div>
41+
</div>
42+
</div>
43+
44+
<Heading :level="3">
45+
Single Line
46+
</Heading>
47+
<div class="chart-example">
48+
<div class="chart-example__showcase">
49+
<Chart
50+
:lines="[singleLineData]"
51+
:detalization="currentDetalization"
52+
/>
53+
</div>
54+
</div>
55+
56+
<Heading :level="3">
57+
Multiple Lines
58+
</Heading>
59+
<div class="chart-example">
60+
<div class="chart-example__showcase">
61+
<Chart
62+
:lines="multipleLinesData"
63+
:detalization="currentDetalization"
64+
/>
65+
</div>
66+
</div>
67+
</template>
68+
69+
<script setup lang="ts">
70+
import { ref, computed } from 'vue';
71+
import PageHeader from '../../components/PageHeader.vue';
72+
import { Chart, ChartLineColor, Heading, Select } from '../../../src/vue';
73+
import type { ChartItem, ChartLine } from '../../../src/vue/components/chart';
74+
import type { ContextMenuItem, DefaultItem } from '../../../src/vue/components/context-menu/ContextMenu.types';
75+
76+
/**
77+
* Detalization types for chart timestamp formatting
78+
*/
79+
type DetalizationValue = 'minutes' | 'hours' | 'days';
80+
81+
/**
82+
* Mapping from Select title to detalization value
83+
*/
84+
const detalizationMap: Record<string, DetalizationValue> = {
85+
days: 'days',
86+
hours: 'hours',
87+
minutes: 'minutes',
88+
};
89+
90+
/**
91+
* Generate sample chart data
92+
*
93+
* @param points - Number of data points to generate
94+
* @param intervalSeconds - Time interval between points in seconds
95+
* @param baseValue - Base value for random count generation
96+
*/
97+
function generateData(points: number, intervalSeconds: number, baseValue = 100): ChartItem[] {
98+
const now = Math.floor(Date.now() / 1000);
99+
100+
return Array.from({ length: points }, (_, i) => ({
101+
timestamp: now - (points - i) * intervalSeconds,
102+
count: Math.floor(Math.random() * baseValue) + Math.floor(baseValue / 2),
103+
}));
104+
}
105+
106+
/**
107+
* Empty handler for select option activation
108+
*/
109+
const onActivate = (): void => {};
110+
111+
/**
112+
* Currently selected detalization option
113+
*/
114+
const detalizationSelected = ref<DefaultItem>({
115+
title: 'days',
116+
onActivate,
117+
});
118+
119+
/**
120+
* Available detalization options for the Select component
121+
*/
122+
const detalizationItems: ContextMenuItem[] = [
123+
{ title: 'days',
124+
onActivate },
125+
{ title: 'hours',
126+
onActivate },
127+
{ title: 'minutes',
128+
onActivate },
129+
];
130+
131+
/**
132+
* Current detalization value derived from selected option
133+
*/
134+
const currentDetalization = computed<DetalizationValue>(() => {
135+
return detalizationMap[detalizationSelected.value.title] || 'days';
136+
});
137+
138+
/**
139+
* Single line chart data - 30 days of events
140+
*/
141+
const singleLineData = computed<ChartLine>(() => ({
142+
label: 'events',
143+
data: generateData(30, 86400, 2000),
144+
color: ChartLineColor.Red,
145+
}));
146+
147+
/**
148+
* Multiple lines chart data - accepted and filtered events
149+
*/
150+
const multipleLinesData = computed<ChartLine[]>(() => [
151+
{
152+
label: 'accepted',
153+
data: generateData(30, 86400, 150),
154+
color: ChartLineColor.Red,
155+
},
156+
{
157+
label: 'filtered',
158+
data: generateData(30, 86400, 50),
159+
color: ChartLineColor.LightGrey,
160+
},
161+
]);
162+
</script>
163+
164+
<style scoped>
165+
.chart-props {
166+
display: flex;
167+
flex-direction: column;
168+
gap: var(--spacing-l);
169+
margin-bottom: var(--spacing-xl);
170+
171+
&__item {
172+
padding: var(--spacing-m);
173+
background-color: var(--base--bg-secondary);
174+
border-radius: var(--radius-m);
175+
}
176+
177+
&__name {
178+
margin: 0 0 var(--spacing-s);
179+
}
180+
181+
&__description {
182+
margin: 0 0 var(--spacing-s);
183+
color: var(--base--text-secondary);
184+
}
185+
186+
&__code {
187+
margin: 0;
188+
padding: var(--spacing-s);
189+
background-color: var(--base--bg-primary);
190+
border-radius: var(--radius-s);
191+
overflow-x: auto;
192+
}
193+
194+
&__list {
195+
display: flex;
196+
flex-direction: column;
197+
gap: var(--spacing-s);
198+
margin: 0 0 var(--spacing-m);
199+
padding-left: var(--spacing-l);
200+
color: var(--base--text-secondary);
201+
202+
code {
203+
padding: var(--spacing-xxs) var(--spacing-ms);
204+
background-color: var(--base--bg-primary);
205+
border-radius: var(--radius-s);
206+
}
207+
}
208+
209+
&__control {
210+
display: flex;
211+
align-items: center;
212+
gap: var(--spacing-s);
213+
}
214+
215+
&__control-label {
216+
color: var(--base--text-secondary);
217+
}
218+
}
219+
220+
.chart-example {
221+
display: grid;
222+
grid-template-columns: 1fr;
223+
gap: var(--spacing-l);
224+
margin-bottom: var(--spacing-xl);
225+
position: relative;
226+
227+
&__showcase {
228+
width: 100%;
229+
background-color: var(--base--bg-secondary);
230+
border-radius: var(--radius-m);
231+
}
232+
233+
}
234+
</style>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<PageHeader>
3+
Counter
4+
<template #description>
5+
A component that animates value changes with a smooth slide transition effect.
6+
</template>
7+
</PageHeader>
8+
9+
<div class="counters">
10+
<div class="counters__value">
11+
<Counter :value="animatedValue" />
12+
</div>
13+
<div class="counters__btn">
14+
<Button
15+
16+
@click="animatedValue += 100"
17+
>
18+
+100
19+
</Button>
20+
<Button
21+
22+
@click="animatedValue -= 100"
23+
>
24+
-100
25+
</Button>
26+
<Button
27+
secondary
28+
@click="animatedValue = 0"
29+
>
30+
Reset
31+
</Button>
32+
</div>
33+
</div>
34+
</template>
35+
36+
<script setup lang="ts">
37+
import { ref } from 'vue';
38+
import PageHeader from '../../components/PageHeader.vue';
39+
import { Counter, Button } from '../../../src/vue';
40+
41+
const animatedValue = ref(100);
42+
43+
</script>
44+
45+
<style scoped>
46+
.counters {
47+
display: grid;
48+
grid-template-columns: repeat(2, max-content);
49+
gap: var(--spacing-xxl);
50+
align-items: center;
51+
&__value{
52+
width: 3rem;
53+
}
54+
&__btn{
55+
display: flex;
56+
gap: var(--spacing-m);
57+
align-items: center;
58+
}
59+
}
60+
61+
</style>

@codexteam/ui/dev/routes.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import Editor from './pages/components/Editor.vue';
3030
import ThemePreview from './pages/components/ThemePreview.vue';
3131
import Popup from './pages/components/Popup.vue';
3232
import Confirm from './pages/components/Confirm.vue';
33+
import Counter from './pages/components/Counter.vue';
34+
import Chart from './pages/components/Chart.vue';
3335
import Navbar from './pages/layout/Navbar.vue';
3436
import PageBlock from './pages/layout/PageBlock.vue';
3537

@@ -157,6 +159,14 @@ const routes: RouteRecordRaw[] = [
157159
path: '/components/confirm',
158160
component: Confirm as Component,
159161
},
162+
{
163+
path: '/components/counter',
164+
component: Counter as Component,
165+
},
166+
{
167+
path: '/components/chart',
168+
component: Chart as Component,
169+
},
160170
{
161171
path: '/layout/navbar',
162172
component: Navbar as Component,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ChartLineColor } from './Chart.types';
2+
import type { ChartLineColors } from './Chart.types';
3+
4+
/**
5+
* Colors for dark color scheme.
6+
*/
7+
export const chartColorsDark: ChartLineColors[] = [
8+
{
9+
name: ChartLineColor.LightGrey,
10+
strokeStart: 'rgba(75, 90, 121, 0.33)',
11+
strokeEnd: 'rgba(71, 72, 85, 0.16)',
12+
fillStart: 'rgba(63, 136, 255, 0.01)',
13+
fillEnd: 'rgba(66, 78, 93, 0.05)',
14+
pointerColor: '#717289',
15+
},
16+
{
17+
name: ChartLineColor.Red,
18+
strokeStart: '#FF2E51',
19+
strokeEnd: '#424565',
20+
fillStart: 'rgba(255, 46, 81, 0.3)',
21+
fillEnd: 'rgba(66, 69, 101, 0)',
22+
pointerColor: '#FF2E51',
23+
},
24+
];
25+
26+
/**
27+
* Colors for light color scheme.
28+
*/
29+
export const chartColorsLight: ChartLineColors[] = [
30+
{
31+
name: ChartLineColor.LightGrey,
32+
strokeStart: 'rgba(75, 90, 121, 0.22)',
33+
strokeEnd: 'rgba(71, 72, 85, 0.08)',
34+
fillStart: 'rgba(225, 236, 255, 0.12)',
35+
fillEnd: 'rgba(66, 78, 93, 0.02)',
36+
pointerColor: '#717289',
37+
},
38+
{
39+
name: ChartLineColor.Red,
40+
strokeStart: '#FF4A68',
41+
strokeEnd: 'rgba(119, 136, 198, 0.4)',
42+
fillStart: 'rgba(255, 94, 121, 0.46)',
43+
fillEnd: 'rgba(255, 190, 198, 0)',
44+
pointerColor: '#FF4A68',
45+
},
46+
];

0 commit comments

Comments
 (0)