1- import { Card , CardContent } from '@/components/ui/card' ;
21import { Button } from '@/components/ui/button' ;
3- import { LogIn , LogOut } from 'lucide-react' ;
2+ import { LogIn , LogOut , Pause } from 'lucide-react' ;
43import type { ClockEntry } from '@/store/useHistoryStore' ;
54
65interface WorkClockProps {
@@ -9,6 +8,7 @@ interface WorkClockProps {
98 todayTotal : { hours : number ; minutes : number ; seconds : number } ;
109 onClockIn : ( ) => void ;
1110 onClockOut : ( ) => void ;
11+ onBreak ?: ( ) => void ;
1212}
1313
1414export function WorkClock ( {
@@ -17,115 +17,112 @@ export function WorkClock({
1717 todayTotal,
1818 onClockIn,
1919 onClockOut,
20+ onBreak,
2021} : WorkClockProps ) {
21- return (
22- < Card className = "border-2 backdrop-blur-xl bg-gradient-to-br from-card/80 via-card/50 to-card/80 shadow-x overflow-hidden relative" >
23- < div className = "absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-primary/10" > </ div >
24-
25- < CardContent className = "relative z-10 pt-8 pb-8" >
26- < div className = "flex flex-col items-center justify-center space-y-6" >
27- < div className = "relative w-64 h-64 sm:w-72 sm:h-72" >
28- < svg className = "w-full h-full transform -rotate-90" >
29- < defs >
30- < linearGradient id = "clockGradient" x1 = "0%" y1 = "0%" x2 = "100%" y2 = "100%" >
31- < stop offset = "0%" stopColor = "#22c55e" stopOpacity = "0.8" />
32- < stop offset = "100%" stopColor = "#16a34a" stopOpacity = "1" />
33- </ linearGradient >
34- </ defs >
35-
36- { [ ...Array ( 60 ) ] . map ( ( _ , i ) => {
37- const angle = ( i * 6 * Math . PI ) / 180 ;
38- const isHourMark = i % 5 === 0 ;
39- const outerRadius = 136 ;
40- const innerRadius = isHourMark ? 126 : 130 ;
41- const x1 = 144 + outerRadius * Math . cos ( angle ) ;
42- const y1 = 144 + outerRadius * Math . sin ( angle ) ;
43- const x2 = 144 + innerRadius * Math . cos ( angle ) ;
44- const y2 = 144 + innerRadius * Math . sin ( angle ) ;
22+ const timeString = `${ String ( todayTotal . hours ) . padStart ( 2 , '0' ) } :${ String ( todayTotal . minutes ) . padStart ( 2 , '0' ) } :${ String ( todayTotal . seconds ) . padStart ( 2 , '0' ) } ` ;
4523
46- return (
47- < line
48- key = { i }
49- x1 = { x1 }
50- y1 = { y1 }
51- x2 = { x2 }
52- y2 = { y2 }
53- stroke = "currentColor"
54- strokeWidth = { isHourMark ? '2' : '1' }
55- className = "text-muted-foreground/30"
56- />
57- ) ;
58- } ) }
59-
60- { /* Background circle */ }
61- < circle
62- cx = "144"
63- cy = "144"
64- r = "110"
65- stroke = "currentColor"
66- strokeWidth = "8"
67- fill = "none"
68- className = "text-muted/10"
69- />
24+ return (
25+ < div className = "grid grid-cols-1 lg:grid-cols-3 gap-8" >
26+ { /* Main Time Display - Hero Section */ }
27+ < div className = "lg:col-span-2 relative overflow-hidden rounded-xl bg-surface-container-low border border-outline-variant/10 p-10 flex flex-col justify-between min-h-[360px]" >
28+ { /* Ambient Glow Background */ }
29+ < div className = "absolute -top-20 -right-20 w-80 h-80 bg-primary/10 blur-[100px] rounded-full" > </ div >
7030
71- { /* Progress circle */ }
72- { todayEntry && isToday && (
73- < circle
74- cx = "144"
75- cy = "144"
76- r = "110"
77- stroke = "url(#clockGradient)"
78- strokeWidth = "8"
79- fill = "none"
80- strokeDasharray = { `${ 2 * Math . PI * 110 } ` }
81- strokeDashoffset = { `${ 2 * Math . PI * 110 * ( 1 - ( todayTotal . hours % 24 ) / 24 ) } ` }
82- className = "transition-all duration-1000"
83- strokeLinecap = "round"
84- />
85- ) }
86- </ svg >
31+ < div className = "relative z-10" >
32+ { /* Status Indicator */ }
33+ < div className = "flex items-center gap-3 mb-8" >
34+ < div className = "w-3 h-3 bg-primary rounded-full animate-pulse shadow-[0_0_10px_rgba(92,253,128,0.8)]" > </ div >
35+ < span className = "text-primary font-label tracking-widest uppercase text-xs font-bold" >
36+ { todayEntry && isToday ? 'Currently Clocked In' : 'Ready to Clock In' }
37+ </ span >
38+ </ div >
8739
88- { /* Center content */ }
89- < div className = "absolute inset-0 flex items-center justify-center flex-col" >
90- < div className = "text-center space-y-1" >
91- < p className = "text-xs text-muted-foreground uppercase tracking-wider" >
92- { todayEntry && isToday ? 'Time at Work' : 'Left Time' }
93- </ p >
94- < div className = "text-xl sm:text-2xl tabular-nums text-green-500" >
95- { todayEntry && isToday
96- ? `${ String ( todayTotal . hours ) . padStart ( 2 , '0' ) } h ${ String ( todayTotal . minutes ) . padStart ( 2 , '0' ) } m ${ String ( todayTotal . seconds ) . padStart ( 2 , '0' ) } s`
97- : 'Online' }
98- </ div >
99- </ div >
100- </ div >
40+ { /* Large Time Display */ }
41+ < div className = "flex flex-col mb-8" >
42+ < span className = "text-on-surface-variant font-label uppercase tracking-[0.2em] mb-2 text-xs" >
43+ { todayEntry && isToday ? 'Elapsed Professional Time' : 'Total Time' }
44+ </ span >
45+ < h3 className = "font-headline text-[4rem] sm:text-[5rem] lg:text-[6rem] font-bold leading-none tracking-tighter text-on-background" >
46+ { todayEntry && isToday ? timeString . slice ( 0 , 5 ) : '00:00' }
47+ < span className = "text-primary/50 text-2xl sm:text-3xl ml-2 tracking-normal font-medium" >
48+ :{ todayEntry && isToday ? timeString . slice ( 6 ) : '00' }
49+ </ span >
50+ </ h3 >
10151 </ div >
52+ </ div >
10253
103- { /* Clock In/Out Buttons */ }
104- { isToday && (
105- < div className = "flex flex-col sm:flex-row gap-3 w-full max-w-md" >
54+ { /* Action Buttons */ }
55+ { isToday && (
56+ < div className = "relative z-10 flex flex-col sm:flex-row items-center gap-4" >
57+ { todayEntry ? (
58+ < >
59+ < Button
60+ onClick = { onClockOut }
61+ className = "px-10 py-5 bg-primary text-on-primary-container font-headline font-bold text-lg rounded-xl flex items-center gap-3 transition-transform duration-150 border border-primary/20"
62+ >
63+ < LogOut className = "w-6 h-6" />
64+ Clock Out
65+ </ Button >
66+ < Button
67+ onClick = { onBreak }
68+ variant = "outline"
69+ className = "px-8 py-5 border border-outline-variant/30 text-secondary font-headline font-bold text-lg rounded-xl flex items-center gap-3 hover:bg-secondary/5 transition-all"
70+ >
71+ < Pause className = "w-5 h-5" />
72+ Take a Break
73+ </ Button >
74+ </ >
75+ ) : (
10676 < Button
107- size = "lg"
10877 onClick = { onClockIn }
109- disabled = { ! ! todayEntry }
110- className = "flex-1 h-14 border-2 border-gray-500/20 text-base gap-3 shadow-green-500/15 hover:shadow-x hover:border-purple-500/20 transition-radius disabled:opacity-50"
78+ className = "px-10 py-5 bg-primary text-on-primary-container font-headline font-bold text-lg rounded-xl flex items-center gap-3 transition-transform duration-150 active:scale-95 shadow-lg shadow-primary/20"
11179 >
112- < LogIn className = "w-5 h-5 " />
80+ < LogIn className = "w-6 h-6 " />
11381 Clock In
11482 </ Button >
115- < Button
116- size = "lg"
117- onClick = { onClockOut }
118- disabled = { ! todayEntry }
119- variant = "secondary"
120- className = "flex-1 h-14 border-2 border-gray-500/20 text-base gap-3 shadow-red-500/15 hover:shadow-x hover:border-red-500/20 transition-radius disabled:opacity-40"
121- >
122- < LogOut className = "w-5 h-5" />
123- Clock Out
124- </ Button >
83+ ) }
84+ </ div >
85+ ) }
86+ </ div >
87+
88+ { /* Side Card: Daily Pulse - Corner Position */ }
89+ < div className = "lg:col-span-1 flex flex-col gap-4" >
90+ < div className = "bg-surface-container-highest/40 backdrop-blur-md rounded-xl p-8 border border-outline-variant/10 flex-1 flex flex-col justify-center" >
91+ < h4 className = "text-on-surface-variant font-label uppercase tracking-widest text-xs mb-6" > Daily Pulse</ h4 >
92+ < div className = "space-y-6" >
93+ < div className = "flex items-center justify-between" >
94+ < span className = "text-on-surface/80 text-sm" > Session Duration</ span >
95+ < span className = "font-headline font-medium text-lg text-secondary-design" >
96+ { todayEntry && isToday
97+ ? `${ String ( Math . floor ( ( new Date ( ) . getTime ( ) - new Date ( todayEntry . clockIn ) . getTime ( ) ) / ( 1000 * 60 ) ) ) . padStart ( 2 , '0' ) } min`
98+ : '--:-- --' }
99+ </ span >
100+ </ div >
101+ < div className = "flex items-center justify-between" >
102+ < span className = "text-on-surface/80 text-sm" > Status</ span >
103+ < span className = "font-headline font-medium text-lg text-tertiary" >
104+ { todayEntry && isToday && todayEntry . clockOut ? 'Clocked Out' : todayEntry ? 'Online' : 'Offline' }
105+ </ span >
125106 </ div >
126- ) }
107+ < div className = "pt-4 border-t border-outline-variant/10" >
108+ < div className = "flex items-center justify-between text-sm text-on-surface-variant mb-2" >
109+ < span > Daily Progress</ span >
110+ < span >
111+ { todayEntry && isToday ? `${ Math . min ( Math . floor ( ( todayTotal . hours / 8 ) * 100 ) , 100 ) } %` : '0%' }
112+ </ span >
113+ </ div >
114+ < div className = "h-1.5 w-full bg-surface-container-high rounded-full overflow-hidden" >
115+ < div
116+ className = "h-full bg-primary rounded-full transition-all duration-500"
117+ style = { {
118+ width : `${ todayEntry && isToday ? Math . min ( ( todayTotal . hours / 8 ) * 100 , 100 ) : 0 } %` ,
119+ } }
120+ > </ div >
121+ </ div >
122+ </ div >
123+ </ div >
127124 </ div >
128- </ CardContent >
129- </ Card >
125+ </ div >
126+ </ div >
130127 ) ;
131128}
0 commit comments