@@ -5,6 +5,37 @@ import { About } from "./about"
55import { Pricing } from "./pricing"
66import { Venue } from "./venue"
77import { 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+ }
839
940export const metadata : Metadata = {
1041 title : "GraphQLConf 2024 — Sept 10-12" ,
@@ -62,6 +93,69 @@ export default function Page() {
6293 </ div >
6394 </ div >
6495 </ 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+
65159 < Pricing />
66160 < About />
67161 < Venue />
0 commit comments