feat: add basic webui
This commit is contained in:
271
apps/storybook/stories/chart.stories.tsx
Normal file
271
apps/storybook/stories/chart.stories.tsx
Normal file
@@ -0,0 +1,271 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
Label,
|
||||
Line,
|
||||
LineChart,
|
||||
Pie,
|
||||
PieChart,
|
||||
XAxis,
|
||||
} from 'recharts';
|
||||
|
||||
import {
|
||||
type ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from '@konobangu/design-system/components/ui/chart';
|
||||
|
||||
const multiSeriesData = [
|
||||
{ month: 'January', desktop: 186, mobile: 80 },
|
||||
{ month: 'February', desktop: 305, mobile: 200 },
|
||||
{ month: 'March', desktop: 237, mobile: 120 },
|
||||
{ month: 'April', desktop: 73, mobile: 190 },
|
||||
{ month: 'May', desktop: 209, mobile: 130 },
|
||||
{ month: 'June', desktop: 214, mobile: 140 },
|
||||
];
|
||||
|
||||
const multiSeriesConfig = {
|
||||
desktop: {
|
||||
label: 'Desktop',
|
||||
color: 'hsl(var(--chart-1))',
|
||||
},
|
||||
mobile: {
|
||||
label: 'Mobile',
|
||||
color: 'hsl(var(--chart-2))',
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
const singleSeriesData = [
|
||||
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
|
||||
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
|
||||
{ browser: 'other', visitors: 190, fill: 'var(--color-other)' },
|
||||
];
|
||||
|
||||
const singleSeriesConfig = {
|
||||
visitors: {
|
||||
label: 'Visitors',
|
||||
},
|
||||
chrome: {
|
||||
label: 'Chrome',
|
||||
color: 'hsl(var(--chart-1))',
|
||||
},
|
||||
safari: {
|
||||
label: 'Safari',
|
||||
color: 'hsl(var(--chart-2))',
|
||||
},
|
||||
other: {
|
||||
label: 'Other',
|
||||
color: 'hsl(var(--chart-5))',
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
/**
|
||||
* Beautiful charts. Built using Recharts. Copy and paste into your apps.
|
||||
*/
|
||||
const meta = {
|
||||
title: 'ui/Chart',
|
||||
component: ChartContainer,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {},
|
||||
args: {
|
||||
children: <div />,
|
||||
},
|
||||
} satisfies Meta<typeof ChartContainer>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
/**
|
||||
* Combine multiple Area components to create a stacked area chart.
|
||||
*/
|
||||
export const StackedAreaChart: Story = {
|
||||
args: {
|
||||
config: multiSeriesConfig,
|
||||
},
|
||||
render: (args) => (
|
||||
<ChartContainer {...args}>
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
data={multiSeriesData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="dot" />}
|
||||
/>
|
||||
<Area
|
||||
dataKey="mobile"
|
||||
type="natural"
|
||||
fill="var(--color-mobile)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--color-mobile)"
|
||||
stackId="a"
|
||||
/>
|
||||
<Area
|
||||
dataKey="desktop"
|
||||
type="natural"
|
||||
fill="var(--color-desktop)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--color-desktop)"
|
||||
stackId="a"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
),
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine multiple Bar components to create a stacked bar chart.
|
||||
*/
|
||||
export const StackedBarChart: Story = {
|
||||
args: {
|
||||
config: multiSeriesConfig,
|
||||
},
|
||||
render: (args) => (
|
||||
<ChartContainer {...args}>
|
||||
<BarChart accessibilityLayer data={multiSeriesData}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="dashed" />}
|
||||
/>
|
||||
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
|
||||
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
),
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine multiple Line components to create a single line chart.
|
||||
*/
|
||||
export const MultiLineChart: Story = {
|
||||
args: {
|
||||
config: multiSeriesConfig,
|
||||
},
|
||||
render: (args) => (
|
||||
<ChartContainer {...args}>
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
data={multiSeriesData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Line
|
||||
dataKey="desktop"
|
||||
type="natural"
|
||||
stroke="var(--color-desktop)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
<Line
|
||||
dataKey="mobile"
|
||||
type="natural"
|
||||
stroke="var(--color-mobile)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
),
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine Pie and Label components to create a doughnut chart.
|
||||
*/
|
||||
export const DoughnutChart: Story = {
|
||||
args: {
|
||||
config: singleSeriesConfig,
|
||||
},
|
||||
render: (args) => {
|
||||
const totalVisitors = useMemo(() => {
|
||||
return singleSeriesData.reduce((acc, curr) => acc + curr.visitors, 0);
|
||||
}, []);
|
||||
return (
|
||||
<ChartContainer {...args}>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={singleSeriesData}
|
||||
dataKey="visitors"
|
||||
nameKey="browser"
|
||||
innerRadius={48}
|
||||
strokeWidth={5}
|
||||
>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && 'cx' in viewBox && 'cy' in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground font-bold text-3xl"
|
||||
>
|
||||
{totalVisitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-muted-foreground"
|
||||
>
|
||||
Visitors
|
||||
</tspan>
|
||||
</text>
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user