@@ -9,24 +9,38 @@ import { AuthenticatedWrapper } from 'src/components/Common/AuthenticatedWrapper
99import { useBroadcastController } from 'src/hooks/useBroadcastController'
1010import { Broadcast } from 'src/types'
1111
12+ const fadeInUp = {
13+ initial : { opacity : 0 , y : 15 } ,
14+ animate : { opacity : 1 , y : 0 } ,
15+ transition : { duration : 0.3 , ease : 'easeOut' } ,
16+ }
17+
18+ const staggerContainer = {
19+ animate : {
20+ transition : {
21+ staggerChildren : 0.05 ,
22+ } ,
23+ } ,
24+ }
25+
1226const BroadcastsPage : NextPage = ( ) => {
1327 const router = useRouter ( )
14- const broadcastController = useBroadcastController ( )
28+ const { broadcastSections, broadcastState, loadBroadcasts } =
29+ useBroadcastController ( )
1530 const [ loading , setLoading ] = useState ( true )
1631
1732 useEffect ( ( ) => {
1833 const loadData = async ( ) => {
1934 try {
20- await broadcastController . loadBroadcasts ( )
35+ await loadBroadcasts ( )
2136 } catch ( error ) {
2237 console . error ( 'Error loading broadcasts:' , error )
2338 } finally {
2439 setLoading ( false )
2540 }
2641 }
27-
2842 loadData ( )
29- } , [ ] )
43+ } , [ loadBroadcasts ] )
3044
3145 const handleSelectBroadcast = ( broadcast : Broadcast ) => {
3246 const defaultRound =
@@ -47,32 +61,6 @@ const BroadcastsPage: NextPage = () => {
4761 } )
4862 }
4963
50- const containerVariants = {
51- hidden : { opacity : 0 } ,
52- visible : {
53- opacity : 1 ,
54- transition : {
55- duration : 0.3 ,
56- staggerChildren : 0.1 ,
57- } ,
58- } ,
59- }
60-
61- const itemVariants = {
62- hidden : {
63- opacity : 0 ,
64- y : 20 ,
65- } ,
66- visible : {
67- opacity : 1 ,
68- y : 0 ,
69- transition : {
70- duration : 0.4 ,
71- ease : [ 0.25 , 0.46 , 0.45 , 0.94 ] ,
72- } ,
73- } ,
74- }
75-
7664 if ( loading ) {
7765 return (
7866 < >
@@ -97,7 +85,7 @@ const BroadcastsPage: NextPage = () => {
9785 )
9886 }
9987
100- if ( broadcastController . broadcastState . error ) {
88+ if ( broadcastState . error ) {
10189 return (
10290 < >
10391 < Head >
@@ -106,16 +94,20 @@ const BroadcastsPage: NextPage = () => {
10694 < div className = "flex min-h-screen items-center justify-center bg-backdrop" >
10795 < div className = "rounded-lg border border-white/10 bg-background-1 p-6 text-center" >
10896 < h2 className = "mb-4 text-xl font-semibold text-red-400" >
109- Error Loading Broadcasts
97+ Failed to Load Broadcasts
11098 </ h2 >
11199 < p className = "mb-4 text-secondary" >
112- { broadcastController . broadcastState . error }
100+ Unable to connect to Lichess. Please check your internet
101+ connection and try again.
113102 </ p >
114103 < button
115- onClick = { ( ) => window . location . reload ( ) }
104+ onClick = { ( ) => {
105+ setLoading ( true )
106+ loadBroadcasts ( ) . finally ( ( ) => setLoading ( false ) )
107+ } }
116108 className = "rounded border border-human-4/30 bg-human-4 px-4 py-2 text-white transition-all duration-200 hover:border-human-4/50 hover:bg-human-4/80"
117109 >
118- Try Again
110+ Retry
119111 </ button >
120112 </ div >
121113 </ div >
@@ -141,13 +133,14 @@ const BroadcastsPage: NextPage = () => {
141133 'radial-gradient(ellipse 75% 60% at center top, rgba(239, 68, 68, 0.08) 0%, transparent 60%)' ,
142134 } }
143135 />
136+
144137 < motion . div
145138 className = "container relative mx-auto px-6 py-8"
146- variants = { containerVariants }
147- initial = "hidden "
148- animate = "visible"
139+ initial = "initial"
140+ animate = "animate "
141+ variants = { staggerContainer }
149142 >
150- < motion . div variants = { itemVariants } className = "mb-8 text-center" >
143+ < motion . div className = "mb-8 text-center" variants = { fadeInUp } >
151144 < h1 className = "mb-2 text-3xl font-bold text-white" >
152145 Live Broadcasts
153146 </ h1 >
@@ -156,10 +149,10 @@ const BroadcastsPage: NextPage = () => {
156149 </ p >
157150 </ motion . div >
158151
159- { broadcastController . broadcastSections . length === 0 ? (
152+ { broadcastSections . length === 0 ? (
160153 < motion . div
161- variants = { itemVariants }
162154 className = "flex flex-col items-center justify-center py-16 text-center"
155+ variants = { fadeInUp }
163156 >
164157 < span className = "material-symbols-outlined mb-4 !text-6xl text-white/60" >
165158 live_tv
@@ -171,19 +164,33 @@ const BroadcastsPage: NextPage = () => {
171164 There are currently no ongoing tournaments available.
172165 </ p >
173166 < button
174- onClick = { ( ) => broadcastController . loadBroadcasts ( ) }
167+ onClick = { ( ) => {
168+ setLoading ( true )
169+ loadBroadcasts ( ) . finally ( ( ) => setLoading ( false ) )
170+ } }
175171 className = "mt-4 rounded border border-human-4/30 bg-human-4 px-4 py-2 text-white transition-all duration-200 hover:border-human-4/50 hover:bg-human-4/80"
176172 >
177173 Refresh
178174 </ button >
179175 </ motion . div >
180176 ) : (
181- < div className = "space-y-6" >
182- { broadcastController . broadcastSections . map ( ( section ) => (
177+ < motion . div className = "space-y-6" variants = { staggerContainer } >
178+ { broadcastSections . map ( ( section , sectionIndex ) => (
183179 < motion . div
184180 key = { section . type }
185- variants = { itemVariants }
186181 className = "space-y-3"
182+ variants = { {
183+ initial : { opacity : 0 , y : 15 } ,
184+ animate : {
185+ opacity : 1 ,
186+ y : 0 ,
187+ transition : {
188+ duration : 0.25 ,
189+ ease : 'easeOut' ,
190+ delay : sectionIndex * 0.2 ,
191+ } ,
192+ } ,
193+ } }
187194 >
188195 < h2 className = "flex items-center gap-2 text-xl font-semibold text-white" >
189196 { section . title }
@@ -198,12 +205,22 @@ const BroadcastsPage: NextPage = () => {
198205 ) }
199206 </ h2 >
200207
201- < div
208+ < motion . div
202209 className = {
203210 section . type === 'official-active'
204211 ? 'flex flex-wrap gap-4'
205212 : 'grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'
206213 }
214+ initial = "initial"
215+ animate = "animate"
216+ variants = { {
217+ animate : {
218+ transition : {
219+ staggerChildren : 0.03 ,
220+ delayChildren : sectionIndex * 0.2 + 0.15 ,
221+ } ,
222+ } ,
223+ } }
207224 >
208225 { section . broadcasts . map ( ( broadcast ) => {
209226 const ongoingRounds = broadcast . rounds . filter (
@@ -218,12 +235,19 @@ const BroadcastsPage: NextPage = () => {
218235 return (
219236 < motion . div
220237 key = { broadcast . tour . id }
221- variants = { itemVariants }
222238 className = { `from-white/8 to-white/4 hover:from-white/12 hover:to-white/6 group relative flex flex-col overflow-hidden rounded-lg border border-white/10 bg-gradient-to-br backdrop-blur-md transition-all duration-300 hover:border-white/20 ${
223239 section . type === 'official-active'
224240 ? 'w-[280px]'
225241 : ''
226242 } `}
243+ variants = { {
244+ initial : { opacity : 0 , y : 15 } ,
245+ animate : {
246+ opacity : 1 ,
247+ y : 0 ,
248+ transition : { duration : 0.2 , ease : 'easeOut' } ,
249+ } ,
250+ } }
227251 >
228252 < div className = "flex flex-1 flex-col gap-3 p-4" >
229253 < div className = "flex items-start justify-between gap-3" >
@@ -267,7 +291,7 @@ const BroadcastsPage: NextPage = () => {
267291 < button
268292 onClick = { ( ) => handleSelectBroadcast ( broadcast ) }
269293 disabled = { ! hasOngoingRounds && ! isPast }
270- className = { `border-t py-2 text-sm font-medium transition-all duration-300 ${
294+ className = { `border-t py-2 text-sm font-medium tracking-wide transition-all duration-300 ${
271295 hasOngoingRounds
272296 ? 'border-red-500/30 bg-red-500/20 text-red-400 group-hover:bg-red-500/30'
273297 : isPast
@@ -284,18 +308,18 @@ const BroadcastsPage: NextPage = () => {
284308 </ motion . div >
285309 )
286310 } ) }
287- </ div >
311+ </ motion . div >
288312 </ motion . div >
289313 ) ) }
290- </ div >
314+ </ motion . div >
291315 ) }
292316
293317 < motion . div
294- variants = { itemVariants }
295318 className = "mt-8 text-center text-xs text-white/60"
319+ variants = { fadeInUp }
296320 >
297321 < p >
298- Broadcasts powered by { ' ' }
322+ Broadcasts streamed from { ' ' }
299323 < a
300324 href = "https://lichess.org"
301325 target = "_blank"
0 commit comments