11'use client' ;
22
33import React from 'react' ;
4- import { Col , Empty , FloatButton , List , Row , Skeleton , Typography } from 'antd' ;
5- import { PlusOutlined } from '@ant-design/icons' ;
4+ import { Plus } from 'lucide-react' ;
5+ import { Button } from '@/components/ui/button' ;
6+ import { Card , CardHeader , CardTitle , CardContent } from '@/components/ui/card' ;
7+ import { Skeleton } from '@/components/ui/skeleton' ;
68import {
79 Area ,
810 Bar ,
@@ -29,11 +31,8 @@ import {
2931 formatTooltipLabel ,
3032 formatTooltipValue ,
3133} from './chart-utils' ;
32- import styles from './Dashboard.module.css' ;
33- import { Gutter } from 'antd/es/grid/row' ;
3434import { useStickyHeaders } from '@/hooks/useStickyHeaders' ;
35-
36- const { Title, Text } = Typography ;
35+ import { cn } from '@/lib/utils' ;
3736
3837interface DashboardProps {
3938 stats : DevlogStats | null ;
@@ -96,73 +95,78 @@ export function Dashboard({
9695 ] . filter ( ( item ) => item . value > 0 ) ;
9796 } , [ stats ] ) ;
9897
99- // Define gutter for chart rows
100- const chartRowGutter = [ 48 , 24 ] as [ Gutter , Gutter ] ;
101-
10298 // Setup sticky header detection
10399 useStickyHeaders ( {
104- selectorClass : styles . sectionHeader ,
105- stickyClass : styles . isSticky ,
100+ selectorClass : 'section-header' ,
101+ stickyClass : 'is-sticky' ,
106102 topOffset : 0 ,
107103 dependencies : [ ] ,
108104 } ) ;
109105
110106 return (
111107 < div className = "flex flex-col h-full w-full overflow-hidden" >
112- < div className = { ` ${ styles . dashboardContent } scrollable-content` } >
108+ < div className = "flex-1 overflow-y-auto p-6 space-y-8" >
113109 { /* Charts Section */ }
114- < div className = { styles . dashboardChartsSection } >
110+ < div className = "space-y-6" >
115111 { isLoadingTimeSeries ? (
116- < Row gutter = { chartRowGutter } className = { styles . chartRow } >
117- < Col xs = { 24 } lg = { 12 } >
118- < div className = { styles . chartCard } >
119- < Title level = { 4 } className = "mb-4" >
120- Development Activity (Last 30 Days)
121- </ Title >
122- < Skeleton active paragraph = { { rows : 8 } } />
123- </ div >
124- </ Col >
125- < Col xs = { 24 } lg = { 12 } >
126- < div className = { styles . chartCard } >
127- < Title level = { 4 } className = "mb-4" >
128- Current Status Distribution
129- </ Title >
130- < Skeleton active paragraph = { { rows : 8 } } />
131- </ div >
132- </ Col >
133- </ Row >
112+ < div className = "grid grid-cols-1 lg:grid-cols-2 gap-6" >
113+ < Card >
114+ < CardHeader >
115+ < CardTitle > Development Activity (Last 30 Days)</ CardTitle >
116+ </ CardHeader >
117+ < CardContent >
118+ < div className = "space-y-4" >
119+ { Array . from ( { length : 8 } ) . map ( ( _ , i ) => (
120+ < Skeleton key = { i } className = "h-4 w-full" />
121+ ) ) }
122+ </ div >
123+ </ CardContent >
124+ </ Card >
125+ < Card >
126+ < CardHeader >
127+ < CardTitle > Current Status Distribution</ CardTitle >
128+ </ CardHeader >
129+ < CardContent >
130+ < div className = "space-y-4" >
131+ { Array . from ( { length : 8 } ) . map ( ( _ , i ) => (
132+ < Skeleton key = { i } className = "h-4 w-full" />
133+ ) ) }
134+ </ div >
135+ </ CardContent >
136+ </ Card >
137+ </ div >
134138 ) : chartData . length === 0 ? (
135- < Row gutter = { chartRowGutter } >
136- < Col xs = { 24 } lg = { 12 } >
137- < div className = { styles . chartCard } >
138- < Title level = { 4 } className = "mb-4" >
139- Project Progress & Current Workload
140- </ Title >
141- < Empty
142- image = { Empty . PRESENTED_IMAGE_SIMPLE }
143- description = " No development activity data available yet"
144- / >
145- </ div >
146- </ Col >
147- < Col xs = { 24 } lg = { 12 } >
148- < div className = { styles . chartCard } >
149- < Title level = { 4 } className = "mb-4" >
150- Current Status Distribution
151- </ Title >
152- < Empty
153- image = { Empty . PRESENTED_IMAGE_SIMPLE }
154- description = " No status distribution data available yet"
155- / >
156- </ div >
157- </ Col >
158- </ Row >
139+ < div className = "grid grid-cols-1 lg:grid-cols-2 gap-6" >
140+ < Card >
141+ < CardHeader >
142+ < CardTitle > Project Progress & Current Workload </ CardTitle >
143+ </ CardHeader >
144+ < CardContent >
145+ < div className = "flex flex-col items-center justify-center py-12 text-center" >
146+ < div className = "text-muted-foreground mb-2" > 📊 </ div >
147+ < p className = "text-sm text-muted-foreground" > No development activity data available yet</ p >
148+ </ div >
149+ </ CardContent >
150+ </ Card >
151+ < Card >
152+ < CardHeader >
153+ < CardTitle > Current Status Distribution </ CardTitle >
154+ </ CardHeader >
155+ < CardContent >
156+ < div className = "flex flex-col items-center justify-center py-12 text-center" >
157+ < div className = "text-muted-foreground mb-2" > 📈 </ div >
158+ < p className = "text-sm text-muted-foreground" > No status distribution data available yet</ p >
159+ </ div >
160+ </ CardContent >
161+ </ Card >
162+ </ div >
159163 ) : (
160- < Row gutter = { chartRowGutter } >
161- < Col xs = { 24 } lg = { 12 } >
162- < div className = { styles . chartCard } >
163- < Title level = { 4 } className = "mb-4" >
164- Project Progress & Current Workload
165- </ Title >
164+ < div className = "grid grid-cols-1 lg:grid-cols-2 gap-6" >
165+ < Card >
166+ < CardHeader >
167+ < CardTitle > Project Progress & Current Workload </ CardTitle >
168+ </ CardHeader >
169+ < CardContent >
166170 < ResponsiveContainer width = "100%" height = { 300 } >
167171 < ComposedChart data = { chartData } >
168172 < CartesianGrid strokeDasharray = "3 3" />
@@ -222,13 +226,13 @@ export function Dashboard({
222226 />
223227 </ ComposedChart >
224228 </ ResponsiveContainer >
225- </ div >
226- </ Col >
227- < Col xs = { 24 } lg = { 12 } >
228- < div className = { styles . chartCard } >
229- < Title level = { 4 } className = "mb-4" >
230- Current Status Distribution
231- </ Title >
229+ </ CardContent >
230+ </ Card >
231+ < Card >
232+ < CardHeader >
233+ < CardTitle > Current Status Distribution </ CardTitle >
234+ </ CardHeader >
235+ < CardContent >
232236 < ResponsiveContainer width = "100%" height = { 300 } >
233237 < PieChart >
234238 < Pie
@@ -256,108 +260,99 @@ export function Dashboard({
256260 verticalAlign = "bottom"
257261 height = { 36 }
258262 formatter = { ( value : string ) => (
259- < span className = { styles . chartLegendText } > { value } </ span >
263+ < span className = "text-sm" > { value } </ span >
260264 ) }
261265 />
262266 </ PieChart >
263267 </ ResponsiveContainer >
264- </ div >
265- </ Col >
266- </ Row >
268+ </ CardContent >
269+ </ Card >
270+ </ div >
267271 ) }
268272 </ div >
269273
270- { /* Scrollable Content */ }
271- < div className = { `${ styles . recentDevlogs } flex-1 flex flex-col` } >
272- < div className = { styles . sectionHeader } >
273- < Title level = { 3 } className = { styles . recentDevlogsTitle } >
274- Recent Devlogs
275- </ Title >
276- </ div >
277- < div className = "flex-1 overflow-hidden thin-scrollbar-vertical" >
278- { isLoadingDevlogs ? (
279- < List
280- itemLayout = "horizontal"
281- dataSource = { Array . from ( { length : 10 } , ( _ , index ) => ( {
282- key : `skeleton-${ index } ` ,
283- } ) ) }
284- renderItem = { ( ) => (
285- < List . Item className = { styles . devlogListItem } >
286- < List . Item . Meta
287- className = { styles . devlogListItemMeta }
288- avatar = { < Skeleton . Avatar size = { 40 } active /> }
289- title = { < Skeleton paragraph = { { rows : 2 } } active /> }
290- />
291- </ List . Item >
292- ) }
293- />
294- ) : recentDevlogs . length === 0 ? (
295- < Empty
296- image = { Empty . PRESENTED_IMAGE_SIMPLE }
297- description = "No devlogs found"
298- className = { styles . emptyDevlogs }
299- />
300- ) : (
301- < List
302- itemLayout = "horizontal"
303- dataSource = { recentDevlogs }
304- renderItem = { ( devlog ) => (
305- < List . Item
306- className = { styles . devlogListItem }
307- onClick = { ( ) => onViewDevlog ( devlog ) }
308- actions = { [
309- < Text
310- type = "secondary"
311- key = "date"
312- className = { styles . devlogDate }
313- title = { formatTimeAgoWithTooltip ( devlog . updatedAt ) . fullDate }
314- >
315- { formatTimeAgoWithTooltip ( devlog . updatedAt ) . timeAgo }
316- </ Text > ,
317- ] }
318- >
319- < List . Item . Meta
320- className = { styles . devlogListItemMeta }
321- avatar = {
322- < Text strong className = { styles . devlogId } >
323- { devlog . id }
324- </ Text >
325- }
326- title = {
327- < div className = { styles . devlogTitleSection } >
328- < Text strong className = { styles . devlogTitleText } >
329- { devlog . title }
330- </ Text >
331- < div className = { styles . recentDevlogsMeta } >
332- < DevlogStatusTag status = { devlog . status } className = { styles . devlogTag } />
333- < DevlogPriorityTag
334- priority = { devlog . priority }
335- className = { styles . devlogTag }
336- />
337- < DevlogTypeTag type = { devlog . type } className = { styles . devlogTag } />
274+ { /* Recent Devlogs Section */ }
275+ < Card className = "flex-1 flex flex-col" >
276+ < CardHeader className = "section-header" >
277+ < CardTitle > Recent Devlogs</ CardTitle >
278+ </ CardHeader >
279+ < CardContent className = "flex-1 overflow-hidden" >
280+ < div className = "h-full overflow-y-auto" >
281+ { isLoadingDevlogs ? (
282+ < div className = "space-y-4" >
283+ { Array . from ( { length : 10 } ) . map ( ( _ , index ) => (
284+ < div key = { `skeleton-${ index } ` } className = "flex items-start space-x-4 p-4 border-b border-border" >
285+ < div className = "w-12 h-12 bg-muted rounded flex items-center justify-center" >
286+ < Skeleton className = "w-6 h-6" />
287+ </ div >
288+ < div className = "flex-1 space-y-2" >
289+ < Skeleton className = "h-4 w-3/4" />
290+ < Skeleton className = "h-3 w-1/2" />
291+ < div className = "flex space-x-2" >
292+ < Skeleton className = "h-5 w-16" />
293+ < Skeleton className = "h-5 w-16" />
294+ < Skeleton className = "h-5 w-16" />
295+ </ div >
296+ </ div >
297+ < Skeleton className = "h-3 w-16" />
298+ </ div >
299+ ) ) }
300+ </ div >
301+ ) : recentDevlogs . length === 0 ? (
302+ < div className = "flex flex-col items-center justify-center py-12 text-center" >
303+ < div className = "text-muted-foreground mb-2 text-2xl" > 📝</ div >
304+ < p className = "text-sm text-muted-foreground" > No devlogs found</ p >
305+ </ div >
306+ ) : (
307+ < div className = "space-y-0" >
308+ { recentDevlogs . map ( ( devlog ) => (
309+ < div
310+ key = { devlog . id }
311+ className = "flex items-start space-x-4 p-4 border-b border-border hover:bg-muted/50 cursor-pointer transition-colors"
312+ onClick = { ( ) => onViewDevlog ( devlog ) }
313+ >
314+ < div className = "w-12 h-12 bg-primary/10 rounded flex items-center justify-center text-primary font-bold text-sm" >
315+ { devlog . id }
316+ </ div >
317+ < div className = "flex-1 min-w-0" >
318+ < div className = "flex items-start justify-between" >
319+ < div className = "flex-1 min-w-0" >
320+ < h4 className = "font-semibold text-sm mb-1 truncate" > { devlog . title } </ h4 >
321+ < p className = "text-xs text-muted-foreground mb-2 line-clamp-2" >
322+ { devlog . description }
323+ </ p >
324+ < div className = "flex flex-wrap gap-1" >
325+ < DevlogStatusTag status = { devlog . status } />
326+ < DevlogPriorityTag priority = { devlog . priority } />
327+ < DevlogTypeTag type = { devlog . type } />
328+ </ div >
338329 </ div >
330+ < span
331+ className = "text-xs text-muted-foreground ml-4 flex-shrink-0"
332+ title = { formatTimeAgoWithTooltip ( devlog . updatedAt ) . fullDate }
333+ >
334+ { formatTimeAgoWithTooltip ( devlog . updatedAt ) . timeAgo }
335+ </ span >
339336 </ div >
340- }
341- description = {
342- < Text type = "secondary" ellipsis className = { styles . devlogDescription } >
343- { devlog . description }
344- </ Text >
345- }
346- />
347- </ List . Item >
348- ) }
349- />
350- ) }
351- </ div >
352- </ div >
337+ </ div >
338+ </ div >
339+ ) ) }
340+ </ div >
341+ ) }
342+ </ div >
343+ </ CardContent >
344+ </ Card >
353345 </ div >
354346
355- < FloatButton
356- icon = { < PlusOutlined /> }
357- tooltip = "Create new devlog"
347+ { /* Floating Action Button */ }
348+ < Button
349+ size = "lg"
350+ className = "fixed bottom-6 right-6 h-14 w-14 rounded-full shadow-lg"
358351 onClick = { ( ) => router . push ( '/devlogs/create' ) }
359- style = { { right : 24 , bottom : 24 } }
360- />
352+ title = "Create new devlog"
353+ >
354+ < Plus className = "h-6 w-6" />
355+ </ Button >
361356 </ div >
362357 ) ;
363358}
0 commit comments