@@ -2,8 +2,8 @@ import { motion } from "motion/react";
22import { MapPin } from "lucide-react" ;
33import type { ProfessionalExperience , PositionOfResponsibility } from "@/types" ;
44import { slideInLeft , slideInRight } from "@utils/animations" ;
5- import { splitDateRange } from "@utils/dateRange" ;
6- import { MONO_FONT } from "@/constants/theme" ;
5+ import { splitDateRange , isPresent } from "@utils/dateRange" ;
6+ import { MONO_FONT , GREEN } from "@/constants/theme" ;
77import TimelineCardContent from "./TimelineCardContent" ;
88
99interface TimelineCardDesktopProps {
@@ -18,114 +18,153 @@ const TimelineCardDesktop = ({
1818 index,
1919 accentColor,
2020 onClick,
21- } : TimelineCardDesktopProps ) => (
22- < motion . div
23- layout = "position"
24- style = { {
25- display : "grid" ,
26- gridTemplateColumns : "160px 40px 1fr" ,
27- gap : 0 ,
28- } }
29- variants = { index % 2 === 0 ? slideInLeft : slideInRight }
30- custom = { index }
31- transition = { { layout : { duration : 0.4 , ease : [ 0.4 , 0 , 0.2 , 1 ] } } }
32- >
33- { /* Left: Date + Location */ }
34- < div style = { { paddingTop : 4 , textAlign : "right" , paddingRight : 20 } } >
35- < span
36- style = { {
37- fontFamily : MONO_FONT ,
38- fontSize : 12 ,
39- fontWeight : 600 ,
40- color : accentColor ,
41- } }
42- >
43- { splitDateRange ( item . date ) . start }
44- </ span >
45- < span
46- style = { {
47- display : "block" ,
48- fontFamily : MONO_FONT ,
49- fontSize : 11 ,
50- color : "#6e6e90" ,
51- marginTop : 2 ,
52- } }
53- >
54- { item . date . split ( " - " ) . at ( 1 ) ?? "" }
55- </ span >
56- { item . location && (
57- < p
21+ } : TimelineCardDesktopProps ) => {
22+ const { start, end } = splitDateRange ( item . date ) ;
23+ const active = isPresent ( item . date ) ;
24+
25+ return (
26+ < motion . div
27+ layout = "position"
28+ style = { {
29+ display : "grid" ,
30+ gridTemplateColumns : "160px 40px 1fr" ,
31+ gap : 0 ,
32+ } }
33+ variants = { index % 2 === 0 ? slideInLeft : slideInRight }
34+ custom = { index }
35+ transition = { { layout : { duration : 0.4 , ease : [ 0.4 , 0 , 0.2 , 1 ] } } }
36+ >
37+ { /* Left: Date + Location */ }
38+ < div style = { { paddingTop : 4 , textAlign : "right" , paddingRight : 20 } } >
39+ < span
5840 style = { {
59- color : "#6e6e90" ,
41+ fontFamily : MONO_FONT ,
6042 fontSize : 12 ,
61- display : "flex" ,
62- alignItems : "center" ,
63- justifyContent : "flex-end" ,
64- gap : 4 ,
65- marginTop : 12 ,
43+ fontWeight : 600 ,
44+ color : accentColor ,
6645 } }
6746 >
68- < MapPin size = { 11 } style = { { flexShrink : 0 } } />
69- { item . location }
70- </ p >
71- ) }
72- </ div >
47+ { start }
48+ </ span >
49+ { active ? (
50+ < span
51+ style = { {
52+ display : "inline-flex" ,
53+ alignItems : "center" ,
54+ justifyContent : "flex-end" ,
55+ gap : 5 ,
56+ width : "100%" ,
57+ marginTop : 2 ,
58+ fontFamily : MONO_FONT ,
59+ fontSize : 11 ,
60+ fontWeight : 600 ,
61+ color : GREEN ,
62+ letterSpacing : "0.02em" ,
63+ } }
64+ aria-label = "Currently active role"
65+ >
66+ < span
67+ className = "animate-glow-pulse"
68+ aria-hidden = "true"
69+ style = { {
70+ width : 6 ,
71+ height : 6 ,
72+ borderRadius : "50%" ,
73+ backgroundColor : GREEN ,
74+ boxShadow : `0 0 6px ${ GREEN } 99` ,
75+ flexShrink : 0 ,
76+ } }
77+ />
78+ Present
79+ </ span >
80+ ) : (
81+ < span
82+ style = { {
83+ display : "block" ,
84+ fontFamily : MONO_FONT ,
85+ fontSize : 11 ,
86+ color : "#6e6e90" ,
87+ marginTop : 2 ,
88+ } }
89+ >
90+ { end ?? "" }
91+ </ span >
92+ ) }
93+ { item . location && (
94+ < p
95+ style = { {
96+ color : "#6e6e90" ,
97+ fontSize : 12 ,
98+ display : "flex" ,
99+ alignItems : "center" ,
100+ justifyContent : "flex-end" ,
101+ gap : 4 ,
102+ marginTop : 12 ,
103+ } }
104+ >
105+ < MapPin size = { 11 } style = { { flexShrink : 0 } } />
106+ { item . location }
107+ </ p >
108+ ) }
109+ </ div >
73110
74- { /* Center: Timeline track */ }
75- < div
76- style = { {
77- display : "flex" ,
78- flexDirection : "column" ,
79- alignItems : "center" ,
80- position : "relative" ,
81- } }
82- >
111+ { /* Center: Timeline track */ }
83112 < div
84113 style = { {
85- width : 16 ,
86- height : 16 ,
87- borderRadius : "50%" ,
88- border : `2px solid ${ accentColor } ` ,
89- backgroundColor : "rgba(6, 6, 16, 0.6)" ,
90- marginTop : 4 ,
114+ display : "flex" ,
115+ flexDirection : "column" ,
116+ alignItems : "center" ,
91117 position : "relative" ,
92- zIndex : 2 ,
93- flexShrink : 0 ,
94118 } }
95119 >
96120 < div
97- className = "animate-glow-pulse"
98121 style = { {
99- position : "absolute" ,
100- inset : 3 ,
122+ width : 16 ,
123+ height : 16 ,
101124 borderRadius : "50%" ,
102- backgroundColor : accentColor ,
125+ border : `2px solid ${ active ? GREEN : accentColor } ` ,
126+ backgroundColor : "rgba(6, 6, 16, 0.6)" ,
127+ marginTop : 4 ,
128+ position : "relative" ,
129+ zIndex : 2 ,
130+ flexShrink : 0 ,
131+ boxShadow : active ? `0 0 0 4px ${ GREEN } 22` : undefined ,
132+ } }
133+ >
134+ < div
135+ className = "animate-glow-pulse"
136+ style = { {
137+ position : "absolute" ,
138+ inset : 3 ,
139+ borderRadius : "50%" ,
140+ backgroundColor : active ? GREEN : accentColor ,
141+ } }
142+ />
143+ </ div >
144+ < div
145+ style = { {
146+ width : 2 ,
147+ flex : 1 ,
148+ background : `linear-gradient(to bottom, ${ accentColor } 40, ${ accentColor } 10)` ,
149+ borderRadius : 4 ,
103150 } }
104151 />
105152 </ div >
106- < div
107- style = { {
108- width : 2 ,
109- flex : 1 ,
110- background : `linear-gradient(to bottom, ${ accentColor } 40, ${ accentColor } 10)` ,
111- borderRadius : 4 ,
112- } }
113- />
114- </ div >
115153
116- { /* Right: Content card */ }
117- < div
118- className = "glass-card"
119- style = { { padding : "24px 24px" , marginBottom : 20 } }
120- >
121- < TimelineCardContent
122- item = { item }
123- accentColor = { accentColor }
124- isMobile = { false }
125- onClick = { onClick }
126- />
127- </ div >
128- </ motion . div >
129- ) ;
154+ { /* Right: Content card */ }
155+ < div
156+ className = "glass-card"
157+ style = { { padding : "24px 24px" , marginBottom : 20 } }
158+ >
159+ < TimelineCardContent
160+ item = { item }
161+ accentColor = { accentColor }
162+ isMobile = { false }
163+ onClick = { onClick }
164+ />
165+ </ div >
166+ </ motion . div >
167+ ) ;
168+ } ;
130169
131170export default TimelineCardDesktop ;
0 commit comments