Skip to content

Commit 8affbb1

Browse files
authored
Merge branch 'main' into dependabot/npm_and_yarn/vite-7.1.5
2 parents f0dde5b + 8749a6b commit 8affbb1

File tree

5 files changed

+287
-5
lines changed

5 files changed

+287
-5
lines changed

eslint.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import js from '@eslint/js'
33
import pluginQuery from '@tanstack/eslint-plugin-query'
44
import reactHooks from 'eslint-plugin-react-hooks'
55
import reactRefresh from 'eslint-plugin-react-refresh'
6+
import { defineConfig } from 'eslint/config'
67
import tseslint from 'typescript-eslint'
78

8-
export default tseslint.config(
9+
export default defineConfig(
910
{ ignores: ['dist', 'src/components/ui'] },
1011
{
1112
extends: [

pnpm-lock.yaml

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from 'recharts'
2+
3+
const data = [
4+
{
5+
name: 'Mon',
6+
clicks: Math.floor(Math.random() * 900) + 100,
7+
uniques: Math.floor(Math.random() * 700) + 80,
8+
},
9+
{
10+
name: 'Tue',
11+
clicks: Math.floor(Math.random() * 900) + 100,
12+
uniques: Math.floor(Math.random() * 700) + 80,
13+
},
14+
{
15+
name: 'Wed',
16+
clicks: Math.floor(Math.random() * 900) + 100,
17+
uniques: Math.floor(Math.random() * 700) + 80,
18+
},
19+
{
20+
name: 'Thu',
21+
clicks: Math.floor(Math.random() * 900) + 100,
22+
uniques: Math.floor(Math.random() * 700) + 80,
23+
},
24+
{
25+
name: 'Fri',
26+
clicks: Math.floor(Math.random() * 900) + 100,
27+
uniques: Math.floor(Math.random() * 700) + 80,
28+
},
29+
{
30+
name: 'Sat',
31+
clicks: Math.floor(Math.random() * 900) + 100,
32+
uniques: Math.floor(Math.random() * 700) + 80,
33+
},
34+
{
35+
name: 'Sun',
36+
clicks: Math.floor(Math.random() * 900) + 100,
37+
uniques: Math.floor(Math.random() * 700) + 80,
38+
},
39+
]
40+
41+
export function AnalyticsChart() {
42+
return (
43+
<ResponsiveContainer width='100%' height={300}>
44+
<AreaChart data={data}>
45+
<XAxis
46+
dataKey='name'
47+
stroke='#888888'
48+
fontSize={12}
49+
tickLine={false}
50+
axisLine={false}
51+
/>
52+
<YAxis
53+
stroke='#888888'
54+
fontSize={12}
55+
tickLine={false}
56+
axisLine={false}
57+
/>
58+
<Area
59+
type='monotone'
60+
dataKey='clicks'
61+
stroke='currentColor'
62+
className='text-primary'
63+
fill='currentColor'
64+
fillOpacity={0.15}
65+
/>
66+
<Area
67+
type='monotone'
68+
dataKey='uniques'
69+
stroke='currentColor'
70+
className='text-muted-foreground'
71+
fill='currentColor'
72+
fillOpacity={0.1}
73+
/>
74+
</AreaChart>
75+
</ResponsiveContainer>
76+
)
77+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import {
2+
Card,
3+
CardContent,
4+
CardDescription,
5+
CardHeader,
6+
CardTitle,
7+
} from '@/components/ui/card'
8+
import { AnalyticsChart } from './analytics-chart'
9+
10+
export function Analytics() {
11+
type Item = { name: string; value: number }
12+
13+
const SimpleBarList = ({
14+
items,
15+
valueFormatter,
16+
barClass,
17+
}: {
18+
items: Item[]
19+
valueFormatter: (n: number) => string
20+
barClass: string
21+
}) => {
22+
const max = Math.max(...items.map((i) => i.value), 1)
23+
return (
24+
<ul className='space-y-3'>
25+
{items.map((i) => {
26+
const width = `${Math.round((i.value / max) * 100)}%`
27+
return (
28+
<li
29+
key={i.name}
30+
className='flex items-center justify-between gap-3'
31+
>
32+
<div className='min-w-0 flex-1'>
33+
<div className='text-muted-foreground mb-1 truncate text-xs'>
34+
{i.name}
35+
</div>
36+
<div className='bg-muted h-2.5 w-full rounded-full'>
37+
<div
38+
className={`h-2.5 rounded-full ${barClass}`}
39+
style={{ width }}
40+
/>
41+
</div>
42+
</div>
43+
<div className='ps-2 text-xs font-medium tabular-nums'>
44+
{valueFormatter(i.value)}
45+
</div>
46+
</li>
47+
)
48+
})}
49+
</ul>
50+
)
51+
}
52+
return (
53+
<div className='space-y-4'>
54+
<Card>
55+
<CardHeader>
56+
<CardTitle>Traffic Overview</CardTitle>
57+
<CardDescription>Weekly clicks and unique visitors</CardDescription>
58+
</CardHeader>
59+
<CardContent className='px-6'>
60+
<AnalyticsChart />
61+
</CardContent>
62+
</Card>
63+
<div className='grid gap-4 sm:grid-cols-2 lg:grid-cols-4'>
64+
<Card>
65+
<CardHeader className='flex flex-row items-center justify-between space-y-0 pb-2'>
66+
<CardTitle className='text-sm font-medium'>Total Clicks</CardTitle>
67+
<svg
68+
xmlns='http://www.w3.org/2000/svg'
69+
viewBox='0 0 24 24'
70+
fill='none'
71+
stroke='currentColor'
72+
strokeLinecap='round'
73+
strokeLinejoin='round'
74+
strokeWidth='2'
75+
className='text-muted-foreground h-4 w-4'
76+
>
77+
<path d='M3 3v18h18' />
78+
<path d='M7 15l4-4 4 4 4-6' />
79+
</svg>
80+
</CardHeader>
81+
<CardContent>
82+
<div className='text-2xl font-bold'>1,248</div>
83+
<p className='text-muted-foreground text-xs'>+12.4% vs last week</p>
84+
</CardContent>
85+
</Card>
86+
<Card>
87+
<CardHeader className='flex flex-row items-center justify-between space-y-0 pb-2'>
88+
<CardTitle className='text-sm font-medium'>
89+
Unique Visitors
90+
</CardTitle>
91+
<svg
92+
xmlns='http://www.w3.org/2000/svg'
93+
viewBox='0 0 24 24'
94+
fill='none'
95+
stroke='currentColor'
96+
strokeLinecap='round'
97+
strokeLinejoin='round'
98+
strokeWidth='2'
99+
className='text-muted-foreground h-4 w-4'
100+
>
101+
<circle cx='12' cy='7' r='4' />
102+
<path d='M6 21v-2a6 6 0 0 1 12 0v2' />
103+
</svg>
104+
</CardHeader>
105+
<CardContent>
106+
<div className='text-2xl font-bold'>832</div>
107+
<p className='text-muted-foreground text-xs'>+5.8% vs last week</p>
108+
</CardContent>
109+
</Card>
110+
<Card>
111+
<CardHeader className='flex flex-row items-center justify-between space-y-0 pb-2'>
112+
<CardTitle className='text-sm font-medium'>Bounce Rate</CardTitle>
113+
<svg
114+
xmlns='http://www.w3.org/2000/svg'
115+
viewBox='0 0 24 24'
116+
fill='none'
117+
stroke='currentColor'
118+
strokeLinecap='round'
119+
strokeLinejoin='round'
120+
strokeWidth='2'
121+
className='text-muted-foreground h-4 w-4'
122+
>
123+
<path d='M3 12h6l3 6 3-6h6' />
124+
</svg>
125+
</CardHeader>
126+
<CardContent>
127+
<div className='text-2xl font-bold'>42%</div>
128+
<p className='text-muted-foreground text-xs'>-3.2% vs last week</p>
129+
</CardContent>
130+
</Card>
131+
<Card>
132+
<CardHeader className='flex flex-row items-center justify-between space-y-0 pb-2'>
133+
<CardTitle className='text-sm font-medium'>Avg. Session</CardTitle>
134+
<svg
135+
xmlns='http://www.w3.org/2000/svg'
136+
viewBox='0 0 24 24'
137+
fill='none'
138+
stroke='currentColor'
139+
strokeLinecap='round'
140+
strokeLinejoin='round'
141+
strokeWidth='2'
142+
className='text-muted-foreground h-4 w-4'
143+
>
144+
<circle cx='12' cy='12' r='10' />
145+
<path d='M12 6v6l4 2' />
146+
</svg>
147+
</CardHeader>
148+
<CardContent>
149+
<div className='text-2xl font-bold'>3m 24s</div>
150+
<p className='text-muted-foreground text-xs'>+18s vs last week</p>
151+
</CardContent>
152+
</Card>
153+
</div>
154+
<div className='grid grid-cols-1 gap-4 lg:grid-cols-7'>
155+
<Card className='col-span-1 lg:col-span-4'>
156+
<CardHeader>
157+
<CardTitle>Referrers</CardTitle>
158+
<CardDescription>Top sources driving traffic</CardDescription>
159+
</CardHeader>
160+
<CardContent>
161+
<SimpleBarList
162+
items={[
163+
{ name: 'Direct', value: 512 },
164+
{ name: 'Product Hunt', value: 238 },
165+
{ name: 'Twitter', value: 174 },
166+
{ name: 'Blog', value: 104 },
167+
]}
168+
barClass='bg-primary'
169+
valueFormatter={(n) => `${n}`}
170+
/>
171+
</CardContent>
172+
</Card>
173+
<Card className='col-span-1 lg:col-span-3'>
174+
<CardHeader>
175+
<CardTitle>Devices</CardTitle>
176+
<CardDescription>How users access your app</CardDescription>
177+
</CardHeader>
178+
<CardContent>
179+
<SimpleBarList
180+
items={[
181+
{ name: 'Desktop', value: 74 },
182+
{ name: 'Mobile', value: 22 },
183+
{ name: 'Tablet', value: 4 },
184+
]}
185+
barClass='bg-muted-foreground'
186+
valueFormatter={(n) => `${n}%`}
187+
/>
188+
</CardContent>
189+
</Card>
190+
</div>
191+
</div>
192+
)
193+
}

src/features/dashboard/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { TopNav } from '@/components/layout/top-nav'
1414
import { ProfileDropdown } from '@/components/profile-dropdown'
1515
import { Search } from '@/components/search'
1616
import { ThemeSwitch } from '@/components/theme-switch'
17+
import { Analytics } from './components/analytics'
1718
import { Overview } from './components/overview'
1819
import { RecentSales } from './components/recent-sales'
1920

@@ -47,9 +48,7 @@ export function Dashboard() {
4748
<div className='w-full overflow-x-auto pb-2'>
4849
<TabsList>
4950
<TabsTrigger value='overview'>Overview</TabsTrigger>
50-
<TabsTrigger value='analytics' disabled>
51-
Analytics
52-
</TabsTrigger>
51+
<TabsTrigger value='analytics'>Analytics</TabsTrigger>
5352
<TabsTrigger value='reports' disabled>
5453
Reports
5554
</TabsTrigger>
@@ -184,6 +183,9 @@ export function Dashboard() {
184183
</Card>
185184
</div>
186185
</TabsContent>
186+
<TabsContent value='analytics' className='space-y-4'>
187+
<Analytics />
188+
</TabsContent>
187189
</Tabs>
188190
</Main>
189191
</>

0 commit comments

Comments
 (0)