@@ -5,6 +5,37 @@ import { About } from "./about"
5
5
import { Pricing } from "./pricing"
6
6
import { Venue } from "./venue"
7
7
import { Button } from "@/app/conf/_components/button"
8
+ import clsx from "clsx"
9
+ import { InfiniteMovingSpeakers } from "../_components/infinite-moving-speakers"
10
+ import { schedule , speakers } from "./_data"
11
+ import { SessionList } from "../_components/schedule/session-list"
12
+ import { filterCategories2024 } from "../_components/schedule/filter-categories"
13
+ import { eventsColors } from "./utils"
14
+
15
+ function shuffle < T extends any [ ] > ( array : T ) : T {
16
+ let currentIndex = array . length
17
+ let randomIndex : number
18
+
19
+ // While there remain elements to shuffle.
20
+ while ( currentIndex > 0 ) {
21
+ // Pick a remaining element.
22
+ randomIndex = Math . floor ( Math . random ( ) * currentIndex )
23
+ currentIndex --
24
+
25
+ // And swap it with the current element.
26
+ ; [ array [ currentIndex ] , array [ randomIndex ] ] = [
27
+ array [ randomIndex ] ,
28
+ array [ currentIndex ] ,
29
+ ]
30
+ }
31
+
32
+ return array
33
+ }
34
+
35
+ const classes = {
36
+ heading : "text-[45px] text-center font-bold mb-20" ,
37
+ container : "conf-block container text-white" ,
38
+ }
8
39
9
40
export const metadata : Metadata = {
10
41
title : "GraphQLConf 2024 — Sept 10-12" ,
@@ -62,6 +93,69 @@ export default function Page() {
62
93
</ div >
63
94
</ div >
64
95
</ div >
96
+
97
+ < div className = { clsx ( classes . container , "flex flex-col items-center" ) } >
98
+ < h3 className = "text-[45px] text-center font-bold mb-20" >
99
+ Our Special Speakers
100
+ </ h3 >
101
+
102
+ < InfiniteMovingSpeakers pauseOnHover = { true } >
103
+ { speakers
104
+ . filter ( e => e . avatar )
105
+ . map ( speaker => (
106
+ < div
107
+ key = { speaker . username }
108
+ className = "group border-[1.5px] border-[rgba(255,255,255,0.4)] cursor-pointer hover:-translate-y-3 transition-transform duration-300 relative rounded-full overflow-hidden md:size-[210px]"
109
+ >
110
+ < a href = { `/conf/2024/speakers/${ speaker . username } ` } >
111
+ < img
112
+ className = "size-[120px] md:size-[210px] rounded-full"
113
+ src = { speaker . avatar }
114
+ alt = { speaker . name }
115
+ />
116
+ </ a >
117
+ < div className = "pointer-events-none bg-[rgba(0,0,0,0.6)] h-[40px] text-sm md:text-base md:h-[55px] w-[120px] md:w-[210px] absolute left-0 bottom-0 opacity-1 md:opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex justify-center" >
118
+ < span className = "mt-2.5 md:mt-3.5 font-medium" >
119
+ { speaker . name . split ( " " ) [ 0 ] }
120
+ </ span >
121
+ </ div >
122
+ </ div >
123
+ ) ) }
124
+ </ InfiniteMovingSpeakers >
125
+
126
+ < div className = "mt-14 flex gap-4" >
127
+ < Button href = "/conf/2024/speakers" > See all Speakers</ Button >
128
+ </ div >
129
+
130
+ < div className = "mt-16" >
131
+ < h3 className = "text-[45px] text-center font-bold mb-16" >
132
+ The Schedule
133
+ </ h3 >
134
+
135
+ < SessionList
136
+ minimalVersion
137
+ year = "2024"
138
+ filterCategories = { filterCategories2024 }
139
+ eventsColors = { eventsColors }
140
+ showFilter = { false }
141
+ // @ts -expect-error -- fixme
142
+ scheduleData = { shuffle ( schedule . filter ( e => e . speakers ) )
143
+ . slice ( 0 , 3 )
144
+ . map ( schedule => ( {
145
+ ...schedule ,
146
+ speakers :
147
+ schedule ?. speakers ?. map ( speaker =>
148
+ speakers . find ( s => s . username === speaker . username ) ,
149
+ ) || [ ] ,
150
+ } ) ) }
151
+ />
152
+ </ div >
153
+
154
+ < div className = "mt-14 flex gap-4" >
155
+ < Button href = "/conf/2024/speakers" > View full schedule</ Button >
156
+ </ div >
157
+ </ div >
158
+
65
159
< Pricing />
66
160
< About />
67
161
< Venue />
0 commit comments