11import { observer } from 'mobx-react' ;
2- import { FC , useContext } from 'react' ;
2+ import { CSSProperties , FC , useContext , useEffect , useState } from 'react' ;
33import { Card , Col , Row } from 'react-bootstrap' ;
44import { renderToStaticMarkup } from 'react-dom/server' ;
55import ReactTyped from 'react-typed-component' ;
@@ -8,13 +8,82 @@ import { PageHead } from '../components/Layout/PageHead';
88import { I18nContext } from '../models/Translation' ;
99import styles from '../styles/Home.module.less' ;
1010
11+ // Temporarily disable localStorage persistence so the bar returns after refresh.
12+ // const HackathonTopBarStorageKey = 'labor-ai-hackathon-2026-top-bar-dismissed';
13+ const HackathonTopBarLink = '/hackathon/Labor-AI-hackathon-2026' ;
14+
1115const HomePage : FC = observer ( ( ) => {
1216 const { t } = useContext ( I18nContext ) ;
17+ const [ isHackathonTopBarVisible , setIsHackathonTopBarVisible ] = useState ( true ) ;
18+ const [ hackathonTopBarStyle , setHackathonTopBarStyle ] = useState < CSSProperties > ( ) ;
19+
20+ // useEffect(() => {
21+ // setIsHackathonTopBarVisible(localStorage.getItem(HackathonTopBarStorageKey) !== 'true');
22+ // }, []);
23+ useEffect ( ( ) => {
24+ const navbar = document . querySelector ( 'nav' ) ;
25+ const syncTopBarOffset = ( ) => {
26+ const navbarHeight = navbar ?. getBoundingClientRect ( ) . height || 56 ;
27+
28+ setHackathonTopBarStyle ( {
29+ '--hackathon-top-bar-gap' : `${ Math . max ( navbarHeight - 56 , 0 ) } px` ,
30+ '--hackathon-top-bar-offset' : `${ navbarHeight } px` ,
31+ } as CSSProperties ) ;
32+ } ;
33+ const observer =
34+ typeof ResizeObserver === 'undefined' || ! navbar
35+ ? undefined
36+ : new ResizeObserver ( syncTopBarOffset ) ;
37+
38+ syncTopBarOffset ( ) ;
39+ if ( navbar ) observer ?. observe ( navbar ) ;
40+ window . addEventListener ( 'resize' , syncTopBarOffset ) ;
41+
42+ return ( ) => {
43+ observer ?. disconnect ( ) ;
44+ window . removeEventListener ( 'resize' , syncTopBarOffset ) ;
45+ } ;
46+ } , [ ] ) ;
47+
48+ const closeHackathonTopBar = ( ) => {
49+ setIsHackathonTopBarVisible ( false ) ;
50+ // localStorage.setItem(HackathonTopBarStorageKey, 'true');
51+ } ;
1352
1453 return (
1554 < >
1655 < PageHead />
1756
57+ { isHackathonTopBarVisible && (
58+ < aside
59+ className = { styles . hackathonTopBar }
60+ aria-label = { t ( 'home_hackathon_top_bar_aria_label' ) }
61+ style = { hackathonTopBarStyle }
62+ >
63+ < div className = { styles . hackathonTopBarInner } >
64+ < a className = { styles . hackathonTopBarContent } href = { HackathonTopBarLink } >
65+ < span className = { styles . hackathonTopBarText } >
66+ < strong > { t ( 'home_hackathon_top_bar_title' ) } </ strong >
67+ < span > { t ( 'home_hackathon_top_bar_description' ) } </ span >
68+ </ span >
69+ < span className = { styles . hackathonTopBarEventName } > Labor AI Hackathon 2026</ span >
70+ < span className = { styles . hackathonTopBarAction } >
71+ { t ( 'home_hackathon_top_bar_action' ) }
72+ </ span >
73+ </ a >
74+ < button
75+ className = { styles . hackathonTopBarClose }
76+ type = "button"
77+ aria-label = { t ( 'home_hackathon_top_bar_close' ) }
78+ title = { t ( 'home_hackathon_top_bar_close' ) }
79+ onClick = { closeHackathonTopBar }
80+ >
81+ ×
82+ </ button >
83+ </ div >
84+ </ aside >
85+ ) }
86+
1887 < section
1988 className = { `flex-fill d-flex flex-column justify-content-center align-items-center bg-secondary bg-gradient text-dark bg-opacity-10 ${ styles . main } ` }
2089 >
0 commit comments