1
1
import { clsx } from "clsx"
2
- import { ScheduleSession } from "@/app/conf/2023/types"
2
+ import { ics } from "calendar-link"
3
+
4
+ import { SchedSpeaker , ScheduleSession } from "@/app/conf/2023/types"
3
5
import { Button } from "@/app/conf/_design-system/button"
4
6
import { Anchor } from "@/app/conf/_design-system/anchor"
5
7
import { CalendarIcon } from "@/app/conf/_design-system/pixelarticons/calendar-icon"
@@ -16,30 +18,27 @@ export interface LongSessionCardProps
16
18
extends React . HTMLAttributes < HTMLDivElement > {
17
19
session : ScheduleSession
18
20
eventColors ?: Record < string , string >
19
- year ?: string
20
21
}
21
22
22
23
export function LongSessionCard ( {
23
24
session,
24
- year = "2025" ,
25
25
className,
26
26
...props
27
27
} : LongSessionCardProps ) {
28
- const formattedDate = new Date ( session . event_start ) . toLocaleDateString (
29
- "en-US" ,
30
- {
31
- day : "numeric" ,
32
- month : "long" ,
33
- } ,
34
- )
35
- const formattedTime = new Date ( session . event_start ) . toLocaleTimeString (
36
- "en-US" ,
37
- {
38
- hour : "2-digit" ,
39
- minute : "2-digit" ,
40
- hour12 : false ,
41
- } ,
42
- )
28
+ const eventStart = new Date ( session . event_start )
29
+
30
+ const formattedDate = eventStart . toLocaleDateString ( "en-US" , {
31
+ day : "numeric" ,
32
+ month : "short" ,
33
+ } )
34
+
35
+ const year = eventStart . getFullYear ( )
36
+
37
+ const formattedTime = eventStart . toLocaleTimeString ( "en-US" , {
38
+ hour : "2-digit" ,
39
+ minute : "2-digit" ,
40
+ hour12 : false ,
41
+ } )
43
42
44
43
const eventTitle = getEventTitle (
45
44
session ,
@@ -68,14 +67,11 @@ export function LongSessionCard({
68
67
/>
69
68
70
69
< div className = "flex flex-col gap-6 p-4 lg:p-6" >
71
- < div className = "flex items-center justify-between gap-6" >
70
+ < div className = "flex items-start justify-between gap-6" >
72
71
< SessionTags session = { session } />
73
- { video && (
72
+ { year !== new Date ( ) . getFullYear ( ) && (
74
73
< div className = "flex items-center gap-2 border border-neu-400 bg-neu-100 px-2 py-1" >
75
- < span className = "typography-menu text-neu-900" >
76
- { /* todo: find year */ }
77
- 2024
78
- </ span >
74
+ < span className = "typography-menu text-neu-900" > { year } </ span >
79
75
</ div >
80
76
) }
81
77
</ div >
@@ -107,7 +103,8 @@ export function LongSessionCard({
107
103
</ span >
108
104
) }
109
105
{ video && (
110
- < div className = "flex items-center gap-0.5" >
106
+ // ideally, we'd display the duration of the video, not the projected duration of the talk
107
+ < div className = "flex shrink-0 items-center gap-0.5" >
111
108
< ClockIcon className = "size-3" />
112
109
< span className = "typography-body-xs text-neu-600" >
113
110
{ Math . round ( eventDurationMs / ( 1000 * 60 ) ) } min
@@ -118,8 +115,6 @@ export function LongSessionCard({
118
115
</ div >
119
116
</ div >
120
117
121
- { /* todo: past session no recording variant */ }
122
-
123
118
{ video ? (
124
119
< footer className = "p-4 pt-0 lg:px-6 lg:pb-6" >
125
120
< Button
@@ -133,7 +128,7 @@ export function LongSessionCard({
133
128
</ footer >
134
129
) : (
135
130
< footer className = "flex items-center border-t border-neu-200 text-neu-800 dark:border-neu-100" >
136
- < div className = "flex flex-1 items-center gap-6 border-r border-neu-200 p-4 dark:border-neu-100 lg:p-6" >
131
+ < div className = "flex flex-1 items-center gap-2 border-r border-neu-200 p-4 dark:border-neu-100 lg:p-6 xl:gap -6" >
137
132
< div className = "contents flex-col md:max-xl:flex" >
138
133
< div className = "flex items-center gap-0.5 whitespace-pre" >
139
134
< CalendarIcon className = "size-4 shrink-0 -translate-y-px text-sec-dark" />
@@ -149,12 +144,46 @@ export function LongSessionCard({
149
144
< span className = "typography-body-xs" > { session . venue } </ span >
150
145
</ div >
151
146
</ div >
152
- { /* <button className="relative z-[2] flex h-full flex-row items-center justify-center gap-0.5 p-4 text-neu-800 ring-inset ring-neu-400 hover:bg-sec-base/[.035] hover:ring-1 dark:ring-neu-100 lg:px-6">
153
- <PlusIcon className="size-4 shrink-0 text-sec-dark" />
154
- <span className="typography-body-xs">Add to calendar</span>
155
- </button> */ }
147
+ { year === new Date ( ) . getFullYear ( ) && (
148
+ < AddToCalendarLink
149
+ eventTitle = { eventTitle }
150
+ session = { session }
151
+ speakers = { speakers }
152
+ />
153
+ ) }
156
154
</ footer >
157
155
) }
158
156
</ div >
159
157
)
160
158
}
159
+
160
+ function AddToCalendarLink ( {
161
+ eventTitle,
162
+ session,
163
+ speakers,
164
+ } : {
165
+ eventTitle : string
166
+ session : ScheduleSession
167
+ speakers : SchedSpeaker [ ]
168
+ } ) {
169
+ return (
170
+ < a
171
+ className = "relative z-[2] flex h-full flex-row items-center justify-center gap-0.5 p-4 text-neu-800 ring-inset ring-neu-400 hover:bg-sec-base/[.035] hover:ring-1 dark:ring-neu-100 lg:px-6"
172
+ href = { ics ( {
173
+ title : eventTitle ,
174
+ start : session . event_start ,
175
+ end : session . event_end ,
176
+ description : session . description ,
177
+ location : session . venue ,
178
+ organizer : {
179
+ name : `GraphQLConf ${ new Date ( ) . getFullYear ( ) } ` ,
180
+
181
+ } ,
182
+ guests : speakers . map ( s => s . name ) ,
183
+ } ) }
184
+ >
185
+ < PlusIcon className = "size-4 shrink-0 text-sec-dark" />
186
+ < span className = "typography-body-xs" > Add to calendar</ span >
187
+ </ a >
188
+ )
189
+ }
0 commit comments