Merge branch 'master' into chrischinchilla/remove-auth-helpers

This commit is contained in:
Chris Chinchilla authored and GitHub committed 2025-12-11 12:50:52 +01:00
commit 6d2deba35f
640 files changed
+37120 -40316

No files matched your search

+2
View File
@@ -18,3 +18,5 @@
/apps/studio/components/interfaces/Billing/Payment @supabase/security
/apps/studio/components/interfaces/Organization/Documents/ @supabase/security
/apps/studio/pages/new/index.tsx @supabase/security
/apps/studio/data/sql/queries/ @supabase/postgres @avallete
+9 -4
View File
@@ -10,9 +10,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
autofix:
runs-on: blacksmith-2vcpu-ubuntu-2404
@@ -23,10 +20,18 @@ jobs:
- name: Calculate number of commits
run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}"
- name: Generate token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_AUTOFIX_APP_ID }}
private-key: ${{ secrets.GH_AUTOFIX_PRIVATE_KEY }}
permission-contents: write
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.PAT_AUTOFIX }}
token: ${{ steps.app-token.outputs.token }}
fetch-depth: ${{ env.PR_FETCH_DEPTH }}
sparse-checkout: |
packages
+12 -3
View File
@@ -10,8 +10,7 @@ concurrency:
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
contents: read
jobs:
build:
@@ -21,6 +20,16 @@ jobs:
with:
ref: master
- uses: sobolevn/misspell-fixer-action@06ff0b508d4f4c0ba70d15f9a628232c0aade536 # v0.1.0
- name: Generate token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_AUTOFIX_APP_ID }}
private-key: ${{ secrets.GH_AUTOFIX_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ steps.app-token.outputs.token }}
+1 -1
View File
@@ -24,7 +24,7 @@
"@payloadcms/db-postgres": "^3.52.0",
"@payloadcms/live-preview-react": "^3.52.0",
"@payloadcms/next": "3.52.0",
"@payloadcms/payload-cloud": "3.52.0",
"@payloadcms/payload-cloud": "3.60.0",
"@payloadcms/plugin-form-builder": "3.52.0",
"@payloadcms/plugin-nested-docs": "3.52.0",
"@payloadcms/plugin-seo": "3.52.0",
@@ -1,91 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'An area chart with axes'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Axes</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: -20,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<YAxis tickLine={false} axisLine={false} tickMargin={8} tickCount={3} />
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
<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>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,77 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A simple area chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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="line" />} />
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,100 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'An area chart with gradient fill'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Gradient</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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 />} />
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-desktop)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
</linearGradient>
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
</linearGradient>
</defs>
<Area
dataKey="mobile"
type="natural"
fill="url(#fillMobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="url(#fillDesktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,100 +0,0 @@
'use client'
import { TrendingDown, TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'An area chart with icons'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
icon: TrendingDown,
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
icon: TrendingUp,
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Icons</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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="line" />} />
<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"
/>
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,238 +0,0 @@
'use client'
import * as React from 'react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
import {
Select_Shadcn_,
SelectContent_Shadcn_,
SelectItem_Shadcn_,
SelectTrigger_Shadcn_,
SelectValue_Shadcn_,
} from 'ui'
export const description = 'An interactive area chart'
const chartData = [
{ date: '2024-04-01', desktop: 222, mobile: 150 },
{ date: '2024-04-02', desktop: 97, mobile: 180 },
{ date: '2024-04-03', desktop: 167, mobile: 120 },
{ date: '2024-04-04', desktop: 242, mobile: 260 },
{ date: '2024-04-05', desktop: 373, mobile: 290 },
{ date: '2024-04-06', desktop: 301, mobile: 340 },
{ date: '2024-04-07', desktop: 245, mobile: 180 },
{ date: '2024-04-08', desktop: 409, mobile: 320 },
{ date: '2024-04-09', desktop: 59, mobile: 110 },
{ date: '2024-04-10', desktop: 261, mobile: 190 },
{ date: '2024-04-11', desktop: 327, mobile: 350 },
{ date: '2024-04-12', desktop: 292, mobile: 210 },
{ date: '2024-04-13', desktop: 342, mobile: 380 },
{ date: '2024-04-14', desktop: 137, mobile: 220 },
{ date: '2024-04-15', desktop: 120, mobile: 170 },
{ date: '2024-04-16', desktop: 138, mobile: 190 },
{ date: '2024-04-17', desktop: 446, mobile: 360 },
{ date: '2024-04-18', desktop: 364, mobile: 410 },
{ date: '2024-04-19', desktop: 243, mobile: 180 },
{ date: '2024-04-20', desktop: 89, mobile: 150 },
{ date: '2024-04-21', desktop: 137, mobile: 200 },
{ date: '2024-04-22', desktop: 224, mobile: 170 },
{ date: '2024-04-23', desktop: 138, mobile: 230 },
{ date: '2024-04-24', desktop: 387, mobile: 290 },
{ date: '2024-04-25', desktop: 215, mobile: 250 },
{ date: '2024-04-26', desktop: 75, mobile: 130 },
{ date: '2024-04-27', desktop: 383, mobile: 420 },
{ date: '2024-04-28', desktop: 122, mobile: 180 },
{ date: '2024-04-29', desktop: 315, mobile: 240 },
{ date: '2024-04-30', desktop: 454, mobile: 380 },
{ date: '2024-05-01', desktop: 165, mobile: 220 },
{ date: '2024-05-02', desktop: 293, mobile: 310 },
{ date: '2024-05-03', desktop: 247, mobile: 190 },
{ date: '2024-05-04', desktop: 385, mobile: 420 },
{ date: '2024-05-05', desktop: 481, mobile: 390 },
{ date: '2024-05-06', desktop: 498, mobile: 520 },
{ date: '2024-05-07', desktop: 388, mobile: 300 },
{ date: '2024-05-08', desktop: 149, mobile: 210 },
{ date: '2024-05-09', desktop: 227, mobile: 180 },
{ date: '2024-05-10', desktop: 293, mobile: 330 },
{ date: '2024-05-11', desktop: 335, mobile: 270 },
{ date: '2024-05-12', desktop: 197, mobile: 240 },
{ date: '2024-05-13', desktop: 197, mobile: 160 },
{ date: '2024-05-14', desktop: 448, mobile: 490 },
{ date: '2024-05-15', desktop: 473, mobile: 380 },
{ date: '2024-05-16', desktop: 338, mobile: 400 },
{ date: '2024-05-17', desktop: 499, mobile: 420 },
{ date: '2024-05-18', desktop: 315, mobile: 350 },
{ date: '2024-05-19', desktop: 235, mobile: 180 },
{ date: '2024-05-20', desktop: 177, mobile: 230 },
{ date: '2024-05-21', desktop: 82, mobile: 140 },
{ date: '2024-05-22', desktop: 81, mobile: 120 },
{ date: '2024-05-23', desktop: 252, mobile: 290 },
{ date: '2024-05-24', desktop: 294, mobile: 220 },
{ date: '2024-05-25', desktop: 201, mobile: 250 },
{ date: '2024-05-26', desktop: 213, mobile: 170 },
{ date: '2024-05-27', desktop: 420, mobile: 460 },
{ date: '2024-05-28', desktop: 233, mobile: 190 },
{ date: '2024-05-29', desktop: 78, mobile: 130 },
{ date: '2024-05-30', desktop: 340, mobile: 280 },
{ date: '2024-05-31', desktop: 178, mobile: 230 },
{ date: '2024-06-01', desktop: 178, mobile: 200 },
{ date: '2024-06-02', desktop: 470, mobile: 410 },
{ date: '2024-06-03', desktop: 103, mobile: 160 },
{ date: '2024-06-04', desktop: 439, mobile: 380 },
{ date: '2024-06-05', desktop: 88, mobile: 140 },
{ date: '2024-06-06', desktop: 294, mobile: 250 },
{ date: '2024-06-07', desktop: 323, mobile: 370 },
{ date: '2024-06-08', desktop: 385, mobile: 320 },
{ date: '2024-06-09', desktop: 438, mobile: 480 },
{ date: '2024-06-10', desktop: 155, mobile: 200 },
{ date: '2024-06-11', desktop: 92, mobile: 150 },
{ date: '2024-06-12', desktop: 492, mobile: 420 },
{ date: '2024-06-13', desktop: 81, mobile: 130 },
{ date: '2024-06-14', desktop: 426, mobile: 380 },
{ date: '2024-06-15', desktop: 307, mobile: 350 },
{ date: '2024-06-16', desktop: 371, mobile: 310 },
{ date: '2024-06-17', desktop: 475, mobile: 520 },
{ date: '2024-06-18', desktop: 107, mobile: 170 },
{ date: '2024-06-19', desktop: 341, mobile: 290 },
{ date: '2024-06-20', desktop: 408, mobile: 450 },
{ date: '2024-06-21', desktop: 169, mobile: 210 },
{ date: '2024-06-22', desktop: 317, mobile: 270 },
{ date: '2024-06-23', desktop: 480, mobile: 530 },
{ date: '2024-06-24', desktop: 132, mobile: 180 },
{ date: '2024-06-25', desktop: 141, mobile: 190 },
{ date: '2024-06-26', desktop: 434, mobile: 380 },
{ date: '2024-06-27', desktop: 448, mobile: 490 },
{ date: '2024-06-28', desktop: 149, mobile: 200 },
{ date: '2024-06-29', desktop: 103, mobile: 160 },
{ date: '2024-06-30', desktop: 446, mobile: 400 },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
const [timeRange, setTimeRange] = React.useState('90d')
const filteredData = chartData.filter((item) => {
const date = new Date(item.date)
const now = new Date()
let daysToSubtract = 90
if (timeRange === '30d') {
daysToSubtract = 30
} else if (timeRange === '7d') {
daysToSubtract = 7
}
now.setDate(now.getDate() - daysToSubtract)
return date >= now
})
return (
<Card>
<CardHeader className="flex items-center gap-2 space-y-0 border-b py-5 sm:flex-row">
<div className="grid flex-1 gap-1 text-center sm:text-left">
<CardTitle>Area Chart - Interactive</CardTitle>
<CardDescription>Showing total visitors for the last 3 months</CardDescription>
</div>
<Select_Shadcn_ value={timeRange} onValueChange={setTimeRange}>
<SelectTrigger_Shadcn_
className="w-[160px] rounded-lg sm:ml-auto"
aria-label="Select a value"
>
<SelectValue_Shadcn_ placeholder="Last 3 months" />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_ className="rounded-xl">
<SelectItem_Shadcn_ value="90d" className="rounded-lg">
Last 3 months
</SelectItem_Shadcn_>
<SelectItem_Shadcn_ value="30d" className="rounded-lg">
Last 30 days
</SelectItem_Shadcn_>
<SelectItem_Shadcn_ value="7d" className="rounded-lg">
Last 7 days
</SelectItem_Shadcn_>
</SelectContent_Shadcn_>
</Select_Shadcn_>
</CardHeader>
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
<ChartContainer config={chartConfig} className="aspect-auto h-[250px] w-full">
<AreaChart data={filteredData}>
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-desktop)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
</linearGradient>
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
</linearGradient>
</defs>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
})
}}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent
labelFormatter={(value) => {
return new Date(value).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
})
}}
indicator="dot"
/>
}
/>
<Area
dataKey="mobile"
type="natural"
fill="url(#fillMobile)"
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="url(#fillDesktop)"
stroke="var(--color-desktop)"
stackId="a"
/>
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
)
}
@@ -1,98 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'An area chart with a legend'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Legend</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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="line" />} />
<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"
/>
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,80 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A linear area chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Linear</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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" hideLabel />}
/>
<Area
dataKey="desktop"
type="linear"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,104 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A stacked area chart with expand stacking'
const chartData = [
{ month: 'January', desktop: 186, mobile: 80, other: 45 },
{ month: 'February', desktop: 305, mobile: 200, other: 100 },
{ month: 'March', desktop: 237, mobile: 120, other: 150 },
{ month: 'April', desktop: 73, mobile: 190, other: 50 },
{ month: 'May', desktop: 209, mobile: 130, other: 100 },
{ month: 'June', desktop: 214, mobile: 140, other: 160 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-3))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Stacked Expanded</CardTitle>
<CardDescription>Showing total visitors for the last 6months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: 12,
right: 12,
top: 12,
}}
stackOffset="expand"
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<Area
dataKey="other"
type="natural"
fill="var(--color-other)"
fillOpacity={0.1}
stroke="var(--color-other)"
stackId="a"
/>
<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>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,90 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A stacked area chart'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Stacked</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,78 +0,0 @@
'use client'
import { Activity, TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A step area chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
icon: Activity,
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Step</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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 />} />
<Area
dataKey="desktop"
type="step"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,94 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, Rectangle, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A bar chart with an active bar'
const chartData = [
{ browser: 'chrome', visitors: 187, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 275, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Active</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="browser"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => chartConfig[value as keyof typeof chartConfig]?.label}
/>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Bar
dataKey="visitors"
strokeWidth={2}
radius={8}
activeIndex={2}
activeBar={({ ...props }) => {
return (
<Rectangle
{...props}
fillOpacity={0.8}
stroke={props.payload.fill}
strokeDasharray={4}
strokeDashoffset={4}
/>
)
}}
/>
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,60 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A bar chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={8} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,68 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, XAxis, YAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A horizontal bar chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Horizontal</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart
accessibilityLayer
data={chartData}
layout="vertical"
margin={{
left: -20,
}}
>
<XAxis type="number" dataKey="desktop" hide />
<YAxis
dataKey="month"
type="category"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={5} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,92 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, LabelList, XAxis, YAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A bar chart with a custom label'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
label: {
color: 'hsl(var(--background))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Custom Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart
accessibilityLayer
data={chartData}
layout="vertical"
margin={{
right: 16,
}}
>
<CartesianGrid horizontal={false} />
<YAxis
dataKey="month"
type="category"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
hide
/>
<XAxis dataKey="desktop" type="number" hide />
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<Bar dataKey="desktop" layout="vertical" fill="var(--color-desktop)" radius={4}>
<LabelList
dataKey="month"
position="insideLeft"
offset={8}
className="fill-[--color-label]"
fontSize={12}
/>
<LabelList
dataKey="desktop"
position="right"
offset={8}
className="fill-foreground"
fontSize={12}
/>
</Bar>
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,68 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, LabelList, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A bar chart with a label'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart
accessibilityLayer
data={chartData}
margin={{
top: 20,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={8}>
<LabelList position="top" offset={12} className="fill-foreground" fontSize={12} />
</Bar>
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,86 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, XAxis, YAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A mixed bar chart'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Mixed</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart
accessibilityLayer
data={chartData}
layout="vertical"
margin={{
left: 0,
}}
>
<YAxis
dataKey="browser"
type="category"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => chartConfig[value as keyof typeof chartConfig]?.label}
/>
<XAxis dataKey="visitors" type="number" hide />
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Bar dataKey="visitors" layout="vertical" radius={5} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,65 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A multiple bar chart'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Multiple</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<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>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,63 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, Cell, LabelList } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A bar chart with negative values'
const chartData = [
{ month: 'January', visitors: 186 },
{ month: 'February', visitors: 205 },
{ month: 'March', visitors: -207 },
{ month: 'April', visitors: 173 },
{ month: 'May', visitors: -209 },
{ month: 'June', visitors: 214 },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Negative</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel hideIndicator />}
/>
<Bar dataKey="visitors">
<LabelList position="top" dataKey="month" fillOpacity={1} />
{chartData.map((item) => (
<Cell
key={item.month}
fill={item.visitors > 0 ? 'hsl(var(--chart-1))' : 'hsl(var(--chart-2))'}
/>
))}
</Bar>
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'A stacked bar chart with a legend'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Bar Chart - Stacked + Legend</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="desktop" stackId="a" fill="var(--color-desktop)" radius={[0, 0, 4, 4]} />
<Bar dataKey="mobile" stackId="a" fill="var(--color-mobile)" radius={[4, 4, 0, 0]} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -0,0 +1,106 @@
'use client'
import {
Chart,
ChartActions,
ChartCard,
ChartContent,
ChartHeader,
ChartTitle,
ChartEmptyState,
ChartLoadingState,
ChartBar,
ChartLine,
} from 'ui-patterns/Chart'
import { BarChart2, ExternalLink, LineChart } from 'lucide-react'
import { useState, useEffect } from 'react'
export default function ChartComposedActions() {
const [isLoading, setIsLoading] = useState(true)
const [chartType, setChartType] = useState<'bar' | 'line'>('bar')
const actions = [
{
label: 'Open in Logs Explorer',
onClick: () => {
alert('Opening in Logs Explorer...')
},
icon: <ExternalLink size={12} />,
},
{
label: 'Toggle Chart Type',
onClick: () => {
setChartType(chartType === 'bar' ? 'line' : 'bar')
},
icon: chartType === 'bar' ? <LineChart size={12} /> : <BarChart2 size={12} />,
},
]
const data = Array.from({ length: 46 }, (_, i) => {
const date = new Date()
date.setMinutes(date.getMinutes() - i * 5) // Each point 5 minutes apart
return {
timestamp: date.toISOString(),
requests: Math.floor(Math.random() * 100),
}
}).reverse()
useEffect(() => {
setTimeout(() => {
setIsLoading(false)
}, 1000)
}, [])
return (
<div className="flex flex-col gap-6 w-8/12">
<Chart isLoading={isLoading}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Total Requests</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
isEmpty={data.length === 0}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={16} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
<div className="h-40">
{chartType === 'bar' ? (
<ChartBar
data={data}
dataKey="requests"
showGrid={false}
showYAxis={true}
YAxisProps={{
tickFormatter: (value) => `${value}k`,
width: 80,
}}
isFullHeight={true}
/>
) : (
<ChartLine
data={data}
dataKey="requests"
showGrid={true}
showYAxis={true}
YAxisProps={{
tickFormatter: (value) => `${value}k`,
width: 80,
}}
isFullHeight={true}
/>
)}
</div>
</ChartContent>
</ChartCard>
</Chart>
</div>
)
}
@@ -0,0 +1,122 @@
'use client'
import {
Chart,
ChartActions,
ChartCard,
ChartContent,
ChartHeader,
ChartTitle,
ChartEmptyState,
ChartLoadingState,
ChartBar,
ChartLine,
} from 'ui-patterns/Chart'
import { BarChart2, ExternalLink } from 'lucide-react'
import { useState, useEffect } from 'react'
export default function ComposedChartBasic() {
const [isLoading, setIsLoading] = useState(true)
const actions = [
{
label: 'Open in Logs Explorer',
onClick: () => {
alert('Ta da! You clicked me! 🎉')
},
icon: <ExternalLink size={12} />,
},
]
const data = Array.from({ length: 46 }, (_, i) => {
const date = new Date()
date.setMinutes(date.getMinutes() - i * 5) // Each point 5 minutes apart
return {
timestamp: date.toISOString(),
standard_score: Math.floor(Math.random() * 100),
}
}).reverse()
useEffect(() => {
setTimeout(() => {
setIsLoading(false)
}, 1000)
}, [])
return (
<div className="flex flex-col gap-6 w-8/12">
<Chart isLoading={isLoading}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Standard Bar Chart</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
isEmpty={data.length === 0}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={16} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
<div className="h-40">
<ChartBar
data={data}
dataKey="standard_score"
showGrid={false}
showYAxis={true}
YAxisProps={{
tickFormatter: (value) => `${value}k`,
width: 80,
}}
isFullHeight={true}
/>
</div>
</ChartContent>
</ChartCard>
</Chart>
<Chart isLoading={isLoading}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Standard Line Chart</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
isEmpty={data.length === 0}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={16} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
<div className="h-40">
<ChartLine
data={data}
dataKey="standard_score"
showGrid={true}
showYAxis={true}
YAxisProps={{
tickFormatter: (value) => `${value}k`,
width: 80,
}}
isFullHeight={true}
/>
</div>
</ChartContent>
</ChartCard>
</Chart>
</div>
)
}
@@ -0,0 +1,73 @@
'use client'
import {
Chart,
ChartCard,
ChartContent,
ChartHeader,
ChartEmptyState,
ChartLoadingState,
ChartMetric,
} from 'ui-patterns/Chart'
import { BarChart2 } from 'lucide-react'
import { LogsBarChart } from 'ui-patterns/LogsBarChart'
import { useState, useEffect } from 'react'
export default function ComposedChartDemo() {
const [isLoading, setIsLoading] = useState(true)
const data = Array.from({ length: 60 }, (_, i) => {
const date = new Date()
date.setMinutes(date.getMinutes() - i * 5) // Each point 5 minutes apart
return {
timestamp: date.toISOString(),
ok_count: Math.floor(Math.random() * 100), // Random value 0-99
error_count: Math.floor(Math.random() * 50), // Random value 0-50
warning_count: Math.floor(Math.random() * 50), // Random value 0-50
}
}).reverse()
const totalUsersValue = 4663
useEffect(() => {
setTimeout(() => {
setIsLoading(false)
}, 1000)
}, [])
return (
<div className="w-8/12">
<Chart isLoading={isLoading}>
<ChartCard>
<ChartHeader>
<ChartMetric
label="Total Users"
value={totalUsersValue.toLocaleString('en-US')}
tooltip="This is a tooltip"
/>
<div className="flex items-center gap-6">
<ChartMetric label="Warn" value="1.2k" status="warning" align="end" />
<ChartMetric label="Err" value="736" status="negative" align="end" />
</div>
</ChartHeader>
<ChartContent
isEmpty={data.length === 0}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={16} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
<div className="h-40">
<LogsBarChart data={data} isFullHeight={true} />
</div>
</ChartContent>
</ChartCard>
</Chart>
</div>
)
}
@@ -0,0 +1,100 @@
'use client'
import {
Chart,
ChartCard,
ChartHeader,
ChartActions,
ChartContent,
ChartMetric,
ChartSparkline,
} from 'ui-patterns/Chart'
import { ExternalLink } from 'lucide-react'
import { useState, useEffect } from 'react'
import { Skeleton } from 'ui'
export default function ChartComposedMetrics() {
const [data, setData] = useState<Array<{ value: number; timestamp: string }>>([])
const actions = [
{
label: 'Open in Logs Explorer',
onClick: () => {
alert('Ta da! You clicked me! 🎉')
},
icon: <ExternalLink size={12} />,
},
]
useEffect(() => {
const now = new Date()
setData(
Array.from({ length: 12 }, (_, i) => ({
value: Math.floor(4000 + i * 100 + (Math.random() * 2000 - 800)),
timestamp: new Date(now.getTime() - (11 - i) * 60 * 60 * 1000).toISOString(),
}))
)
}, [])
const averageValue = data.reduce((acc, curr) => acc + curr.value, 0) / data.length
const diff = data[data.length - 1]?.value - data[0]?.value || 0
const diffPercentage = (diff / averageValue) * 100
return (
<div className="grid grid-cols-2 gap-6 w-full">
<Chart isLoading={!data.length}>
<ChartCard>
<ChartHeader className="pb-4" align="start">
<ChartMetric label="Slow Queries" value={0} />
<ChartActions actions={actions} />
</ChartHeader>
</ChartCard>
</Chart>
<Chart isLoading={!data.length}>
<ChartCard>
<ChartHeader className="pb-4" align="start">
<ChartMetric label="Sign Ups" value={127} />
<ChartActions actions={actions} />
</ChartHeader>
</ChartCard>
</Chart>
<Chart isLoading={!data.length}>
<ChartCard>
<ChartHeader align="start">
<ChartMetric
label="Active Users"
value={averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
diffValue={diffPercentage.toFixed(2) + '%'}
/>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
</ChartCard>
</Chart>
<Chart isLoading={!data.length}>
<ChartCard>
<ChartHeader align="start">
<ChartMetric
label="Active Users"
value={averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
diffValue={diffPercentage.toFixed(2) + '%'}
/>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
</ChartCard>
</Chart>
</div>
)
}
@@ -0,0 +1,92 @@
'use client'
import { BarChart2, ExternalLink } from 'lucide-react'
import {
Chart,
ChartCard,
ChartHeader,
ChartTitle,
ChartActions,
ChartContent,
ChartEmptyState,
ChartLoadingState,
ChartDisabledState,
} from 'ui-patterns/Chart'
import { Badge } from 'ui'
export default function ChartComposedStates() {
const actions = [
{
label: 'Open in Logs Explorer',
onClick: () => {
alert('Ta da! You clicked me! 🎉')
},
icon: <ExternalLink size={12} />,
},
]
const disabledActions = [
{
label: 'Upgrade to Pro',
href: '#',
},
]
return (
<div className="flex flex-col gap-6 w-8/12">
<Chart isLoading={true}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Response Errors</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent loadingState={<ChartLoadingState />}>My chart here...</ChartContent>
</ChartCard>
</Chart>
<Chart>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Response Errors</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
isEmpty={true}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={20} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
My chart here...
</ChartContent>
</ChartCard>
</Chart>
<Chart isDisabled={true}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Response Errors</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
loadingState={<ChartLoadingState />}
disabledState={
<ChartDisabledState
icon={<Badge variant="success">Pro</Badge>}
label="API Processing Time"
description="This chart is available on the Pro plan and above"
actions={disabledActions}
/>
}
>
My chart here...
</ChartContent>
</ChartCard>
</Chart>
</div>
)
}
@@ -0,0 +1,106 @@
'use client'
import {
Chart,
ChartActions,
ChartCard,
ChartContent,
ChartHeader,
ChartTitle,
ChartEmptyState,
ChartLoadingState,
ChartBar,
ChartFooter,
} from 'ui-patterns/Chart'
import { BarChart2, ExternalLink } from 'lucide-react'
import { useState, useEffect } from 'react'
import { Table, TableHead, TableBody, TableRow, TableCell, TableHeader } from 'ui'
import { format } from 'date-fns'
export default function ChartComposedTable() {
const [isLoading, setIsLoading] = useState(true)
const actions = [
{
label: 'Open in Logs Explorer',
onClick: () => {
alert('Opening in Logs Explorer...')
},
icon: <ExternalLink size={12} />,
},
]
const data = Array.from({ length: 46 }, (_, i) => {
const date = new Date()
date.setMinutes(date.getMinutes() - i * 5) // Each point 5 minutes apart
return {
timestamp: date.toISOString(),
standard_score: Math.floor(Math.random() * 100),
}
}).reverse()
useEffect(() => {
setTimeout(() => {
setIsLoading(false)
}, 1000)
}, [])
return (
<div className="flex flex-col gap-6 w-8/12">
<Chart isLoading={isLoading}>
<ChartCard>
<ChartHeader>
<ChartTitle tooltip="This is a tooltip">Standard Bar Chart</ChartTitle>
<ChartActions actions={actions} />
</ChartHeader>
<ChartContent
isEmpty={data.length === 0}
emptyState={
<ChartEmptyState
icon={<BarChart2 size={16} />}
title="No data to show"
description="It may take up to 24 hours for data to refresh"
/>
}
loadingState={<ChartLoadingState />}
>
<div className="h-40">
<ChartBar
data={data}
dataKey="standard_score"
showGrid={false}
showYAxis={true}
YAxisProps={{
tickFormatter: (value) => `${value}k`,
width: 80,
}}
isFullHeight={true}
/>
</div>
</ChartContent>
<ChartFooter>
<Table>
<TableHeader>
<TableRow>
<TableHead>Timestamp</TableHead>
<TableHead className="text-right">Standard Score</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.slice(0, 3).map((item) => (
<TableRow key={item.timestamp}>
<TableCell className="text-foreground-light">
{format(new Date(item.timestamp), 'MMM d, yyyy h:mm a')}
</TableCell>
<TableCell className="text-right tabular-nums">{item.standard_score}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ChartFooter>
</ChartCard>
</Chart>
</div>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,100 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Dot, Line, LineChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with dots and colors'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
color: 'hsl(var(--chart-2))',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Dots Colors</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
margin={{
top: 24,
left: 24,
right: 24,
}}
>
<CartesianGrid vertical={false} />
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="line" nameKey="visitors" hideLabel />}
/>
<Line
dataKey="visitors"
type="natural"
stroke="var(--color-visitors)"
strokeWidth={2}
dot={({ payload, ...props }) => {
return (
<Dot
key={payload.browser}
r={5}
cx={props.cx}
cy={props.cy}
fill={payload.fill}
stroke={payload.fill}
/>
)
}}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,90 +0,0 @@
'use client'
import { GitCommitVertical, TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with custom dots'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Custom Dots</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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={({ cx, cy, payload }) => {
const r = 24
return (
<GitCommitVertical
key={payload.month}
x={cx - r / 2}
y={cy - r / 2}
width={r}
height={r}
fill="hsl(var(--background))"
stroke="var(--color-desktop)"
/>
)
}}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,82 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with dots'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Dots</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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={{
fill: 'var(--color-desktop)',
}}
activeDot={{
r: 6,
}}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,208 +0,0 @@
'use client'
import * as React from 'react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'An interactive line chart'
const chartData = [
{ date: '2024-04-01', desktop: 222, mobile: 150 },
{ date: '2024-04-02', desktop: 97, mobile: 180 },
{ date: '2024-04-03', desktop: 167, mobile: 120 },
{ date: '2024-04-04', desktop: 242, mobile: 260 },
{ date: '2024-04-05', desktop: 373, mobile: 290 },
{ date: '2024-04-06', desktop: 301, mobile: 340 },
{ date: '2024-04-07', desktop: 245, mobile: 180 },
{ date: '2024-04-08', desktop: 409, mobile: 320 },
{ date: '2024-04-09', desktop: 59, mobile: 110 },
{ date: '2024-04-10', desktop: 261, mobile: 190 },
{ date: '2024-04-11', desktop: 327, mobile: 350 },
{ date: '2024-04-12', desktop: 292, mobile: 210 },
{ date: '2024-04-13', desktop: 342, mobile: 380 },
{ date: '2024-04-14', desktop: 137, mobile: 220 },
{ date: '2024-04-15', desktop: 120, mobile: 170 },
{ date: '2024-04-16', desktop: 138, mobile: 190 },
{ date: '2024-04-17', desktop: 446, mobile: 360 },
{ date: '2024-04-18', desktop: 364, mobile: 410 },
{ date: '2024-04-19', desktop: 243, mobile: 180 },
{ date: '2024-04-20', desktop: 89, mobile: 150 },
{ date: '2024-04-21', desktop: 137, mobile: 200 },
{ date: '2024-04-22', desktop: 224, mobile: 170 },
{ date: '2024-04-23', desktop: 138, mobile: 230 },
{ date: '2024-04-24', desktop: 387, mobile: 290 },
{ date: '2024-04-25', desktop: 215, mobile: 250 },
{ date: '2024-04-26', desktop: 75, mobile: 130 },
{ date: '2024-04-27', desktop: 383, mobile: 420 },
{ date: '2024-04-28', desktop: 122, mobile: 180 },
{ date: '2024-04-29', desktop: 315, mobile: 240 },
{ date: '2024-04-30', desktop: 454, mobile: 380 },
{ date: '2024-05-01', desktop: 165, mobile: 220 },
{ date: '2024-05-02', desktop: 293, mobile: 310 },
{ date: '2024-05-03', desktop: 247, mobile: 190 },
{ date: '2024-05-04', desktop: 385, mobile: 420 },
{ date: '2024-05-05', desktop: 481, mobile: 390 },
{ date: '2024-05-06', desktop: 498, mobile: 520 },
{ date: '2024-05-07', desktop: 388, mobile: 300 },
{ date: '2024-05-08', desktop: 149, mobile: 210 },
{ date: '2024-05-09', desktop: 227, mobile: 180 },
{ date: '2024-05-10', desktop: 293, mobile: 330 },
{ date: '2024-05-11', desktop: 335, mobile: 270 },
{ date: '2024-05-12', desktop: 197, mobile: 240 },
{ date: '2024-05-13', desktop: 197, mobile: 160 },
{ date: '2024-05-14', desktop: 448, mobile: 490 },
{ date: '2024-05-15', desktop: 473, mobile: 380 },
{ date: '2024-05-16', desktop: 338, mobile: 400 },
{ date: '2024-05-17', desktop: 499, mobile: 420 },
{ date: '2024-05-18', desktop: 315, mobile: 350 },
{ date: '2024-05-19', desktop: 235, mobile: 180 },
{ date: '2024-05-20', desktop: 177, mobile: 230 },
{ date: '2024-05-21', desktop: 82, mobile: 140 },
{ date: '2024-05-22', desktop: 81, mobile: 120 },
{ date: '2024-05-23', desktop: 252, mobile: 290 },
{ date: '2024-05-24', desktop: 294, mobile: 220 },
{ date: '2024-05-25', desktop: 201, mobile: 250 },
{ date: '2024-05-26', desktop: 213, mobile: 170 },
{ date: '2024-05-27', desktop: 420, mobile: 460 },
{ date: '2024-05-28', desktop: 233, mobile: 190 },
{ date: '2024-05-29', desktop: 78, mobile: 130 },
{ date: '2024-05-30', desktop: 340, mobile: 280 },
{ date: '2024-05-31', desktop: 178, mobile: 230 },
{ date: '2024-06-01', desktop: 178, mobile: 200 },
{ date: '2024-06-02', desktop: 470, mobile: 410 },
{ date: '2024-06-03', desktop: 103, mobile: 160 },
{ date: '2024-06-04', desktop: 439, mobile: 380 },
{ date: '2024-06-05', desktop: 88, mobile: 140 },
{ date: '2024-06-06', desktop: 294, mobile: 250 },
{ date: '2024-06-07', desktop: 323, mobile: 370 },
{ date: '2024-06-08', desktop: 385, mobile: 320 },
{ date: '2024-06-09', desktop: 438, mobile: 480 },
{ date: '2024-06-10', desktop: 155, mobile: 200 },
{ date: '2024-06-11', desktop: 92, mobile: 150 },
{ date: '2024-06-12', desktop: 492, mobile: 420 },
{ date: '2024-06-13', desktop: 81, mobile: 130 },
{ date: '2024-06-14', desktop: 426, mobile: 380 },
{ date: '2024-06-15', desktop: 307, mobile: 350 },
{ date: '2024-06-16', desktop: 371, mobile: 310 },
{ date: '2024-06-17', desktop: 475, mobile: 520 },
{ date: '2024-06-18', desktop: 107, mobile: 170 },
{ date: '2024-06-19', desktop: 341, mobile: 290 },
{ date: '2024-06-20', desktop: 408, mobile: 450 },
{ date: '2024-06-21', desktop: 169, mobile: 210 },
{ date: '2024-06-22', desktop: 317, mobile: 270 },
{ date: '2024-06-23', desktop: 480, mobile: 530 },
{ date: '2024-06-24', desktop: 132, mobile: 180 },
{ date: '2024-06-25', desktop: 141, mobile: 190 },
{ date: '2024-06-26', desktop: 434, mobile: 380 },
{ date: '2024-06-27', desktop: 448, mobile: 490 },
{ date: '2024-06-28', desktop: 149, mobile: 200 },
{ date: '2024-06-29', desktop: 103, mobile: 160 },
{ date: '2024-06-30', desktop: 446, mobile: 400 },
]
const chartConfig = {
views: {
label: 'Page Views',
},
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
const [activeChart, setActiveChart] = React.useState<keyof typeof chartConfig>('desktop')
const total = React.useMemo(
() => ({
desktop: chartData.reduce((acc, curr) => acc + curr.desktop, 0),
mobile: chartData.reduce((acc, curr) => acc + curr.mobile, 0),
}),
[]
)
return (
<Card>
<CardHeader className="flex flex-col items-stretch space-y-0 border-b p-0 sm:flex-row">
<div className="flex flex-1 flex-col justify-center gap-1 px-6 py-5 sm:py-6">
<CardTitle>Line Chart - Interactive</CardTitle>
<CardDescription>Showing total visitors for the last 3 months</CardDescription>
</div>
<div className="flex">
{['desktop', 'mobile'].map((key) => {
const chart = key as keyof typeof chartConfig
return (
<button
key={chart}
data-active={activeChart === chart}
className="flex flex-1 flex-col justify-center gap-1 border-t px-6 py-4 text-left even:border-l data-[active=true]:bg-muted/50 sm:border-l sm:border-t-0 sm:px-8 sm:py-6"
onClick={() => setActiveChart(chart)}
>
<span className="text-xs text-muted-foreground">{chartConfig[chart].label}</span>
<span className="text-lg font-bold leading-none sm:text-3xl">
{total[key as keyof typeof total].toLocaleString()}
</span>
</button>
)
})}
</div>
</CardHeader>
<CardContent className="px-2 sm:p-6">
<ChartContainer config={chartConfig} className="aspect-auto h-[250px] w-full">
<LineChart
accessibilityLayer
data={chartData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
})
}}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey="views"
labelFormatter={(value) => {
return new Date(value).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})
}}
/>
}
/>
<Line
dataKey={activeChart}
type="monotone"
stroke={`var(--color-${activeChart})`}
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
</CardContent>
</Card>
)
}
@@ -1,103 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, LabelList, Line, LineChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with a custom label'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
color: 'hsl(var(--chart-2))',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Custom Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
margin={{
top: 24,
left: 24,
right: 24,
}}
>
<CartesianGrid vertical={false} />
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="line" nameKey="visitors" hideLabel />}
/>
<Line
dataKey="visitors"
type="natural"
stroke="var(--color-visitors)"
strokeWidth={2}
dot={{
fill: 'var(--color-visitors)',
}}
activeDot={{
r: 6,
}}
>
<LabelList
position="top"
offset={12}
className="fill-foreground"
fontSize={12}
dataKey="browser"
formatter={(value: keyof typeof chartConfig) => chartConfig[value]?.label}
/>
</Line>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,85 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, LabelList, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with a label'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
margin={{
top: 20,
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="line" />} />
<Line
dataKey="desktop"
type="natural"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={{
fill: 'var(--color-desktop)',
}}
activeDot={{
r: 6,
}}
>
<LabelList position="top" offset={12} className="fill-foreground" fontSize={12} />
</Line>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A linear line chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Linear</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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="linear"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,88 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A multiple line chart'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Multiple</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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 />} />
<Line
dataKey="desktop"
type="monotone"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={false}
/>
<Line
dataKey="mobile"
type="monotone"
stroke="var(--color-mobile)"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A line chart with step'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Line Chart - Step</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<LineChart
accessibilityLayer
data={chartData}
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="step"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col items-start gap-2 text-sm">
<div className="flex gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,81 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Label, Pie, PieChart, Sector } from 'recharts'
import { PieSectorDataItem } from 'recharts/types/polar/Pie'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A donut chart with an active sector'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Donut Active</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie
data={chartData}
dataKey="visitors"
nameKey="browser"
innerRadius={60}
strokeWidth={5}
activeIndex={0}
activeShape={({ outerRadius = 0, ...props }: PieSectorDataItem) => (
<Sector {...props} outerRadius={outerRadius + 10} />
)}
/>
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,111 +0,0 @@
'use client'
import * as React from 'react'
import { TrendingUp } from 'lucide-react'
import { Label, Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A donut chart with text'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 287, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 190, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
const totalVisitors = React.useMemo(() => {
return chartData.reduce((acc, curr) => acc + curr.visitors, 0)
}, [])
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Donut with Text</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie
data={chartData}
dataKey="visitors"
nameKey="browser"
innerRadius={60}
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 text-3xl font-bold"
>
{totalVisitors.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 24}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
)
}
}}
/>
</Pie>
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,70 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A donut chart'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Donut</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie data={chartData} dataKey="visitors" nameKey="browser" innerRadius={60} />
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,170 +0,0 @@
'use client'
import * as React from 'react'
import { Label, Pie, PieChart, Sector } from 'recharts'
import { PieSectorDataItem } from 'recharts/types/polar/Pie'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartStyle, ChartTooltip, ChartTooltipContent } from 'ui'
import {
Select_Shadcn_,
SelectContent_Shadcn_,
SelectItem_Shadcn_,
SelectTrigger_Shadcn_,
SelectValue_Shadcn_,
} from 'ui'
export const description = 'An interactive pie chart'
const desktopData = [
{ month: 'january', desktop: 186, fill: 'var(--color-january)' },
{ month: 'february', desktop: 305, fill: 'var(--color-february)' },
{ month: 'march', desktop: 237, fill: 'var(--color-march)' },
{ month: 'april', desktop: 173, fill: 'var(--color-april)' },
{ month: 'may', desktop: 209, fill: 'var(--color-may)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
desktop: {
label: 'Desktop',
},
mobile: {
label: 'Mobile',
},
january: {
label: 'January',
color: 'hsl(var(--chart-1))',
},
february: {
label: 'February',
color: 'hsl(var(--chart-2))',
},
march: {
label: 'March',
color: 'hsl(var(--chart-3))',
},
april: {
label: 'April',
color: 'hsl(var(--chart-4))',
},
may: {
label: 'May',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
const id = 'pie-interactive'
const [activeMonth, setActiveMonth] = React.useState(desktopData[0].month)
const activeIndex = React.useMemo(
() => desktopData.findIndex((item) => item.month === activeMonth),
[activeMonth]
)
const months = React.useMemo(() => desktopData.map((item) => item.month), [])
return (
<Card data-chart={id} className="flex flex-col">
<ChartStyle id={id} config={chartConfig} />
<CardHeader className="flex-row items-start space-y-0 pb-0">
<div className="grid gap-1">
<CardTitle>Pie Chart - Interactive</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</div>
<Select_Shadcn_ value={activeMonth} onValueChange={setActiveMonth}>
<SelectTrigger_Shadcn_
className="ml-auto h-7 w-[130px] rounded-lg pl-2.5"
aria-label="Select a value"
>
<SelectValue_Shadcn_ placeholder="Select month" />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_ align="end" className="rounded-xl">
{months.map((key) => {
const config = chartConfig[key as keyof typeof chartConfig]
if (!config) {
return null
}
return (
<SelectItem_Shadcn_ key={key} value={key} className="rounded-lg [&_span]:flex">
<div className="flex items-center gap-2 text-xs">
<span
className="flex h-3 w-3 shrink-0 rounded-sm"
style={{
backgroundColor: `var(--color-${key})`,
}}
/>
{config?.label}
</div>
</SelectItem_Shadcn_>
)
})}
</SelectContent_Shadcn_>
</Select_Shadcn_>
</CardHeader>
<CardContent className="flex flex-1 justify-center pb-0">
<ChartContainer
id={id}
config={chartConfig}
className="mx-auto aspect-square w-full max-w-[300px]"
>
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie
data={desktopData}
dataKey="desktop"
nameKey="month"
innerRadius={60}
strokeWidth={5}
activeIndex={activeIndex}
activeShape={({ outerRadius = 0, ...props }: PieSectorDataItem) => (
<g>
<Sector {...props} outerRadius={outerRadius + 10} />
<Sector
{...props}
outerRadius={outerRadius + 25}
innerRadius={outerRadius + 12}
/>
</g>
)}
>
<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 text-3xl font-bold"
>
{desktopData[activeIndex].desktop.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 24}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
)
}
}}
/>
</Pie>
</PieChart>
</ChartContainer>
</CardContent>
</Card>
)
}
@@ -1,92 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A pie chart with a custom label'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Custom Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip content={<ChartTooltipContent nameKey="visitors" hideLabel />} />
<Pie
data={chartData}
dataKey="visitors"
labelLine={false}
label={({ payload, ...props }) => {
return (
<text
cx={props.cx}
cy={props.cy}
x={props.x}
y={props.y}
textAnchor={props.textAnchor}
dominantBaseline={props.dominantBaseline}
fill="hsla(var(--foreground))"
>
{`${
chartConfig[payload.browser as keyof typeof chartConfig]?.label
} (${payload.visitors})`}
</text>
)
}}
nameKey="browser"
/>
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,78 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { LabelList, Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A pie chart with a label list'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Label List</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip content={<ChartTooltipContent nameKey="visitors" hideLabel />} />
<Pie data={chartData} dataKey="visitors">
<LabelList
dataKey="browser"
className="fill-background"
stroke="none"
fontSize={12}
formatter={(value: keyof typeof chartConfig) => chartConfig[value]?.label}
/>
</Pie>
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A pie chart with a label'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer
config={chartConfig}
className="mx-auto aspect-square max-h-[250px] pb-0 [&_.recharts-pie-label-text]:fill-foreground"
>
<PieChart>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<Pie data={chartData} dataKey="visitors" label nameKey="browser" />
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,64 +0,0 @@
'use client'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartLegend, ChartLegendContent } from 'ui'
export const description = 'A pie chart with a legend'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Legend</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[300px]">
<PieChart>
<Pie data={chartData} dataKey="visitors" />
<ChartLegend
content={<ChartLegendContent nameKey="browser" />}
className="-translate-y-2 flex-wrap gap-2 [&>*]:basis-1/4 [&>*]:justify-center"
/>
</PieChart>
</ChartContainer>
</CardContent>
</Card>
)
}
@@ -1,70 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A pie chart with no separator'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Separator None</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie data={chartData} dataKey="visitors" nameKey="browser" stroke="0" />
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,70 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A simple pie chart'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<Pie data={chartData} dataKey="visitors" nameKey="browser" />
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,97 +0,0 @@
'use client'
import * as React from 'react'
import { TrendingUp } from 'lucide-react'
import { Label, Pie, PieChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A pie chart with stacked sections'
const desktopData = [
{ month: 'january', desktop: 186, fill: 'var(--color-january)' },
{ month: 'february', desktop: 305, fill: 'var(--color-february)' },
{ month: 'march', desktop: 237, fill: 'var(--color-march)' },
{ month: 'april', desktop: 173, fill: 'var(--color-april)' },
{ month: 'may', desktop: 209, fill: 'var(--color-may)' },
]
const mobileData = [
{ month: 'january', mobile: 80, fill: 'var(--color-january)' },
{ month: 'february', mobile: 200, fill: 'var(--color-february)' },
{ month: 'march', mobile: 120, fill: 'var(--color-march)' },
{ month: 'april', mobile: 190, fill: 'var(--color-april)' },
{ month: 'may', mobile: 130, fill: 'var(--color-may)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
desktop: {
label: 'Desktop',
},
mobile: {
label: 'Mobile',
},
january: {
label: 'January',
color: 'hsl(var(--chart-1))',
},
february: {
label: 'February',
color: 'hsl(var(--chart-2))',
},
march: {
label: 'March',
color: 'hsl(var(--chart-3))',
},
april: {
label: 'April',
color: 'hsl(var(--chart-4))',
},
may: {
label: 'May',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Pie Chart - Stacked</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<PieChart>
<ChartTooltip
content={
<ChartTooltipContent
labelKey="visitors"
nameKey="month"
indicator="line"
labelFormatter={(_, payload) => {
return chartConfig[payload?.[0].dataKey as keyof typeof chartConfig].label
}}
/>
}
/>
<Pie data={desktopData} dataKey="desktop" outerRadius={60} />
<Pie data={mobileData} dataKey="mobile" innerRadius={70} outerRadius={90} />
</PieChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,54 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 273 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,62 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with dots'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 273 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center">
<CardTitle>Radar Chart - Dots</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid />
<Radar
dataKey="desktop"
fill="var(--color-desktop)"
fillOpacity={0.6}
dot={{
r: 4,
fillOpacity: 1,
}}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,54 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a grid and circle fill'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 285 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 203 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 264 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid Circle Filled</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
<PolarGrid className="fill-[--color-desktop] opacity-20" gridType="circle" />
<PolarAngleAxis dataKey="month" />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.5} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,62 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a grid and circle fill'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 203 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid Circle - No lines</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarGrid gridType="circle" radialLines={false} />
<PolarAngleAxis dataKey="month" />
<Radar
dataKey="desktop"
fill="var(--color-desktop)"
fillOpacity={0.6}
dot={{
r: 4,
fillOpacity: 1,
}}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,62 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a grid and circle'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 273 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid Circle</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarGrid gridType="circle" />
<PolarAngleAxis dataKey="month" />
<Radar
dataKey="desktop"
fill="var(--color-desktop)"
fillOpacity={0.6}
dot={{
r: 4,
fillOpacity: 1,
}}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,54 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a custom grid'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 273 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid Custom</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarGrid radialLines={false} polarRadius={[90]} strokeWidth={1} />
<PolarAngleAxis dataKey="month" />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,54 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a grid filled'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 285 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 203 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 264 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid Filled</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarGrid className="fill-[--color-desktop] opacity-20" />
<PolarAngleAxis dataKey="month" />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.5} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,61 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with no grid'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 273 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Grid None</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarAngleAxis dataKey="month" />
<Radar
dataKey="desktop"
fill="var(--color-desktop)"
fillOpacity={0.6}
dot={{
r: 4,
fillOpacity: 1,
}}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,75 +0,0 @@
'use client'
import { ArrowDownFromLine, ArrowUpFromLine, TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'A radar chart with icons'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
icon: ArrowDownFromLine,
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
icon: ArrowUpFromLine,
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Icons</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart
data={chartData}
margin={{
top: -40,
bottom: -10,
}}
>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
<Radar dataKey="mobile" fill="var(--color-mobile)" />
<ChartLegend className="mt-8" content={<ChartLegendContent />} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 pt-4 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,91 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a custom label'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Custom Label</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart
data={chartData}
margin={{
top: 10,
right: 10,
bottom: 10,
left: 10,
}}
>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<PolarAngleAxis
dataKey="month"
tick={({ x, y, textAnchor, value, index, ...props }) => {
const data = chartData[index]
return (
<text
x={x}
y={index === 0 ? y - 10 : y}
textAnchor={textAnchor}
fontSize={13}
fontWeight={500}
{...props}
>
<tspan>{data.desktop}</tspan>
<tspan className="fill-muted-foreground">/</tspan>
<tspan>{data.mobile}</tspan>
<tspan x={x} dy={'1rem'} fontSize={12} className="fill-muted-foreground">
{data.month}
</tspan>
</text>
)
}}
/>
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
<Radar dataKey="mobile" fill="var(--color-mobile)" />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'A radar chart with a legend'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Legend</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart
data={chartData}
margin={{
top: -40,
bottom: -10,
}}
>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
<Radar dataKey="mobile" fill="var(--color-mobile)" />
<ChartLegend className="mt-8" content={<ChartLegendContent />} />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 pt-4 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,71 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with lines only'
const chartData = [
{ month: 'January', desktop: 186, mobile: 160 },
{ month: 'February', desktop: 185, mobile: 170 },
{ month: 'March', desktop: 207, mobile: 180 },
{ month: 'April', desktop: 173, mobile: 160 },
{ month: 'May', desktop: 160, mobile: 190 },
{ month: 'June', desktop: 174, mobile: 204 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Lines Only</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid radialLines={false} />
<Radar
dataKey="desktop"
fill="var(--color-desktop)"
fillOpacity={0}
stroke="var(--color-desktop)"
strokeWidth={2}
/>
<Radar
dataKey="mobile"
fill="var(--color-mobile)"
fillOpacity={0}
stroke="var(--color-mobile)"
strokeWidth={2}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,59 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with multiple data'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Multiple</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} />
<PolarAngleAxis dataKey="month" />
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
<Radar dataKey="mobile" fill="var(--color-mobile)" />
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,67 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radar chart with a radius axis'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader className="items-center pb-4">
<CardTitle>Radar Chart - Radius Axis</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadarChart data={chartData}>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="line" labelKey="month" />}
/>
<PolarGrid />
<Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} />
<Radar dataKey="mobile" fill="var(--color-mobile)" />
<PolarRadiusAxis
angle={60}
stroke="hsla(var(--foreground))"
orientation="middle"
axisLine={false}
/>
</RadarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</CardFooter>
</Card>
)
}
@@ -1,74 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { PolarGrid, RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radial chart with a grid'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart - Grid</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadialBarChart data={chartData} innerRadius={30} outerRadius={100}>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel nameKey="browser" />}
/>
<PolarGrid gridType="circle" />
<RadialBar dataKey="visitors" />
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,86 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { LabelList, RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radial chart with a label'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart - Label</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadialBarChart
data={chartData}
startAngle={-90}
endAngle={380}
innerRadius={30}
outerRadius={110}
>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel nameKey="browser" />}
/>
<RadialBar dataKey="visitors" background>
<LabelList
position="insideStart"
dataKey="browser"
className="fill-white capitalize mix-blend-luminosity"
fontSize={11}
/>
</RadialBar>
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,85 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Label, PolarGrid, PolarRadiusAxis, RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer } from 'ui'
export const description = 'A radial chart with a custom shape'
const chartData = [{ browser: 'safari', visitors: 1260, fill: 'var(--color-safari)' }]
const chartConfig = {
visitors: {
label: 'Visitors',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart - Shape</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadialBarChart data={chartData} endAngle={100} innerRadius={80} outerRadius={140}>
<PolarGrid
gridType="circle"
radialLines={false}
stroke="none"
className="first:fill-muted last:fill-background"
polarRadius={[86, 74]}
/>
<RadialBar dataKey="visitors" background />
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
<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 text-4xl font-bold"
>
{chartData[0].visitors.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 24}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
)
}
}}
/>
</PolarRadiusAxis>
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,73 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radial chart'
const chartData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
{ browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
{ browser: 'other', visitors: 90, fill: 'var(--color-other)' },
]
const chartConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
firefox: {
label: 'Firefox',
color: 'hsl(var(--chart-3))',
},
edge: {
label: 'Edge',
color: 'hsl(var(--chart-4))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadialBarChart data={chartData} innerRadius={30} outerRadius={110}>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel nameKey="browser" />}
/>
<RadialBar dataKey="visitors" background />
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,90 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Label, PolarRadiusAxis, RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A radial chart with stacked sections'
const chartData = [{ month: 'january', desktop: 1260, mobile: 570 }]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
const totalVisitors = chartData[0].desktop + chartData[0].mobile
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart - Stacked</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex flex-1 items-center pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square w-full max-w-[250px]">
<RadialBarChart data={chartData} endAngle={180} innerRadius={80} outerRadius={130}>
<ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
<Label
content={({ viewBox }) => {
if (viewBox && 'cx' in viewBox && 'cy' in viewBox) {
return (
<text x={viewBox.cx} y={viewBox.cy} textAnchor="middle">
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) - 16}
className="fill-foreground text-2xl font-bold"
>
{totalVisitors.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 4}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
)
}
}}
/>
</PolarRadiusAxis>
<RadialBar
dataKey="desktop"
stackId="a"
cornerRadius={5}
fill="var(--color-desktop)"
className="stroke-transparent stroke-2"
/>
<RadialBar
dataKey="mobile"
fill="var(--color-mobile)"
stackId="a"
cornerRadius={5}
className="stroke-transparent stroke-2"
/>
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
@@ -1,91 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Label, PolarGrid, PolarRadiusAxis, RadialBar, RadialBarChart } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer } from 'ui'
export const description = 'A radial chart with text'
const chartData = [{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' }]
const chartConfig = {
visitors: {
label: 'Visitors',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Radial Chart - Text</CardTitle>
<CardDescription>January - June 2024</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
<RadialBarChart
data={chartData}
startAngle={0}
endAngle={250}
innerRadius={80}
outerRadius={110}
>
<PolarGrid
gridType="circle"
radialLines={false}
stroke="none"
className="first:fill-muted last:fill-background"
polarRadius={[86, 74]}
/>
<RadialBar dataKey="visitors" background cornerRadius={10} />
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
<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 text-4xl font-bold"
>
{chartData[0].visitors.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 24}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
)
}
}}
/>
</PolarRadiusAxis>
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="leading-none text-muted-foreground">
Showing total visitors for the last 6 months
</div>
</CardFooter>
</Card>
)
}
File diff suppressed because it is too large. Load diff
@@ -1,6 +1,4 @@
import fs from 'fs'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from 'ui'
// import { parse } from 'react-docgen'
export function ComponentProps(props: any) {
// map through all props types for this component DropdownMenu
@@ -11,10 +9,6 @@ export function ComponentProps(props: any) {
// export default ({ name }: { name: string }) => <div>{{name}}</div>;
// `
// const documentation = parse(code)
//
// console.log(documentation)
// console.log('from the component props', JSON.parse(props.docs))
const docs = JSON.parse(props.docs)
@@ -1,5 +1,5 @@
import { docsConfig } from '@/config/docs'
import NavigationItem from '@/components/side-navigation-item'
import { docsConfig } from '@/config/docs'
function SideNavigation() {
return (
@@ -9,7 +9,16 @@ function SideNavigation() {
<div className="font-mono uppercase text-xs text-foreground-lighter/75 mb-2 px-6 tracking-widest">
{section.title}
</div>
{section.items.map((item, i) => (
{(section.sortOrder === 'alphabetical'
? (() => {
const priorityItems = section.items.filter((item) => item.priority)
const regularItems = section.items
.filter((item) => !item.priority)
.sort((a, b) => a.title.localeCompare(b.title))
return [...priorityItems, ...regularItems]
})()
: section.items
).map((item, i) => (
<NavigationItem item={item} key={`${item.href}-${i}`} />
))}
</div>
@@ -240,12 +240,70 @@ const SourcePanel = forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement> &
}
}
const RechartsPanel = () => {
if (doc.source?.recharts) {
return (
<div
className={cn(
'bg-surface-75/50 border flex items-center p-3 px-5 gap-6 first:rounded-t-md last:rounded-b-md',
props.className
)}
{...props}
>
<svg
width="146"
height="24"
viewBox="0 0 146 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M124.123 1.21484L109.695 23.9951L108.737 23.3887L107.779 22.7812L122.207 0L124.123 1.21484ZM15.4844 5.4082L2.96387 11.998L15.4844 18.5879L14.4277 20.5957L0 13.002L0.52832 11.998L0 10.9941L14.4277 3.40039L15.4844 5.4082ZM145.335 10.9941L144.807 11.998L145.335 13.002L130.907 20.5957L129.851 18.5879L142.37 11.998L129.851 5.4082L130.907 3.40039L145.335 10.9941ZM68.5801 8.39746C68.8994 8.39746 69.2665 8.43699 69.6807 8.51465C70.0991 8.58798 70.5024 8.74074 70.8906 8.97363C71.2832 9.20658 71.6093 9.55816 71.8682 10.0283C72.127 10.4985 72.2568 11.1286 72.2568 11.918V18.4678H70.7285V17.1221H70.6514C70.6409 17.1439 70.6271 17.1644 70.6152 17.1865C70.598 17.2186 70.5818 17.2524 70.5615 17.2852L70.4443 17.457C70.3581 17.5724 70.2545 17.6916 70.1338 17.8145C70.1245 17.8239 70.1141 17.8324 70.1045 17.8418C70.0734 17.8722 70.0414 17.9023 70.0078 17.9316C69.7839 18.1272 69.5044 18.2981 69.1689 18.4424C68.7678 18.6148 68.2781 18.7012 67.7002 18.7012C67.0703 18.7012 66.4988 18.582 65.9854 18.3447C65.6861 18.2039 65.4237 18.0261 65.1963 17.8135C65.0335 17.6615 64.8876 17.4915 64.7617 17.3027C64.5935 17.0479 64.4739 16.763 64.3994 16.4492C64.3724 16.3357 64.3497 16.2188 64.335 16.0977C64.3344 16.0928 64.3346 16.0879 64.334 16.083C64.3175 15.9423 64.3086 15.7965 64.3086 15.6455C64.3087 15.0766 64.4215 14.6153 64.6455 14.2617C64.7017 14.172 64.7624 14.0869 64.8281 14.0068C64.8444 13.987 64.862 13.9684 64.8789 13.9492C65.0657 13.7362 65.287 13.5583 65.5449 13.4189C65.736 13.3157 65.938 13.2267 66.1494 13.1504C66.3529 13.0768 66.5659 13.0155 66.7881 12.9668C66.9022 12.941 67.0165 12.9167 67.1309 12.8936C67.2457 12.8703 67.3605 12.8477 67.4756 12.8271C67.5904 12.8067 67.7053 12.7873 67.8203 12.7695C67.9354 12.7517 68.0507 12.7358 68.166 12.7207C68.77 12.6431 69.2604 12.5847 69.6357 12.5459C70.0151 12.5027 70.2914 12.4312 70.4639 12.332C70.53 12.2949 70.5836 12.2471 70.625 12.1895C70.6389 12.1701 70.651 12.1496 70.6621 12.1279C70.7063 12.0417 70.7285 11.9374 70.7285 11.8145V11.7627C70.7285 11.4437 70.6849 11.1601 70.5977 10.9121C70.554 10.7881 70.5001 10.6726 70.4346 10.5664C70.3692 10.4603 70.2923 10.3628 70.2051 10.2744C70.0325 10.0977 69.8149 9.9654 69.5527 9.87695C69.4871 9.85481 69.4189 9.83496 69.3477 9.81836C69.1342 9.76858 68.8955 9.74415 68.6318 9.74414C67.9029 9.7442 67.3311 9.90344 66.917 10.2227C66.7617 10.3424 66.6236 10.4651 66.5029 10.5908C66.3458 10.7544 66.2187 10.9237 66.1201 11.0977C66.1177 11.102 66.1147 11.106 66.1123 11.1104L66.0439 11.2451L64.5928 10.7275C64.6561 10.5797 64.7251 10.4395 64.7988 10.3076C64.8087 10.29 64.82 10.2732 64.8301 10.2559C64.8959 10.1423 64.9653 10.0349 65.0391 9.93359C65.0466 9.9232 65.0539 9.91261 65.0615 9.90234C65.0956 9.85658 65.1312 9.81272 65.167 9.76953C65.1741 9.76094 65.1803 9.75165 65.1875 9.74316C65.2256 9.69808 65.2647 9.65451 65.3047 9.6123C65.312 9.6046 65.3188 9.59647 65.3262 9.58887C65.3732 9.54019 65.4221 9.49397 65.4717 9.44922L65.5156 9.41211C65.5531 9.37961 65.59 9.34673 65.6289 9.31641C66.0646 8.97561 66.5394 8.73826 67.0527 8.60449C67.5703 8.46646 68.0797 8.3975 68.5801 8.39746ZM37.4268 8.40137C37.491 8.40408 37.5551 8.40769 37.6191 8.41309C38.0052 8.44542 38.3878 8.52676 38.7666 8.65625C38.8269 8.67688 38.8863 8.69992 38.9453 8.72363C39.0099 8.74954 39.0737 8.77707 39.1367 8.80664C39.4982 8.97651 39.835 9.20692 40.1455 9.49805C40.5595 9.88199 40.8889 10.3914 41.1348 11.0254C41.3807 11.6596 41.5039 12.4405 41.5039 13.3682V14.0156H34.2861C34.2975 14.3591 34.3374 14.677 34.4062 14.9697C34.4355 15.0944 34.4691 15.2146 34.5088 15.3301C34.5156 15.3499 34.5241 15.3691 34.5312 15.3887C34.5726 15.5024 34.6181 15.6123 34.6699 15.7168C34.7686 15.9108 34.8817 16.0874 35.0088 16.2471C35.2209 16.5132 35.4723 16.7314 35.7637 16.9014C35.7835 16.9128 35.8041 16.9227 35.8242 16.9336C35.9066 16.9783 35.9911 17.0191 36.0781 17.0557C36.4686 17.2196 36.9047 17.3027 37.3877 17.3027C37.7888 17.3027 38.1511 17.2468 38.4746 17.1348C38.7205 17.0474 38.9408 16.9278 39.1357 16.7773C39.2006 16.7273 39.263 16.6742 39.3223 16.6172C39.5596 16.3842 39.7426 16.0942 39.8721 15.749L41.3486 16.1641C41.2641 16.4361 41.147 16.6903 41 16.9268C40.8797 17.1202 40.7393 17.3022 40.5771 17.4717C40.5732 17.4758 40.5694 17.4802 40.5654 17.4844C40.4739 17.578 40.3767 17.6666 40.2744 17.75C40.1718 17.8337 40.0636 17.9119 39.9502 17.9854C39.7239 18.1318 39.4764 18.2586 39.207 18.3643C39.1943 18.3692 39.1808 18.3731 39.168 18.3779C39.0606 18.418 38.9505 18.4534 38.8379 18.4854C38.7505 18.5102 38.6618 18.5338 38.5713 18.5537C38.2032 18.6345 37.809 18.6757 37.3887 18.6758C36.9098 18.6758 36.4631 18.6224 36.0498 18.5166C35.6367 18.4109 35.2556 18.2524 34.9082 18.041C34.2182 17.6139 33.6858 17.0182 33.3105 16.2549C33.0626 15.7416 32.8996 15.1719 32.8174 14.5469C32.7764 14.2366 32.7539 13.9129 32.7539 13.5752C32.7539 13.0662 32.8006 12.5872 32.8936 12.1387C32.9168 12.0264 32.9427 11.9161 32.9717 11.8076C33.005 11.6833 33.043 11.5618 33.084 11.4424C33.15 11.2496 33.2246 11.0627 33.3105 10.8828C33.53Line truncated
fill="currentColor"
/>
</svg>
<div className="flex flex-row items-center justify-between text-sm w-full">
<span className="text-foreground-light text-xs">This component uses Recharts</span>
{doc.links ? (
<div className="flex items-center gap-2 justify-end">
{doc.links?.doc && (
<Button
type="outline"
className="rounded-full"
icon={<ExternalLink className="text-foreground-muted" strokeWidth={1} />}
>
<Link href={doc.links.doc} target="_blank" rel="noreferrer">
Docs
</Link>
</Button>
)}
{doc.links?.api && (
<Button
type="outline"
className="rounded-full"
icon={<ExternalLink className="text-foreground-muted" strokeWidth={1} />}
>
<Link href={doc.links.api} target="_blank" rel="noreferrer">
API Reference
</Link>
</Button>
)}
</div>
) : null}
</div>
</div>
)
}
}
return (
<div className="flex flex-col -space-y-px">
<RadixPanel />
<VaulPanel />
<InputOtp />
<ReactAccesibleTreeViewPanel />
<RechartsPanel />
{/* <ShadcnPanel /> */}
</div>
)
+32 -15
View File
@@ -9,6 +9,7 @@ export const docsConfig: DocsConfig = {
sidebarNav: [
{
title: 'Getting Started',
sortOrder: 'manual',
items: [
{
title: 'Introduction',
@@ -49,15 +50,17 @@ export const docsConfig: DocsConfig = {
},
{
title: 'UI Patterns',
sortOrder: 'alphabetical',
items: [
{
title: 'Navigation',
href: '/docs/ui-patterns/navigation',
title: 'Introduction',
href: '/docs/ui-patterns/ui-patterns',
items: [],
priority: true,
},
{
title: 'Layout',
href: '/docs/ui-patterns/layout',
title: 'Charts',
href: '/docs/ui-patterns/charts',
items: [],
},
{
@@ -70,15 +73,32 @@ export const docsConfig: DocsConfig = {
href: '/docs/ui-patterns/forms',
items: [],
},
{
title: 'Layout',
href: '/docs/ui-patterns/layout',
items: [],
},
{
title: 'Navigation',
href: '/docs/ui-patterns/navigation',
items: [],
},
{
title: 'Tables',
href: '/docs/ui-patterns/tables',
items: [],
},
],
},
{
title: 'Fragment Components',
sortOrder: 'alphabetical',
items: [
{
title: 'Introduction',
href: '/docs/components/fragment-components',
href: '/docs/fragments/fragment-components',
items: [],
priority: true,
},
{
title: 'Admonition',
@@ -169,11 +189,13 @@ export const docsConfig: DocsConfig = {
},
{
title: 'Atom Components',
sortOrder: 'alphabetical',
items: [
{
title: 'Introduction',
href: '/docs/components/atom-components',
items: [],
priority: true,
},
{
title: 'Accordion',
@@ -231,11 +253,6 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/carousel',
items: [],
},
{
title: 'Chart',
href: '/docs/components/chart',
items: [],
},
{
title: 'Checkbox',
href: '/docs/components/checkbox',
@@ -266,11 +283,6 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/context-menu',
items: [],
},
{
title: 'Data Table',
href: '/docs/components/data-table',
items: [],
},
{
title: 'Date Picker',
href: '/docs/components/date-picker',
@@ -291,6 +303,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/dropdown-menu',
items: [],
},
{
title: 'Field',
href: '/docs/components/field',
items: [],
},
{
title: 'Form',
href: '/docs/components/form',
@@ -27,29 +27,33 @@ Chromium-based browsers and Firefox handle this automatically via the Tab key. S
Interactive page elements should also provide visual feedback upon selection via a `focus-visible` state. We use consistent focus styles such as `inset-focus` so users recognize this state instantly.
[Button](../components/button) has all of the above built-in. Bespoke interactive elements however, such as the below clickable [TableRow](../components/table), require these props to be added manually:
[Button](components/button) has all of the above built-in. Bespoke interactive elements however, such as the below interactive [Table Row](components/table#examples), require these props to be added manually:
```tsx showLineNumbers {3, 5-11}
```tsx showLineNumbers {4-14}
<TableRow
key={id}
className="relative cursor-pointer h-16 inset-focus"
onClick={(event) => handleBucketNavigation(name, event)}
onClick={(event) => {
if (event.currentTarget !== event.target) return
handleBucketNavigation(bucket.id, event)
}}
onKeyDown={(event) => {
if (event.currentTarget !== event.target) return
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
handleBucketNavigation(name, event)
handleBucketNavigation(bucket.id, event)
}
}}
tabIndex={0}
>
<TableCell>
<p>{name}</p>
</TableCell>
<TableCell>{name}</TableCell>
</TableRow>
```
Consider also affordances like `ctrl` and `meta` key support for opening in a new tab. Anything that you can do with a mouse input should be replicable by keyboard.
See the examples within [Table](components/table#examples) for more.
### Radio groups
Single-select option groups such as `<input type="radio">` should behave as a single control. Only the first item of radio groups should become focused with the Tab key. The next Tab should move focus from the group to the next focusable control.
@@ -7,47 +7,19 @@ source:
shadcn: true
---
The primitive component that forms [Admonition](../fragments/admonition). Do not use this component unless you are intentionally deviating from our consistent callout pattern.
Alert forms the core primitives for [Admonition](../fragments/admonition). Use the Admonition component unless you must deviate from our consistent patterns. Examples where Alert might make sense include:
<ComponentPreview
name="alert-demo"
description="An alert with an icon, title and description. The title says 'Heads up!' and the description is 'You can add components to your app using the cli.'."
peekCode
wide
/>
- Bespoke icon requirement
- Highly custom internal contents
<ComponentPreview name="alert-demo" peekCode wide />
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add alert
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="alert" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
@@ -63,19 +35,3 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
</AlertDescription>
</Alert>
```
## Examples
### Default
<ComponentPreview
name="alert-demo"
description="An alert with an icon, title and description. The title says 'Heads up!' and the description is 'You can add components to your app using the cli.'."
/>
### Destructive
<ComponentPreview
name="alert-destructive"
description="An alert with a destructive variant. The title says 'Delete this item?' and the description is 'This action cannot be undone.'."
/>
@@ -1,4 +1,10 @@
---
title: Atom components
description:
description: Fundamental building blocks of user interfaces, based on shadcn/ui components.
---
Atom components are the fundamental building blocks of our design system. These are primitive, single-purpose components that serve as the foundation for building more complex interfaces. Unlike fragment components (pre-built composite components) or UI patterns (guidelines for structuring sections), atom components are the smallest reusable units that can be composed together.
These components are based on [shadcn/ui](https://ui.shadcn.com) and live in the `ui` package, making them shareable across all Supabase applications. They provide consistent styling, accessibility, and behavior for common interface elements like buttons, inputs, cards, dialogs, and form controls.
Atom components are imported from the `ui` package and can be used directly or combined to create fragment components and implement UI patterns. They form the base layer of our component architecture, ensuring visual and functional consistency across the entire design system.
@@ -1,842 +0,0 @@
---
title: Data Table
description: Powerful table and datagrids built using TanStack Table.
component: true
links:
doc: https://tanstack.com/table/v8/docs/guide/introduction
---
<ComponentPreview name="data-table-demo" peekCode wide />
## Introduction
Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/guide/introduction#what-is-headless-ui) provides.
So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own.
We'll start with the basic `<Table />` component and build a complex data table from scratch.
<Callout className="mt-4">
**Tip:** If you find yourself using the same table in multiple places in your app, you can always extract it into a reusable component.
</Callout>
## Table of Contents
This guide will show you how to use [TanStack Table](https://tanstack.com/table) and the `<Table />` component to build your own custom data table. We'll cover the following topics:
- [Basic Table](#basic-table)
- [Row Actions](#row-actions)
- [Pagination](#pagination)
- [Sorting](#sorting)
- [Filtering](#filtering)
- [Visibility](#visibility)
- [Row Selection](#row-selection)
- [Reusable Components](#reusable-components)
## Installation
1. Add the `<Table />` component to your project:
```bash
npx shadcn-ui@latest add table
```
2. Add `tanstack/react-table` dependency:
```bash
npm install @tanstack/react-table
```
## Prerequisites
We are going to build a table to show recent payments. Here's what our data looks like:
```tsx showLineNumbers
type Payment = {
id: string
amount: number
status: 'pending' | 'processing' | 'success' | 'failed'
email: string
}
export const payments: Payment[] = [
{
id: '728ed52f',
amount: 100,
status: 'pending',
email: 'm@example.com',
},
{
id: '489e1d42',
amount: 125,
status: 'processing',
email: 'example@gmail.com',
},
// ...
]
```
## Project Structure
Start by creating the following file structure:
```txt
app
└── payments
├── columns.tsx
├── data-table.tsx
└── page.tsx
```
I'm using a Next.js example here but this works for any other React framework.
- `columns.tsx` (client component) will contain our column definitions.
- `data-table.tsx` (client component) will contain our `<DataTable />` component.
- `page.tsx` (server component) is where we'll fetch data and render our table.
## Basic Table
Let's start by building a basic table.
<Steps>
### Column Definitions
First, we'll define our columns.
```tsx showLineNumbers title="app/payments/columns.tsx" {3,14-27}
'use client'
import { ColumnDef } from '@tanstack/react-table'
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Payment = {
id: string
amount: number
status: 'pending' | 'processing' | 'success' | 'failed'
email: string
}
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: 'status',
header: 'Status',
},
{
accessorKey: 'email',
header: 'Email',
},
{
accessorKey: 'amount',
header: 'Amount',
},
]
```
<Callout className="mt-4">
**Note:** Columns are where you define the core of what your table
will look like. They define the data that will be displayed, how it will be
formatted, sorted and filtered.
</Callout>
### `<DataTable />` component
Next, we'll create a `<DataTable />` component to render our table.
```tsx showLineNumbers title="app/payments/data-table.tsx"
'use client'
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
}
export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
})
return (
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(header.column.columnDef.header, header.getContext())}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}
```
<Callout>
**Tip**: If you find yourself using `<DataTable />` in multiple places, this is the component you could make reusable by extracting it to `components/ui/data-table.tsx`.
`<DataTable columns={columns} data={data} />`
</Callout>
### Render the table
Finally, we'll render our table in our page component.
```tsx showLineNumbers title="app/payments/page.tsx" {22}
import { Payment, columns } from './columns'
import { DataTable } from './data-table'
async function getData(): Promise<Payment[]> {
// Fetch data from your API here.
return [
{
id: '728ed52f',
amount: 100,
status: 'pending',
email: 'm@example.com',
},
// ...
]
}
export default async function DemoPage() {
const data = await getData()
return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={data} />
</div>
)
}
```
</Steps>
## Cell Formatting
Let's format the amount cell to display the dollar amount. We'll also align the cell to the right.
<Steps>
### Update columns definition
Update the `header` and `cell` definitions for amount as follows:
```tsx showLineNumbers title="app/payments/columns.tsx" {4-15}
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: 'amount',
header: () => <div className="text-right">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue('amount'))
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount)
return <div className="text-right font-medium">{formatted}</div>
},
},
]
```
You can use the same approach to format other cells and headers.
</Steps>
## Row Actions
Let's add row actions to our table. We'll use a `<Dropdown />` component for this.
<Steps>
### Update columns definition
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component.
```tsx showLineNumbers title="app/payments/columns.tsx" {4,6-14,18-45}
'use client'
import { ColumnDef } from '@tanstack/react-table'
import { MoreHorizontal } from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export const columns: ColumnDef<Payment>[] = [
// ...
{
id: 'actions',
cell: ({ row }) => {
const payment = row.original
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem onClick={() => navigator.clipboard.writeText(payment.id)}>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
},
},
// ...
]
```
You can access the row data using `row.original` in the `cell` function. Use this to handle actions for your row eg. use the `id` to make a DELETE call to your API.
</Steps>
## Pagination
Next, we'll add pagination to our table.
<Steps>
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {5,17}
import {
ColumnDef,
flexRender,
getCoreRowModel,
getPaginationRowModel,
useReactTable,
} from '@tanstack/react-table'
export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
// ...
}
```
This will automatically paginate your rows into pages of 10. See the [pagination docs](https://tanstack.com/table/v8/docs/api/features/pagination) for more information on customizing page size and implementing manual pagination.
### Add pagination controls
We can add pagination controls to our table using the `<Button />` component and the `table.previousPage()`, `table.nextPage()` API methods.
```tsx showLineNumbers title="app/payments/data-table.tsx" {1,15,21-39}
import { Button } from "@/components/ui/button"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
return (
<div>
<div className="rounded-md border">
<Table>
{ // .... }
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
)
}
```
See [Reusable Components](#reusable-components) section for a more advanced pagination component.
</Steps>
## Sorting
Let's make the email column sortable.
<Steps>
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" showLineNumbers {3,6,10,18,25-28}
"use client"
import * as React from "react"
import {
ColumnDef,
SortingState,
flexRender,
getCoreRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})
return (
<div>
<div className="rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
### Make header cell sortable
We can now update the `email` header cell to add sorting controls.
```tsx showLineNumbers title="app/payments/columns.tsx" {4,9-19}
'use client'
import { ColumnDef } from '@tanstack/react-table'
import { ArrowUpDown, MoreHorizontal } from 'lucide-react'
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: 'email',
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Email
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
},
]
```
This will automatically sort the table (asc and desc) when the user toggles on the header cell.
</Steps>
## Filtering
Let's add a search input to filter emails in our table.
<Steps>
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {6,10,17,24-26,35-36,39,45-54}
"use client"
import * as React from "react"
import {
ColumnDef,
ColumnFiltersState,
SortingState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
onColumnFiltersChange: setColumnFilters,
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
columnFilters,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
</div>
<div className="rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
Filtering is now enabled for the `email` column. You can add filters to other columns as well. See the [filtering docs](https://tanstack.com/table/v8/docs/guide/filters) for more information on customizing filters.
</Steps>
## Visibility
Adding column visibility is fairly simple using `@tanstack/react-table` visibility API.
<Steps>
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {8,18-23,33-34,45,49,64-91}
"use client"
import * as React from "react"
import {
ColumnDef,
ColumnFiltersState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnFilters,
columnVisibility,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={table.getColumn("email")?.getFilterValue() as string}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto">
Columns
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter(
(column) => column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
This adds a dropdown menu that you can use to toggle column visibility.
</Steps>
## Row Selection
Next, we're going to add row selection to our table.
<Steps>
### Update column definitions
```tsx showLineNumbers title="app/payments/columns.tsx" {6,9-27}
'use client'
import { ColumnDef } from '@tanstack/react-table'
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
export const columns: ColumnDef<Payment>[] = [
{
id: 'select',
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate')
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
]
```
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {11,23,28}
export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
})
return (
<div>
<div className="rounded-md border">
<Table />
</div>
</div>
)
}
```
This adds a checkbox to each row and a checkbox in the header to select all rows.
### Show selected rows
You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API.
```tsx
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length}{' '}
row(s) selected.
</div>
```
</Steps>
## Reusable Components
Here are some components you can use to build your data tables. This is from the [Tasks](/examples/tasks) demo.
### Column header
Make any column header sortable and hideable.
<ComponentSource src="/app/(app)/examples/tasks/components/data-table-column-header.tsx" />
```tsx {5}
export const columns = [
{
accessorKey: 'email',
header: ({ column }) => <DataTableColumnHeader column={column} title="Email" />,
},
]
```
### Pagination
Add pagination controls to your table including page size and selection count.
<ComponentSource src="/app/(app)/examples/tasks/components/data-table-pagination.tsx" />
```tsx
<DataTablePagination table={table} />
```
### Column toggle
A component to toggle column visibility.
<ComponentSource src="/app/(app)/examples/tasks/components/data-table-view-options.tsx" />
```tsx
<DataTableViewOptions table={table} />
```
@@ -15,12 +15,6 @@ source:
## Installation
So I guess I can write anything i want in here.
## Props
{/* <ComponentProps component={'/Dropdown'} foo="world" /> */}
<Tabs defaultValue="cli">
<TabsList>
@@ -0,0 +1,333 @@
---
title: Field
description: Combine labels, controls, and help text to compose accessible form fields and grouped inputs.
component: true
source:
shadcn: true
---
<ComponentPreview
name="field-demo"
className="[&_.preview]:h-[800px] [&_.preview]:p-6 md:[&_.preview]:h-[850px]"
/>
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add field
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="field" title="components/ui/field.tsx" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx showLineNumbers
import {
Field,
FieldContent,
FieldDescription,
FieldError,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
FieldTitle,
} from '@/components/ui/field'
```
```tsx showLineNumbers
<FieldSet>
<FieldLegend>Profile</FieldLegend>
<FieldDescription>This appears on invoices and emails.</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel htmlFor="name">Full name</FieldLabel>
<Input id="name" autoComplete="off" placeholder="Evil Rabbit" />
<FieldDescription>This appears on invoices and emails.</FieldDescription>
</Field>
<Field>
<FieldLabel htmlFor="username">Username</FieldLabel>
<Input id="username" autoComplete="off" aria-invalid />
<FieldError>Choose another username.</FieldError>
</Field>
<Field orientation="horizontal">
<Switch id="newsletter" />
<FieldLabel htmlFor="newsletter">Subscribe to the newsletter</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
```
## Anatomy
The `Field` family is designed for composing accessible forms. A typical field is structured as follows:
```tsx showLineNumbers
<Field>
<FieldLabel htmlFor="input-id">Label</FieldLabel>
{/* Input, Select, Switch, etc. */}
<FieldDescription>Optional helper text.</FieldDescription>
<FieldError>Validation message.</FieldError>
</Field>
```
- `Field` is the core wrapper for a single field.
- `FieldContent` is a flex column that groups label and description. Not required if you have no description.
- Wrap related fields with `FieldGroup`, and use `FieldSet` with `FieldLegend` for semantic grouping.
## Form
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form) or [Tanstack Form](/docs/forms/tanstack-form).
## Examples
### Input
<ComponentPreview name="field-input" className="!mb-4 [&_.preview]:p-6" />
### Textarea
<ComponentPreview name="field-textarea" className="!mb-4 [&_.preview]:p-6" />
### Select
<ComponentPreview name="field-select" className="!mb-4 [&_.preview]:p-6" />
### Slider
<ComponentPreview name="field-slider" className="!mb-4 [&_.preview]:p-6" />
### Fieldset
<ComponentPreview name="field-fieldset" className="!mb-4 [&_.preview]:p-6" />
### Checkbox
<ComponentPreview name="field-checkbox" className="!mb-4 [&_.preview]:p-6" />
### Radio
<ComponentPreview name="field-radio" className="!mb-4 [&_.preview]:p-6" />
### Switch
<ComponentPreview name="field-switch" className="!mb-4 [&_.preview]:p-6" />
### Choice Card
Wrap `Field` components inside `FieldLabel` to create selectable field groups. This works with `RadioItem`, `Checkbox` and `Switch` components.
<ComponentPreview name="field-choice-card" className="!mb-4 [&_.preview]:p-6" />
### Field Group
Stack `Field` components with `FieldGroup`. Add `FieldSeparator` to divide them.
<ComponentPreview name="field-group" className="!mb-4 [&_.preview]:p-6" />
## Responsive Layout
- **Vertical fields:** Default orientation stacks label, control, and helper text—ideal for mobile-first layouts.
- **Horizontal fields:** Set `orientation="horizontal"` on `Field` to align the label and control side-by-side. Pair with `FieldContent` to keep descriptions aligned.
- **Responsive fields:** Set `orientation="responsive"` for automatic column layouts inside container-aware parents. Apply `@container/field-group` classes on `FieldGroup` to switch orientations at specific breakpoints.
<ComponentPreview
name="field-responsive"
className="!mb-4 [&_.preview]:h-[650px] [&_.preview]:p-6 [&_.preview]:md:h-[500px] [&_.preview]:md:p-10"
/>
## Validation and Errors
- Add `data-invalid` to `Field` to switch the entire block into an error state.
- Add `aria-invalid` on the input itself for assistive technologies.
- Render `FieldError` immediately after the control or inside `FieldContent` to keep error messages aligned with the field.
```tsx showLineNumbers /data-invalid/ /aria-invalid/
<Field data-invalid>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" aria-invalid />
<FieldError>Enter a valid email address.</FieldError>
</Field>
```
## Accessibility
- `FieldSet` and `FieldLegend` keep related controls grouped for keyboard and assistive tech users.
- `Field` outputs `role="group"` so nested controls inherit labeling from `FieldLabel` and `FieldLegend` when combined.
- Apply `FieldSeparator` sparingly to ensure screen readers encounter clear section boundaries.
## API Reference
### FieldSet
Container that renders a semantic `fieldset` with spacing presets.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldSet>
<FieldLegend>Delivery</FieldLegend>
<FieldGroup>{/* Fields */}</FieldGroup>
</FieldSet>
```
### FieldLegend
Legend element for a `FieldSet`. Switch to the `label` variant to align with label sizing.
| Prop | Type | Default |
| ----------- | --------------------- | ---------- |
| `variant` | `"legend" \| "label"` | `"legend"` |
| `className` | `string` | |
```tsx
<FieldLegend variant="label">Notification Preferences</FieldLegend>
```
The `FieldLegend` has two variants: `legend` and `label`. The `label` variant applies label sizing and alignment. Handy if you have nested `FieldSet`.
### FieldGroup
Layout wrapper that stacks `Field` components and enables container queries for responsive orientations.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldGroup className="@container/field-group flex flex-col gap-6">
<Field>{/* ... */}</Field>
<Field>{/* ... */}</Field>
</FieldGroup>
```
### Field
The core wrapper for a single field. Provides orientation control, invalid state styling, and spacing.
| Prop | Type | Default |
| -------------- | -------------------------------------------- | ------------ |
| `orientation` | `"vertical" \| "horizontal" \| "responsive"` | `"vertical"` |
| `className` | `string` | |
| `data-invalid` | `boolean` | |
```tsx
<Field orientation="horizontal">
<FieldLabel htmlFor="remember">Remember me</FieldLabel>
<Switch id="remember" />
</Field>
```
### FieldContent
Flex column that groups control and descriptions when the label sits beside the control. Not required if you have no description.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<Field>
<Checkbox id="notifications" />
<FieldContent>
<FieldLabel htmlFor="notifications">Notifications</FieldLabel>
<FieldDescription>Email, SMS, and push options.</FieldDescription>
</FieldContent>
</Field>
```
### FieldLabel
Label styled for both direct inputs and nested `Field` children.
| Prop | Type | Default |
| ----------- | --------- | ------- |
| `className` | `string` | |
| `asChild` | `boolean` | `false` |
```tsx
<FieldLabel htmlFor="email">Email</FieldLabel>
```
### FieldTitle
Renders a title with label styling inside `FieldContent`.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldContent>
<FieldTitle>Enable Touch ID</FieldTitle>
<FieldDescription>Unlock your device faster.</FieldDescription>
</FieldContent>
```
### FieldDescription
Helper text slot that automatically balances long lines in horizontal layouts.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldDescription>We never share your email with anyone.</FieldDescription>
```
### FieldSeparator
Visual divider to separate sections inside a `FieldGroup`. Accepts optional inline content.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldSeparator>Or continue with</FieldSeparator>
```
### FieldError
Accessible error container that accepts children or an `errors` array (e.g., from `react-hook-form`).
| Prop | Type | Default |
| ----------- | ------------------------------------------ | ------- |
| `errors` | `Array<{ message?: string } \| undefined>` | |
| `className` | `string` | |
```tsx
<FieldError errors={errors.username} />
```
When the `errors` array contains multiple messages, the component renders a list automatically.
`FieldError` also accepts issues produced by any validator that implements [Standard Schema](https://standardschema.dev/), including Zod, Valibot, and ArkType. Pass the `issues` array from the schema result directly to render a unified error list across libraries.
@@ -1,4 +0,0 @@
---
title: Fragment components
description: ''
---
@@ -59,3 +59,9 @@ import { Slider } from '@/components/ui/slider'
```tsx
<Slider defaultValue={[33]} max={100} step={1} />
```
## Examples
### Min and Max Range
<ComponentPreview name="slider-minMax-range" peekCode wide />
@@ -1,64 +1,134 @@
---
title: Table
description: A responsive table component for basic data.
description: A responsive table component for presenting data inline.
component: true
source:
shadcn: true
---
Table presents basic tabular data presentation within a [Card](/docs/components/card).
Table is an opinionated `<table>` element for basic tabular data presentation. It is usually presented within a [Card](../components/card).
<ComponentPreview name="table-demo" peekCode wide />
Columns will naturally take the width of their content. Width specification is therefore not required unless you require columns to span a specific width. An example use-case may be when placing multiple Table instances on the one page, where columns on each table should optically align.
`TableHead` includes a `whitespace-nowrap` utility class to prevent its text from wrapping. `TableCell` must have any custom width specified, as there are legitimate use cases for both wrapping (or truncated) text.
## Usage
```tsx
import {
Card,
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
} from 'ui'
```
```tsx
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">INV001</TableCell>
<TableCell>Paid</TableCell>
<TableCell>Credit Card</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
</TableBody>
</Table>
<Card>
<Table>
<TableHeader>
<TableRow>
<TableHead>Column 1</TableHead>
<TableHead>Column 2</TableHead>
<TableHead>Column 3</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Value 1</TableCell>
<TableCell>Value 2</TableCell>
<TableCell>Value 3</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={2}>Total</TableCell>
<TableCell>Value</TableCell>
</TableRow>
</TableFooter>
</Table>
</Card>
```
## Sortable Columns
## Layout
Use `TableHeadSort` inside `TableHead` to enable column sorting.
Columns will naturally take the width of their content unless otherwise specified. Specific column widths may be useful for controlling layout shift or for aligning multiple Table instances vertically.
Table Head includes a `whitespace-nowrap` utility class to prevent its text from wrapping. Table Cell must have any custom width specified, as there are legitimate use cases for both wrapping (or truncated) text.
The Table component is wrapped in a `ShadowScrollArea` by default, which provides horizontal scrolling on smaller screens when the table content exceeds the viewport width.
## Structure
Table is comprised of the following [Shadcn primitives](https://ui.shadcn.com/docs/components/table) which map directly to their HTML counterparts:
| Component | HTML element |
| ------------- | ------------------------------------------------------------------------------------------- |
| Table | [`<table>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table) |
| Table Body | [`<tbody>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tbody) |
| Table Caption | [`<caption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/caption) |
| Table Cell | [`<td>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/td) |
| Table Footer | [`<tfoot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tfoot) |
| Table Head | [`<th>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/th) |
| Table Header | [`<thead>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/thead) |
| Table Row | [`<tr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tr) |
Table and its child components follow their HTML element counterparts for semantics, accessibility, and best practices.
### Table Caption
Table Caption describes a table’s purpose or content. Think of it like the label of a diagram. It should only contain a single text node.
Just like its `<caption>` counterpart, Table Caption should be the first child of a Table element (before a Table Body) irrespective of its final visual positioning.
### Table Footer
Table Footer is a semantic grouping for the final rows of a table, typically used for column summaries, totals, or footnotes that relate to the data in the body of the table.
Table Footer typically contains the same child elements as a Table Body, such as Table Row and Table Cell, and is a sibling of Table Body.
## Examples
### Empty state
When displaying an empty state within a table, dim the Table Head text to indicate that no data is present. Use consistent zero results presentation across your application to maintain a cohesive user experience.
<ComponentPreview name="empty-state-zero-items-table" />
To prevent the empty state row from being highlighted on hover, apply the `[&>td]:hover:bg-inherit` class to the Table Row containing the empty state message.
```tsx showLineNumbers {1}
<TableRow className="[&>td]:hover:bg-inherit">
<TableCell colSpan={3}>
<p className="text-sm text-foreground">No results found</p>
<p className="text-sm text-foreground-lighter">
Your search for “test” did not return any results
</p>
</TableCell>
</TableRow>
```
See [Empty States](../ui-patterns/empty-states) for more information.
### Sortable columns
Use `TableHeadSort` inside Table Head to enable column sorting. This component provides visual indicators for sort state (ascending, descending, or unsorted) and handles click interactions.
```tsx
import { TableHeadSort } from 'ui'
```
| Prop | Type | Description |
| -------------- | -------------------------- | ------------------------------------------------------------------ |
| `column` | `string` | Unique identifier for the column |
| `currentSort` | `string` | Current sort state in format `"column:order"` (e.g., `"name:asc"`) |
| `onSortChange` | `(column: string) => void` | Callback fired when column header is clicked |
| `children` | `ReactNode` | The label text for the column header |
| `className` | `string` | Optional additional CSS classes |
```tsx
```tsx showLineNumbers {2}
<TableHead>
<TableHeadSort column="name" currentSort={sort} onSortChange={handleSortChange}>
Name
@@ -66,10 +136,85 @@ Use `TableHeadSort` inside `TableHead` to enable column sorting.
</TableHead>
```
## Data Table
The component displays:
You can use the `<Table />` component to build more complex data tables. Combine it with [@tanstack/react-table](https://tanstack.com/table/v8) to create tables with sorting, filtering and pagination.
- An up arrow when the column is sorted ascending
- A down arrow when the column is sorted descending
- A chevrons icon when the column is not currently sorted (visible on hover)
See the [Data Table](/docs/components/data-table) documentation for more information.
<ComponentPreview name="table-sort" />
You can also see an example of a data table in the [Tasks](/examples/tasks) demo.
### Row icons
When adding icon columns to your table, use [Accessibility](../accessibility) markup by including a screen reader-only label in the corresponding Table Head using the `sr-only` class. This ensures that assistive technologies can properly identify the column's purpose. Remove these icon cells when loading or displaying zero results to maintain a clean and consistent table structure.
<ComponentPreview name="table-icons" />
```tsx showLineNumbers {4, 5, 13, 14}
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-1">
<span className="sr-only">Icon</span>
</TableHead>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="w-1">
<IconName size={16} className="text-foreground-muted" />
</TableCell>
<TableCell>Value</TableCell>
<TableCell>Value</TableCell>
</TableRow>
</TableBody>
</Table>
```
### Actions
Action should be placed in the last column of each Table Row to maintain a logical reading flow. Users scan table data from left to right, so positioning actions on the right ensures they encounter the primary information first before reaching interactive controls.
#### Multiple actions
When multiple actions are available for a row, display one primary action as a button and place additional options in an overflow menu. This keeps the table clean and scannable while providing access to all necessary actions without overwhelming the user.
<ComponentPreview name="table-actions" />
#### Cross-links
You may need to link to related resources from within table cells. In these cases, use the `text-link-table-cell` CSS class to provide a visual hint that the text is interactive while maintaining its appearance as tertiary content.
<ComponentPreview name="table-cross-link" />
Avoid making the entire row interactive when using cross-links. Multiple interactive areas within a single row increases the chance of mis-taps and creates ambiguity about which action will be triggered. Keep cross-links as discrete, scannable elements within their respective cells, and maintain a dedicated action column for primary row-level actions.
#### Row-level navigation
The entire Table Row may be tappable. This pattern is most effective when navigation is the sole or primary action for each row, as it provides a large, easy-to-target interaction area.
Avoid adding other actions when using row-level navigation, as multiple interactive areas within a single row create competing affordances and increase interaction complexity.
<ComponentPreview name="table-row-link" />
When implementing row-level navigation, pay close attention to [Accessibility](/accessibility#focus-management) requirements. The row must be keyboard accessible with proper focus management, including:
- Handling `Enter` and `Space` key presses for activation
- Providing visual focus indicators using classes like `inset-focus`
- Supporting modifier keys (`Ctrl`/`Cmd`) for opening links in new tabs
#### Row navigation with actions
If you must combine row-level navigation with additional actions, nest all secondary actions in an overflow menu and maintain a [ChevronRight](https://lucide.dev/icons/chevron-right) visual indicator to signal that the row is navigable. This pattern preserves the primary navigation affordance while keeping secondary actions accessible but unobtrusive.
<ComponentPreview name="table-row-link-actions" />
This hybrid approach requires careful attention to event handling. Ensure that taps on action buttons stop event propagation to prevent triggering row navigation, and maintain clear visual separation between the navigable row area and the action controls.
## Related
Use the Table component for simple, static tabular data presentation with a fixed number of rows. Consider using [Data Table](../ui-patterns/tables#data-table) for more complex cases as it provides built-in sorting, filtering, and pagination capabilities.
Refer to [Tables](../ui-patterns/tables) for broader guidance and best practices on presenting tabular data.
@@ -4,7 +4,7 @@ description: Displays a callout for user attention.
fragment: true
---
Admonition provides focus for situations that require a callout. Use this instead of [Alert](../components/alert) unless you specifically need the primitives.
Admonition provides focus for situations that require a callout.
<ComponentPreview
name="admonition-demo"
@@ -13,6 +13,8 @@ Admonition provides focus for situations that require a callout. Use this instea
wide
/>
Use Admonition instead of [Alert](../components/alert) unless you specifically need the primitives. If in doubt, stick with Admonition.
## Usage
```tsx
@@ -54,6 +56,13 @@ Only ever use the `primary` (green) button `type` on a `default` Admonition. Eve
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
/>
There are several components that wrap the `warning` Admonition type with reusable text or functionality. These include:
- AlertError
- NoPermission
AlertError for example rolls up consistent error handling and support contact methods.
### Destructive
<ComponentPreview
@@ -0,0 +1,10 @@
---
title: Fragment components
description: Reusable composite components assembled from atom components to solve common interface needs.
---
Fragment components are pre-built composite components that combine multiple atom components to create reusable interface elements. Unlike atom components (basic building blocks like buttons and inputs) or UI patterns (guidelines for structuring entire sections), fragment components are ready-to-use solutions for specific interface needs.
These components help maintain consistency across Supabase products by providing standardized implementations for common interface patterns like data visualization, dialogs, empty states, forms, layout, and navigation.
Fragment components are imported from the `ui-patterns` package and can be used directly in your application. They encapsulate common combinations of atom components, reducing boilerplate and ensuring consistent behavior across similar features.
+25 -1
View File
@@ -3,10 +3,11 @@ title: Introduction
description: Components and patterns that you can copy and paste into Supabase apps. Accessible. Customizable. Open Source.
---
Welcome to the Supabase Design System!
## FAQ
<Accordion type="multiple">
<AccordionItem value="faq-1">
<AccordionTrigger>
Why copy/paste and not packaged as a dependency?
@@ -20,5 +21,28 @@ One of the drawback of packaging the components in an npm package is that the st
</AccordionContent>
</AccordionItem>
<AccordionItem value="faq-2">
<AccordionTrigger>
Which libraries do you use?
</AccordionTrigger>
<AccordionContent>
We use the following libraries as a basis. Anywhere we use additional libraries, we document them in the individual component pages.
- [tailwindcss](https://tailwindcss.com)
- [shadcn/ui](https://ui.shadcn.com)
- [lucide-react](https://lucide.dev)
- [react-hook-form](https://react-hook-form.com)
You can find the full list of dependencies in the [package.json](https://github.com/supabase/design-system/blob/main/package.json) file.
</AccordionContent>
</AccordionItem>
<AccordionItem value="faq-3">
<AccordionTrigger>
I was looking for Supabase UI Library
</AccordionTrigger>
<AccordionContent>
If you are looking for the Supabase UI, you can find it [here](https://supabase.com/ui).
</AccordionContent>
</AccordionItem>
</Accordion>
@@ -0,0 +1,281 @@
---
title: Charts
description: Composable charts for Reports, Dashboards and other visualizations.
links:
doc: https://recharts.github.io/en-US/
source:
recharts: true
---
<ComponentPreview name="chart-composed-demo" peekCode wide />
## About
Charts are an integral part of Observability at Supabase. Charts aim to be composable and reusable for frictionless setup.
Our charts use a combination of our own presentational components and [Recharts](https://recharts.github.io/en-US/) for extensibility.
## Best Practices
1. **Use provided chart types first**: Always try to use the default provided charts first, otherwise passing Recharts compoennts to `<ChartContent>` is possible but not recommended to avoid complexity.
2. **Use the `useChart` context to show loading and disabled states**: The `useChart` context provides boolean flags for child components to show `isLoading` and `isDisabled` states.
3. **Keep it simple**: Try to avoid abstracting the chart content too much. These components should cover most of your presentational needs.
## Examples
### Basic Chart Types
<ComponentPreview name="chart-composed-basic" wide />
### Chart States
<ComponentPreview name="chart-composed-states" wide />
### Charts as Standalone Metrics
<ComponentPreview name="chart-composed-metrics" wide />
### Charts with Actions
<ComponentPreview name="chart-composed-actions" wide />
### Chart with Table
<ComponentPreview name="chart-composed-table" wide />
You can pass through our [Table](/docs/components/table) component to the `ChartFooter` and expect it to be styled correctly. There is no additional need to style the table, `ChartFooter` will handle the styling for you.
## API
### Chart
The root container component that provides chart context to all child components.
| Prop | Type | Default | Description |
| ------------ | -------------------------------------- | ------- | ------------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Chart child components |
| `isLoading` | `boolean` | `false` | Shows loading state in child components via the `useChart` context |
| `isDisabled` | `boolean` | `false` | Disables chart interactions via the `useChart` context |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartCard
A card wrapper for the chart. Can be used as a Card component or as a slot.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ------- | ----------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Chart content |
| `asChild` | `boolean` | - | Render as child component (uses Slot) - ideal for removing the `Card` wrapper |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartHeader
Container for chart header content like title and actions.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ---------- | ------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Header content (typically ChartTitle, ChartActions, or ChartMetric) |
| `align` | `'start' \| 'center'` | `'center'` | Alignment of header content |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartTitle
Displays the chart title with optional tooltip.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ------- | ------------------------------------- |
| `children` | `React.ReactNode` | - | Title text |
| `tooltip` | `string` | - | Tooltip text shown on help icon hover |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartActions
Renders action buttons or links in the chart header.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ------- | ---------------------------------------------------------- |
| `actions` | `ChartAction[]` | - | Array of action objects (see ChartAction type below) |
| `children` | `React.ReactNode` | - | Custom action content (takes precedence over actions prop) |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
#### ChartAction Type
| Property | Type | Description |
| ----------- | -------------------- | ----------------------------------------------- |
| `label` | `string` | Accessible label for the action |
| `icon` | `React.ReactNode` | Icon component to display |
| `onClick` | `() => void` | Click handler for button actions |
| `href` | `string` | URL for link actions |
| `type` | `'button' \| 'link'` | Action type (auto-detected if href is provided) |
| `className` | `string` | Additional CSS classes |
### ChartMetric
Displays a metric value with optional status indicator.
| Prop | Type | Default | Description |
| ----------- | ---------------------------------------------------- | --------- | --------------------------------------------------- |
| `label` | `string` | - | Metric label text |
| `value` | `string \| number \| null \| undefined` | - | Metric value to display |
| `diffValue` | `string \| number \| null \| undefined` | - | Differential value to display (shown as +/- change) |
| `status` | `'positive' \| 'negative' \| 'warning' \| 'default'` | - | Status indicator color |
| `align` | `'start' \| 'end'` | `'start'` | Alignment of the metric |
| `tooltip` | `string` | - | Tooltip text shown on help icon hover |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartContent
Container for the main chart visualization. Handles loading and empty states.
| Prop | Type | Default | Description |
| ----------------- | -------------------------------------- | ------- | -------------------------------------- |
| `children` | `React.ReactNode` | - | Chart visualization content |
| `isEmpty` | `boolean` | `false` | Whether to show empty state |
| `emptyState` | `React.ReactNode` | - | Custom empty state component |
| `loadingState` | `React.ReactNode` | - | Custom loading state component |
| `disabledState` | `React.ReactNode` | - | Custom disabled state component |
| `disabledActions` | `ChartAction[]` | - | Actions to show when chart is disabled |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartEmptyState
Pre-built empty state component for charts.
| Prop | Type | Default | Description |
| ------------- | -------------------------------------- | ------- | ------------------------ |
| `title` | `string` | - | Empty state title |
| `description` | `string` | - | Empty state description |
| `icon` | `React.ReactNode` | - | Optional icon to display |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartLoadingState
Pre-built loading state component. Takes no props.
### ChartFooter
Container for footer content below the chart.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ------- | ---------------------- |
| `children` | `React.ReactNode` | - | Footer content |
| `className` | `string` | - | Additional CSS classes |
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | - | All standard div props |
### ChartConfig
Type definition for chart configuration used with Recharts components.
```tsx
type ChartConfig = {
[key: string]: {
label?: React.ReactNode
icon?: React.ComponentType
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<'light' | 'dark', string> }
)
}
```
| Property | Type | Description |
| -------- | ----------------------------------- | -------------------------------------------------------- |
| `label` | `React.ReactNode` | Label for the data series |
| `icon` | `React.ComponentType` | Icon component for the data series |
| `color` | `string` | Single color value (mutually exclusive with theme) |
| `theme` | `Record<'light' \| 'dark', string>` | Theme-aware color values (mutually exclusive with color) |
### ChartLine
Line chart component for displaying time-series data.
| Prop | Type | Default | Description |
| ------------------- | --------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------- |
| `data` | `ChartLineTick[]` | - | Array of data points with timestamp |
| `dataKey` | `string` | - | Key in data object to plot |
| `config` | `ChartConfig?` | - | Chart configuration for styling |
| `onLineClick` | `(datum: ChartLineTick, tooltipData?: CategoricalChartState) => void` | - | Click handler for line points |
| `DateTimeFormat` | `string` | `'MMM D, YYYY, hh:mma'` | Date format for tooltips and labels |
| `isFullHeight` | `boolean` | `false` | Whether chart should take full height |
| `className` | `string` | - | Additional CSS classes |
| `color` | `string` | `'hsl(var(--brand-default))'` | Line color |
| `hoverColor` | `string` | `'hsl(var(--brand-500))'` | Line color on hover |
| `chartHighlight` | `ChartHighlight` | - | Highlight selection configuration |
| `updateDateRange` | `(from: string, to: string) => void` | - | Callback when date range is updated via highlight |
| `highlightActions` | `ChartHighlightAction[]` | - | Actions to show when area is highlighted |
| `syncId` | `string` | - | ID to sync multiple charts |
| `showHighlightArea` | `boolean` | `true` | Whether to show highlight area |
| `cursor` | `string` | - | Cursor style (defaults to 'crosshair' if chartHighlight provided) |
| `showGrid` | `boolean` | `false` | Whether to show grid lines |
| `showYAxis` | `boolean` | `false` | Whether to show Y-axis |
| `YAxisProps` | `object` | - | Additional Y-axis props (tick, tickFormatter, width, etc.) |
| `strokeWidth` | `number` | `1.5` | Line stroke width |
#### ChartLineTick Type
| Property | Type | Description |
| --------------- | ------------------ | ---------------------------- |
| `timestamp` | `string` | Timestamp for the data point |
| `[key: string]` | `string \| number` | Additional data fields |
#### ChartHighlight Type
| Property | Type | Description |
| ----------------- | ------------------------------------------------------------- | ------------------------------------ |
| `handleMouseDown` | `(e: { activeLabel?: string; coordinates?: string }) => void` | Mouse down handler |
| `handleMouseMove` | `(e: { activeLabel?: string; coordinates?: string }) => void` | Mouse move handler |
| `handleMouseUp` | `(e: { chartX?: number; chartY?: number }) => void` | Mouse up handler |
| `coordinates` | `{ left?: string; right?: string }` | Highlight area coordinates |
| `clearHighlight` | `() => void?` | Optional function to clear highlight |
#### ChartHighlightAction Type
| Property | Type | Description |
| ------------ | -------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `id` | `string` | Unique identifier for the action |
| `label` | `string \| ((ctx: { start: string; end: string; clear: () => void }) => string)` | Action label or function that returns label |
| `icon` | `ReactNode?` | Optional icon component |
| `isDisabled` | `(ctx: { start: string; end: string; clear: () => void }) => boolean?` | Optional function to determine if action is disabled |
| `onSelect` | `(ctx: { start: string; end: string; clear: () => void }) => void` | Action selection handler |
### ChartBar
Bar chart component for displaying time-series data.
| Prop | Type | Default | Description |
| ------------------- | -------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------- |
| `data` | `ChartBarTick[]` | - | Array of data points with timestamp |
| `dataKey` | `string` | - | Key in data object to plot |
| `config` | `ChartConfig?` | - | Chart configuration for styling |
| `onBarClick` | `(datum: ChartBarTick, tooltipData?: CategoricalChartState) => void` | - | Click handler for bars |
| `DateTimeFormat` | `string` | `'MMM D, YYYY, hh:mma'` | Date format for tooltips and labels |
| `isFullHeight` | `boolean` | `false` | Whether chart should take full height |
| `className` | `string` | - | Additional CSS classes |
| `color` | `string` | `'hsl(var(--brand-default))'` | Bar color |
| `hoverColor` | `string` | `'hsl(var(--brand-500))'` | Bar color on hover |
| `chartHighlight` | `ChartHighlight` | - | Highlight selection configuration |
| `updateDateRange` | `(from: string, to: string) => void` | - | Callback when date range is updated via highlight |
| `highlightActions` | `ChartHighlightAction[]` | - | Actions to show when area is highlighted |
| `syncId` | `string` | - | ID to sync multiple charts |
| `showHighlightArea` | `boolean` | `true` | Whether to show highlight area |
| `cursor` | `string` | - | Cursor style (defaults to 'crosshair' if chartHighlight provided) |
| `showGrid` | `boolean` | `false` | Whether to show grid lines |
| `showYAxis` | `boolean` | `false` | Whether to show Y-axis |
| `YAxisProps` | `object` | - | Additional Y-axis props (tick, tickFormatter, width, etc.) |
#### ChartBarTick Type
| Property | Type | Description |
| --------------- | ------------------ | ---------------------------- |
| `timestamp` | `string` | Timestamp for the data point |
| `[key: string]` | `string \| number` | Additional data fields |
@@ -14,7 +14,7 @@ There are two ways an empty state may be displayed in cases where there is no da
### Initial state
Perhaps the user has not yet created any data. The presentation of this empty state depends on the context of the list and the type of data it contains.
Perhaps the user has not yet created any data. The presentation of this empty state depends on the context of the list and the type of data it contains. Be mindful of the journey to rendering an empty state and any possible layout shift along the way.
#### Presentational
@@ -22,7 +22,7 @@ The user may be learning about a feature for the first time, and could benefit f
<ComponentPreview name="empty-state-presentational-icon" peekCode wide />
Remember to use active language in these cases. For example: “Create a vector bucket” instead of “No vector buckets found”. The latter is more appropriate in table-based presentations, as described below.
Remember to use active language in presentational empty states. For example: “Create a vector bucket” instead of “No vector buckets found”. The latter is more appropriate in table-based presentations, as described below.
#### Informational
@@ -42,13 +42,13 @@ A [Table](../components/table) instance with zero results should display a singl
<ComponentPreview name="empty-state-zero-items-table" peekCode wide />
#### DataGrid
#### Data Grid
[DataGrid](../components/data-table) typically spans the full height and width of a container. A classic example is [Users](https://supabase.com/dashboard/project/_/auth/users), which (as it sounds) displays a list of the project’s registered users. Any instance with zero results should display a more prominent empty with a clear title, description, and supporting illustration.
[Data Grid](../ui-patterns/tables#data-grid) and [Data Table](../ui-patterns/tables#data-table) component patterns typically span the full height and width of a container. A classic example is [Users](https://supabase.com/dashboard/project/_/auth/users), which (as it sounds) displays a list of the project’s registered users. Any instance with zero results should display a more prominent empty with a clear title, description, and supporting illustration.
<ComponentPreview name="empty-state-zero-items-data-grid" peekCode wide />
<ComponentPreview name="data-grid-empty-state" peekCode wide />
Other DataGrid instances include [Cron Jobs](https://supabase.com/dashboard/project/_/integrations/cron/jobs) and [Queues](https://supabase.com/dashboard/project/_/integrations/queues).
Other Data Grid instances include [Cron Jobs](https://supabase.com/dashboard/project/_/integrations/cron/jobs) and [Queues](https://supabase.com/dashboard/project/_/integrations/queues).
## Missing route
@@ -61,7 +61,3 @@ Users may accidentally navigate to a non-existent dynamic route, such as a non-e
For presentational empty states (initial states with value propositions and actions), use the [EmptyStatePresentational](../fragments/empty-state-presentational) component from `ui-patterns`. This component provides a consistent structure with support for icons, titles, descriptions, and action buttons.
For other empty state scenarios (zero results, missing routes, etc), custom components may still be appropriate as the context and needs for each placement can differ significantly.
## External references
- [_Empty States_ on GitHub Primer](https://primer.style/product/ui-patterns/empty-states/)
@@ -0,0 +1,83 @@
---
title: Tables
description: Display structured data in a scannable, organized way.
---
Tables are a fundamental pattern for displaying structured data in rows and columns. They provide a scannable, organized way to present collections of related information, making it easy for users to compare values, identify patterns, and take action on specific items.
The choice of table pattern depends on several factors: the complexity of the data, the level of interactivity required, the amount of data being displayed, and the context within the page layout.
## Components
There are three main table patterns, each suited to different use cases:
- [Table](../components/table) is a low-level, presentational table component.
- [Data Table](#data-table) builds on [Table](../components/table) and [TanStack Table](https://tanstack.com/table) to provide a feature-rich data browsing experience (sorting, filtering, pagination, etc.).
- [Data Grid](#data-grid) is a separate grid implementation used for highly interactive, spreadsheet-like surfaces and very large datasets.
Use Table when:
- You need simple, static display
- No filtering or complex behavior is needed
Use Data Table when:
- You need sorting, pagination, filtering, search, or row actions
- You want TanStack-powered behavior with table semantics
Use Data Grid when:
- You need virtualization today
- You need column resizing
- You need spreadsheet-like editing
Data Table and Data Grid are both _pattern components_: they are composed from primitives and built per use case. They are not available as standalone components.
### Table
[Table](../components/table) is designed for simple, static tabular data presentation. It is a presentational wrapper around the HTML `<table>` element. Use it when:
- Displaying a fixed, known number of rows
- The data is primarily read-only
- Sort, filter, or search actions are not required or can be basic
<ComponentPreview name="table-demo" peekCode wide />
### Data Table
Data Table is a pattern component and is not exposed as a Design System component. It is built on top of [Table](../components/table) and [TanStack Table](https://tanstack.com/table).
Data Table extends Table with column definitions and row models (via TanStack) for complex sorting, filtering, and row actions. Use it when:
- Displaying large datasets that require pagination
- Users need to perform complex sort, filter, or search actions through the data
- Row selection is required
Data Table does not yet support virtualization, resizable columns, or advanced editors. These capabilities are planned as part of [consolidation with Data Grid](#future).
<ComponentPreview name="data-table-demo" peekCode wide />
As you can see from the above example, Data Table’s composition is heavily dependent on use case. We do not yet have a shared Design System component for this reason.
Follow [Shadcn’s Data Table documentation](https://ui.shadcn.com/docs/components/data-table) for a complete guide on building upon the Data Table pattern for each specific use case. These patterns map closely to the approaches we follow internally.
### Data Grid
Data Grid is a pattern component and is not exposed as a Design System component. It is based on [React Data Grid](https://comcast.github.io/react-data-grid/#/CommonFeatures) and originally adopted for areas including Studio’s Table Editor, Query Performance, and other high-interaction surfaces.
Use it only when you need virtualization, column resizing, or complex cell editing. Otherwise [Data Table](#data-table) is simpler and more flexible.
<ComponentPreview name="data-grid-demo" peekCode wide />
## Future
Data Table and Data Grid overlap significantly. We’re looking at consolidating these into one data table component, which will likely be improvements to Data Table given the numerous advantages of TanStack Table and difficulties extending React Data Grid.
The likely direction is a single Data Table component built on TanStack Table, with
- Virtualization
- Resizable columns
- Plug-in cell editors
- Shared filtering/sorting utilities
- Shared UI patterns (horizontal and vertical filter bars, date pickers, side panels)
- Accessible, semantic HTML table markup
@@ -0,0 +1,16 @@
---
title: UI patterns
description: Higher-level guidance on how to compose components together to solve common interface problems.
---
UI patterns are reusable design solutions that combine multiple components from our design system to address common interface challenges. Unlike atom components (basic building blocks like buttons and inputs) or fragment components (pre-built composite components), UI patterns provide guidelines and best practices for structuring entire interface sections.
These patterns help ensure consistency across Supabase products by establishing standard approaches for:
- **[Charts](/docs/ui-patterns/charts)**: Visualizing data consistently using standardized chart types and styling.
- **[Empty States](/docs/ui-patterns/empty-states)**: Communicating the absence of data and guiding users toward meaningful actions.
- **[Forms](/docs/ui-patterns/forms)**: Building cohesive form experiences in both page layouts and side panels.
- **[Layout](/docs/ui-patterns/layout)**: Creating consistent page structures with proper spacing, max-widths, and content organization.
- **[Navigation](/docs/ui-patterns/navigation)**: Organizing complex hierarchical navigation systems across multiple products and contexts.
UI patterns may incorporate external libraries (such as `react-markdown`, `reactflow`, `recharts`, etc) or compose various components from the `ui` package. They serve as blueprints for solving recurring design problems, ensuring that similar features across the application follow the same structural and interaction patterns.
@@ -53,6 +53,9 @@ const NestedProperties = defineNestedType(() => ({
reactAccessibleTreeview: {
type: 'boolean',
},
recharts: {
type: 'boolean',
},
},
}))
+9 -1
View File
@@ -1,4 +1,12 @@
const { defineConfig } = require('eslint/config')
const supabaseConfig = require('eslint-config-supabase/next')
module.exports = defineConfig([supabaseConfig])
module.exports = defineConfig([
supabaseConfig,
{
files: ['registry/**/*.tsx', '__registry__/**/*.tsx'],
rules: {
'no-restricted-exports': 'off',
},
},
])
@@ -7,10 +7,6 @@ import { visit } from 'unist-util-visit'
import { Index } from '../__registry__'
import { styles } from '../registry/styles'
// import { parse } from 'react-docgen'
// import * as reactDocgenTypescript from 'react-docgen-typescript'
// import { Column, IColumnProps } from './sample-component'
import React from 'react' // ComponentType
@@ -38,61 +34,6 @@ export function rehypeComponent() {
type?: string
}) || {}
// console.log(srcPath, componentName)
// inspectComponentProps(Column)
// console.log('NEW NODE: ', node.name)
// if (node.name === 'ComponentProps') {
// // Parse a file for docgen info
// const options = {
// // savePropValueAsString: true,
// }
// // const parser = reactDocgenTypescript.parse('./sample-component.tsx', options)
// // console.log('PARSER', parser)
// const code = `
// /** My first component */
// export default ({ name, title }: {
// /** My first component */
// name: string,
// /** My first component */
// title: string
// }) => <div>{{name}}</div>;
// `
// // console.log('node', node)
// const documentation = parse(code)[0]
// // console.log('documentation', documentation)
// // Add attributes to object
// node.attributes?.push({
// type: 'mdxJsxAttribute',
// name: 'docs',
// value: JSON.stringify(documentation),
// })
// // console.log('node after', node)
// // Add random text as children
// // node.children?.push({
// // type: 'text',
// // value: 'I am random text', // Generate a random UUID as text content
// // })
// // node.data = {
// // ...node.data,
// // name: 'documentation',
// // type: 'mdxJsxAttribute',
// // value: documentation,
// // }
// }
if (node.name === 'ComponentSource') {
// console.log('DO NOT USE THIS COMPONENT')
// This component should not be in use!
+2 -2
View File
@@ -18,9 +18,10 @@
},
"dependencies": {
"@hookform/resolvers": "^3.1.1",
"@tanstack/react-table": "^8.21.3",
"contentlayer2": "0.4.6",
"dayjs": "1.11.13",
"date-fns": "^2.30.0",
"dayjs": "1.11.13",
"eslint-config-supabase": "workspace:*",
"icons": "workspace:*",
"jotai": "^2.8.0",
@@ -32,7 +33,6 @@
"react": "catalog:",
"react-data-grid": "7.0.0-beta.41",
"react-day-picker": "^9.11.1",
"react-docgen": "^7.0.3",
"react-dom": "catalog:",
"react-hook-form": "^7.45.0",
"react-inlinesvg": "^4.0.4",
+24 -467
View File
@@ -1,113 +1,6 @@
import { Registry } from './schema'
export const charts: Registry = [
// Area Charts
{
name: 'chart-area-axes',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-axes.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-default',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-default.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-gradient',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-gradient.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-icons',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-icons.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-interactive',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-interactive.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-legend',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-legend.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-linear',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-linear.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-stacked-expand',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-stacked-expand.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-stacked',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-stacked.tsx'],
category: 'Charts',
subcategory: 'Area',
},
{
name: 'chart-area-step',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-area-step.tsx'],
category: 'Charts',
subcategory: 'Area',
},
// Bar Charts
{
name: 'chart-bar-active',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-active.tsx'],
category: 'Charts',
subcategory: 'Bar',
},
{
name: 'chart-bar-default',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-default.tsx'],
category: 'Charts',
subcategory: 'Bar',
},
{
name: 'chart-bar-horizontal',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-horizontal.tsx'],
category: 'Charts',
subcategory: 'Bar',
},
{
name: 'chart-bar-interactive',
type: 'components:block',
@@ -117,387 +10,51 @@ export const charts: Registry = [
subcategory: 'Bar',
},
{
name: 'chart-bar-label-custom',
name: 'chart-composed-demo',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-label-custom.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-demo.tsx'],
category: 'Charts',
subcategory: 'Bar',
subcategory: 'Composed',
},
{
name: 'chart-bar-label',
name: 'chart-composed-basic',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-label.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-basic.tsx'],
category: 'Charts',
subcategory: 'Bar',
subcategory: 'Composed',
},
{
name: 'chart-bar-mixed',
name: 'chart-composed-states',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-mixed.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-states.tsx'],
category: 'Charts',
subcategory: 'Bar',
subcategory: 'Composed',
},
{
name: 'chart-bar-multiple',
name: 'chart-composed-table',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-multiple.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-table.tsx'],
category: 'Charts',
subcategory: 'Bar',
subcategory: 'Composed',
},
{
name: 'chart-bar-negative',
name: 'chart-composed-metrics',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-negative.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-metrics.tsx'],
category: 'Charts',
subcategory: 'Bar',
subcategory: 'Composed',
},
{
name: 'chart-bar-stacked',
name: 'chart-composed-actions',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-bar-stacked.tsx'],
registryDependencies: ['chart'],
files: ['block/chart-composed-actions.tsx'],
category: 'Charts',
subcategory: 'Bar',
},
// Line Charts
{
name: 'chart-line-default',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-default.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-dots-colors',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-dots-colors.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-dots-custom',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-dots-custom.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-dots',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-dots.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-interactive',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-interactive.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-label-custom',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-label-custom.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-label',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-label.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-linear',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-linear.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-multiple',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-multiple.tsx'],
category: 'Charts',
subcategory: 'Line',
},
{
name: 'chart-line-step',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-line-step.tsx'],
category: 'Charts',
subcategory: 'Line',
},
// Pie Charts
{
name: 'chart-pie-donut-active',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-donut-active.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-donut-text',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-donut-text.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-donut',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-donut.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-interactive',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-interactive.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-label-custom',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-label-custom.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-label-list',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-label-list.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-label',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-label.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-legend',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-legend.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-separator-none',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-separator-none.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-simple',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-simple.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
{
name: 'chart-pie-stacked',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-pie-stacked.tsx'],
category: 'Charts',
subcategory: 'Pie',
},
// Radar Charts
{
name: 'chart-radar-default',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-default.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-dots',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-dots.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-circle-fill',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-circle-fill.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-circle-no-lines',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-circle-no-lines.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-circle',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-circle.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-custom',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-custom.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-fill',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-fill.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-grid-none',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-grid-none.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-icons',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-icons.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-label-custom',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-label-custom.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-legend',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-legend.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-lines-only',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-lines-only.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-multiple',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-multiple.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
{
name: 'chart-radar-radius',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radar-radius.tsx'],
category: 'Charts',
subcategory: 'Radar',
},
// Radial Charts
{
name: 'chart-radial-grid',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-grid.tsx'],
category: 'Charts',
subcategory: 'Radial',
},
{
name: 'chart-radial-label',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-label.tsx'],
category: 'Charts',
subcategory: 'Radial',
},
{
name: 'chart-radial-shape',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-shape.tsx'],
category: 'Charts',
subcategory: 'Radial',
},
{
name: 'chart-radial-simple',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-simple.tsx'],
category: 'Charts',
subcategory: 'Radial',
},
{
name: 'chart-radial-stacked',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-stacked.tsx'],
category: 'Charts',
subcategory: 'Radial',
},
{
name: 'chart-radial-text',
type: 'components:block',
registryDependencies: ['card', 'chart'],
files: ['block/chart-radial-text.tsx'],
category: 'Charts',
subcategory: 'Radial',
subcategory: 'Composed',
},
]
@@ -1,91 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'An area chart with axes'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Axes</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: -20,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<YAxis tickLine={false} axisLine={false} tickMargin={8} tickCount={3} />
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
<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>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,77 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'A simple area chart'
const chartData = [
{ month: 'January', desktop: 186 },
{ month: 'February', desktop: 305 },
{ month: 'March', desktop: 237 },
{ month: 'April', desktop: 73 },
{ month: 'May', desktop: 209 },
{ month: 'June', desktop: 214 },
]
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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="line" />} />
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,100 +0,0 @@
'use client'
import { TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
export const description = 'An area chart with gradient fill'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Gradient</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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 />} />
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-desktop)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
</linearGradient>
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
</linearGradient>
</defs>
<Area
dataKey="mobile"
type="natural"
fill="url(#fillMobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="url(#fillDesktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
@@ -1,100 +0,0 @@
'use client'
import { TrendingDown, TrendingUp } from 'lucide-react'
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from 'ui'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from 'ui'
export const description = 'An area chart with icons'
const chartData = [
{ 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 chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
icon: TrendingDown,
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
icon: TrendingUp,
},
} satisfies ChartConfig
export default function Component() {
return (
<Card>
<CardHeader>
<CardTitle>Area Chart - Icons</CardTitle>
<CardDescription>Showing total visitors for the last 6 months</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
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="line" />} />
<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"
/>
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter>
</Card>
)
}
Loaded 100 of 640 files, more files were not shown because too many files have changed in this diff. Show more