Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 247 additions & 39 deletions @codexteam/ui/dev/pages/components/Chart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,39 @@
lines
</h4>
<p class="chart-props__description">
An array of line objects to display on the chart.
An array of line objects to display on the chart. Each line has
<code>label</code>, <code>data</code> and optional <code>color</code>.
</p>
</div>

<div class="chart-props__item">
<h4 class="chart-props__name">
lines[].color
</h4>
<p class="chart-props__description">
Built-in palette token, or a hex override. Omit it and the line stays red.
</p>
<ul class="chart-props__list">
<li>
<code>red</code>, <code>light-grey</code>, <code>blue</code>,
<code>green</code>, <code>orange</code>, <code>violet</code>,
<code>yellow</code>, <code>cyan</code>, <code>pink</code>
</li>
<li>hex override: <code>'#7CFF6B'</code></li>
</ul>
</div>

<div class="chart-props__item">
<h4 class="chart-props__name">
detalization
</h4>
<p class="chart-props__description">
Controls how timestamps are formatted on the X-axis legend and tooltip.
Does not affect data aggregation — only the display format.
Grain of the X-axis and tooltip timestamps. Preview data follows the selected step.
</p>
<ul class="chart-props__list">
<li><code>'days'</code> — shows day and month (e.g., "19 dec")</li>
<li><code>'hours'</code> — shows day, month, and time (e.g., "19 dec, 14:00")</li>
<li><code>'minutes'</code> — shows day, month, and time (e.g., "19 dec, 14:30")</li>
<li><code>'days'</code> — 30 daily points, labels like "19 dec"</li>
<li><code>'hours'</code> — 24 hourly points, labels like "19 dec, 14:00"</li>
<li><code>'minutes'</code> — 60 minute points, labels like "14:30"</li>
</ul>
<div class="chart-props__control">
<span class="chart-props__control-label">Try it:</span>
Expand All @@ -39,16 +56,43 @@
/>
</div>
</div>

<div class="chart-props__item">
<h4 class="chart-props__name">
legend
</h4>
<p class="chart-props__description">
Static series legend under the chart: color dot + <code>label</code> for each line.
Off by default so existing layouts stay the same.
</p>
<div class="chart-props__control">
<span class="chart-props__control-label">Try it:</span>
<Switch
v-model="legendEnabled"
:value="legendEnabled"
/>
</div>
</div>
</div>

<Heading :level="3">
Single Line
</Heading>
<div class="chart-example">
<div class="chart-example__toolbar">
<span class="chart-props__control-label">color:</span>
<Select
v-model="singleLineColorSelected"
:align="{ vertically: 'below', horizontally: 'left' }"
:is-disabled="false"
:items="paletteColorItems"
/>
</div>
<div class="chart-example__showcase">
<Chart
:lines="[singleLineData]"
:detalization="currentDetalization"
:legend="legendEnabled"
/>
</div>
</div>
Expand All @@ -61,6 +105,39 @@
<Chart
:lines="multipleLinesData"
:detalization="currentDetalization"
:legend="legendEnabled"
/>
</div>
</div>

<Heading :level="3">
Palette
</Heading>
<p class="chart-example-note">
Every hardcoded <code>ChartLineColor</code> token on one chart. No hex.
</p>
<div class="chart-example chart-example--tall">
<div class="chart-example__showcase">
<Chart
:lines="paletteSeriesData"
:detalization="currentDetalization"
:legend="legendEnabled"
/>
</div>
</div>

<Heading :level="3">
Hex override
</Heading>
<p class="chart-example-note">
Same series as Single Line, but <code>color: '#7CFF6B'</code>.
</p>
<div class="chart-example">
<div class="chart-example__showcase">
<Chart
:lines="[hexLineData]"
:detalization="currentDetalization"
:legend="legendEnabled"
/>
</div>
</div>
Expand All @@ -69,7 +146,7 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import PageHeader from '../../components/PageHeader.vue';
import { Chart, ChartLineColor, Heading, Select } from '../../../src/vue';
import { Chart, ChartLineColor, Heading, Select, Switch } from '../../../src/vue';
import type { ChartItem, ChartLine } from '../../../src/vue/components/chart';
import type { ContextMenuItem, DefaultItem } from '../../../src/vue/components/context-menu/ContextMenu.types';

Expand All @@ -88,17 +165,48 @@ const detalizationMap: Record<string, DetalizationValue> = {
};

/**
* Generate sample chart data
* Axis step for each detalization
*/
const detalizationConfig: Record<DetalizationValue, {
points: number;
intervalSeconds: number;
}> = {
days: {
points: 30,
intervalSeconds: 86400,
},
hours: {
points: 24,
intervalSeconds: 3600,
},
minutes: {
points: 60,
intervalSeconds: 60,
},
};

/**
* Shared timestamps aligned to the selected detalization bucket
*
* @param points - Number of data points to generate
* @param intervalSeconds - Time interval between points in seconds
* @param baseValue - Base value for random count generation
* @param points - Number of ticks
* @param intervalSeconds - Step between ticks
*/
function generateData(points: number, intervalSeconds: number, baseValue = 100): ChartItem[] {
function generateTimestamps(points: number, intervalSeconds: number): number[] {
const now = Math.floor(Date.now() / 1000);
const aligned = now - (now % intervalSeconds);

return Array.from({ length: points }, (_, i) => aligned - (points - 1 - i) * intervalSeconds);
}

return Array.from({ length: points }, (_, i) => ({
timestamp: now - (points - i) * intervalSeconds,
/**
* Generate sample chart data
*
* @param timestamps - Shared axis timestamps
* @param baseValue - Base value for random count generation
*/
function generateData(timestamps: number[], baseValue = 100): ChartItem[] {
return timestamps.map(timestamp => ({
timestamp,
count: Math.floor(Math.random() * baseValue) + Math.floor(baseValue / 2),
}));
}
Expand All @@ -116,6 +224,11 @@ const detalizationSelected = ref<DefaultItem>({
onActivate,
});

/**
* Toggle static series legend in the preview
*/
const legendEnabled = ref(true);

/**
* Available detalization options for the Select component
*/
Expand All @@ -136,29 +249,107 @@ const currentDetalization = computed<DetalizationValue>(() => {
});

/**
* Single line chart data - 30 days of events
* One axis for all preview charts, matching the selected detalization
*/
const demoTimestamps = computed((): number[] => {
const { points, intervalSeconds } = detalizationConfig[currentDetalization.value];

return generateTimestamps(points, intervalSeconds);
});

/**
* Built-in palette tokens, same order as ChartLineColor
*/
const singleLineData = computed<ChartLine>(() => ({
label: 'events',
data: generateData(30, 86400, 2000),
color: ChartLineColor.Red,
const paletteTokens: ChartLineColor[] = Object.values(ChartLineColor);

/**
* Fast lookup for Select titles
*/
const paletteTokenSet = new Set<string>(paletteTokens);

/**
* Color picker for the single-line preview
*/
const singleLineColorSelected = ref<DefaultItem>({
title: ChartLineColor.Red,
onActivate,
});

/**
* Palette options for the Single Line select
*/
const paletteColorItems: ContextMenuItem[] = paletteTokens.map(title => ({
title,
onActivate,
}));

/**
* Keep points stable when only the color token changes
*/
const singleLinePoints = computed((): ChartItem[] => {
return generateData(demoTimestamps.value, 2000);
});

/**
* Single line chart data
*/
const singleLineData = computed<ChartLine>(() => {
const title = singleLineColorSelected.value.title;
const color = paletteTokenSet.has(title)
? title as ChartLineColor
: ChartLineColor.Red;

return {
label: title,
data: singleLinePoints.value,
color,
};
});

/**
* Hex override demo — same points as Single Line
*/
const hexLineData = computed<ChartLine>(() => {
return {
label: '#7CFF6B',
data: singleLinePoints.value,
color: '#7CFF6B',
};
});

/**
* Multiple lines chart data - accepted and filtered events
*/
const multipleLinesData = computed<ChartLine[]>(() => [
{
label: 'accepted',
data: generateData(30, 86400, 150),
color: ChartLineColor.Red,
},
{
label: 'filtered',
data: generateData(30, 86400, 50),
color: ChartLineColor.LightGrey,
},
]);
const multipleLinesData = computed<ChartLine[]>(() => {
const timestamps = demoTimestamps.value;

return [
{
label: 'accepted',
data: generateData(timestamps, 150),
color: ChartLineColor.Red,
},
{
label: 'filtered',
data: generateData(timestamps, 50),
color: ChartLineColor.LightGrey,
},
];
});

/**
* All hardcoded palette tokens stacked for comparison
*/
const paletteSeriesData = computed<ChartLine[]>(() => {
const timestamps = demoTimestamps.value;
const bases = [150, 130, 110, 95, 80, 70, 55, 40, 25];

return paletteTokens.map((color, index) => ({
label: color,
data: generateData(timestamps, bases[index] ?? 50),
color,
}));
});
</script>

<style scoped>
Expand All @@ -181,14 +372,12 @@ const multipleLinesData = computed<ChartLine[]>(() => [
&__description {
margin: 0 0 var(--spacing-s);
color: var(--base--text-secondary);
}

&__code {
margin: 0;
padding: var(--spacing-s);
background-color: var(--base--bg-primary);
border-radius: var(--radius-s);
overflow-x: auto;
code {
padding: var(--spacing-xxs) var(--spacing-ms);
background-color: var(--base--bg-primary);
border-radius: var(--radius-s);
}
}

&__list {
Expand Down Expand Up @@ -217,18 +406,37 @@ const multipleLinesData = computed<ChartLine[]>(() => [
}
}

.chart-example-note {
margin: 0 0 var(--spacing-m);
color: var(--base--text-secondary);
}

.chart-example {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-l);
margin-bottom: var(--spacing-xl);
margin: 0 0 var(--spacing-xxl);
position: relative;

&__toolbar {
display: flex;
align-items: center;
gap: var(--spacing-s);
}

&__showcase {
width: 100%;
background-color: var(--base--bg-secondary);
border-radius: var(--radius-m);
}

&:last-child {
margin-bottom: 0;
padding-bottom: 180px;
}

&--tall {
padding-bottom: 240px;
}
}
</style>
2 changes: 1 addition & 1 deletion @codexteam/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codexteam/ui",
"version": "0.2.5",
"version": "0.2.6",
"type": "module",
"sideEffects": [
"*.css",
Expand Down
Loading
Loading