@@ -7,7 +7,7 @@ import clsx from "clsx";
77import { useAccount } from "wagmi" ;
88import { PlayIcon } from "@heroicons/react/24/solid" ;
99import { useFetchUserData } from "~~/hooks/useFetchUserData" ;
10- import { TOTAL_CHALLENGES } from "~~/utils/getChallenges" ;
10+ import { CHALLENGE_DESCRIPTIONS , CHALLENGE_NAMES , SEASONS , TOTAL_CHALLENGES } from "~~/utils/getChallenges" ;
1111
1212const invaderClass = "mx-auto w-10 h-10 md:w-12 md:h-12 cursor-crosshair" ;
1313const gridClass = "mx-auto my-6 md:my-8 grid grid-cols-4 gap-4" ;
@@ -18,7 +18,7 @@ export function HeroInvaders() {
1818 const [ rowThreeMove , setRowThreeMove ] = useState ( "translate-x-0" ) ;
1919
2020 const { address : connectedAddress } = useAccount ( ) ;
21- const { hasCompletedChallenge1 } = useFetchUserData ( { address : connectedAddress } ) ;
21+ const { hasCompletedChallenge1, challengesBySeasons } = useFetchUserData ( { address : connectedAddress } ) ;
2222
2323 useEffect ( ( ) => {
2424 const interval = setInterval ( ( ) => {
@@ -52,48 +52,117 @@ export function HeroInvaders() {
5252
5353 return (
5454 < >
55- < div >
56- < div className = { clsx ( gridClass , rowOneMove ) } >
57- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-1.svg" alt = "" />
58- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-2.svg" alt = "" />
59- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-3.svg" alt = "" />
60- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-4.svg" alt = "" />
55+ { /* Hero Section with Background Invaders */ }
56+ < div className = "relative min-h-[400px] flex flex-col items-center justify-center py-12 w-full max-w-3xl" >
57+ { /* Animated Invaders Background */ }
58+ < div className = "absolute inset-0 opacity-20 pointer-events-none overflow-hidden" >
59+ < div className = { clsx ( gridClass , rowOneMove ) } >
60+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-1.svg" alt = "" />
61+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-2.svg" alt = "" />
62+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-3.svg" alt = "" />
63+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-4.svg" alt = "" />
64+ </ div >
65+ < div className = { clsx ( gridClass , rowTwoMove ) } >
66+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-5.svg" alt = "" />
67+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-6.svg" alt = "" />
68+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-7.svg" alt = "" />
69+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-8.svg" alt = "" />
70+ </ div >
71+ < div className = { clsx ( gridClass , rowThreeMove ) } >
72+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-9.svg" alt = "" />
73+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-10.svg" alt = "" />
74+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-11.svg" alt = "" />
75+ < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-12.svg" alt = "" />
76+ </ div >
6177 </ div >
62- < div className = { clsx ( gridClass , rowTwoMove ) } >
63- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-5.svg" alt = "" />
64- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-6.svg" alt = "" />
65- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-7.svg" alt = "" />
66- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-8.svg" alt = "" />
67- </ div >
68- < div className = { clsx ( gridClass , rowThreeMove ) } >
69- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-9.svg" alt = "" />
70- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-10.svg" alt = "" />
71- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-11.svg" alt = "" />
72- < Image width = { 96 } height = { 96 } className = { invaderClass } src = "/season-1/invader-12.svg" alt = "" />
78+
79+ { /* Hero Content */ }
80+ < div className = "relative z-10" >
81+ < div className = "mx-auto px-12 max-w-60" >
82+ < Image width = { 112 } height = { 80 } className = "w-full h-auto" src = "/fortress-noflag.svg" alt = "" />
83+ </ div >
84+ < div className = "mt-8 text-center" >
85+ < h1 className = "md:text-2xl font-pressStart tracking-wide leading-relaxed" > Solidity Invaders</ h1 >
86+ < p className = "mt-6 text-lg md:text-xl/8" >
87+ ALERT! Invaders have taken { TOTAL_CHALLENGES } flags from the BuidlGuidl Fortress across multiple seasons.
88+ Your mission is to complete Ethereum coding challenges and reclaim all of the flags. Each season brings
89+ new invaders and tougher challenges!
90+ </ p >
91+ </ div >
92+ { /* Start/Continue Button */ }
93+ < div className = "text-center mt-8" >
94+ { ! hasCompletedChallenge1 && (
95+ < Link href = "/bangkok/challenges/1" className = "pl-8 pr-6 btn btn-primary btn-outline font-pressStart" >
96+ Start < PlayIcon className = "h-6 w-6" />
97+ </ Link >
98+ ) }
99+ { hasCompletedChallenge1 && (
100+ < Link
101+ href = { `/profile/${ connectedAddress } ` }
102+ className = "pl-8 pr-6 btn btn-primary btn-outline font-pressStart"
103+ >
104+ Continue < PlayIcon className = "h-6 w-6" />
105+ </ Link >
106+ ) }
107+ </ div >
73108 </ div >
74109 </ div >
75- < div className = "text-center my-12" >
76- { ! hasCompletedChallenge1 && (
77- < Link href = "/bangkok/challenges/1" className = "pl-8 pr-6 btn btn-primary btn-outline font-pressStart" >
78- Start < PlayIcon className = "h-6 w-6" />
79- </ Link >
80- ) }
81- { hasCompletedChallenge1 && (
82- < Link href = { `/profile/${ connectedAddress } ` } className = "pl-8 pr-6 btn btn-primary btn-outline font-pressStart" >
83- Continue < PlayIcon className = "h-6 w-6" />
84- </ Link >
85- ) }
86- </ div >
87- < div className = "mx-auto px-12 max-w-60" >
88- < Image width = { 112 } height = { 80 } className = "w-full h-auto" src = "/fortress-noflag.svg" alt = "" />
110+
111+ { /* Challenge Grid - 2 Columns (1 per season) */ }
112+ < div className = "mt-12 grid grid-cols-1 md:grid-cols-2 gap-8 w-full max-w-3xl" >
113+ { Object . entries ( challengesBySeasons )
114+ . sort ( ( [ a ] , [ b ] ) => Number ( a ) - Number ( b ) )
115+ . map ( ( [ season , challenges ] ) => (
116+ < div key = { season } >
117+ < p className = "m-0 mb-4 text-sm text-gray-400 font-pressStart" >
118+ { SEASONS [ Number ( season ) ] ?. name ?? `Season ${ season } ` }
119+ </ p >
120+ < div className = "space-y-2" >
121+ { challenges . map ( challenge => {
122+ const seasonNum = Number ( season ) ;
123+ const challengeId = Number ( challenge . challengeId ) ;
124+ const slug = SEASONS [ seasonNum ] ?. slug ?? "bangkok" ;
125+ const description = CHALLENGE_DESCRIPTIONS [ seasonNum ] ?. [ challenge . challengeId ] ?? "" ;
126+ return (
127+ < div key = { challenge . challengeId } className = "tooltip tooltip-left w-full" data-tip = { description } >
128+ < Link
129+ href = { `/${ slug } /challenges/${ challengeId } ` }
130+ className = { clsx (
131+ "flex items-center gap-3 p-2 rounded-md hover:bg-gray-900 transition-colors" ,
132+ challenge . solved && "bg-gray-900/50" ,
133+ ) }
134+ >
135+ < Image
136+ width = { 32 }
137+ height = { 32 }
138+ className = "w-8 h-8 shrink-0"
139+ src = { `/season-${ season } /invader-${ challengeId } .svg` }
140+ alt = ""
141+ />
142+ < span className = { clsx ( "text-sm" , challenge . solved && "text-primary" ) } >
143+ { CHALLENGE_NAMES [ seasonNum ] ?. [ challenge . challengeId ] ?? `Challenge ${ challengeId } ` }
144+ </ span >
145+ { challenge . solved && < span className = "text-primary text-xs ml-auto" > ✓</ span > }
146+ </ Link >
147+ </ div >
148+ ) ;
149+ } ) }
150+ </ div >
151+ </ div >
152+ ) ) }
89153 </ div >
90- < div className = "mt-12 text-center" >
91- < h1 className = "md:text-2xl font-pressStart tracking-wide leading-relaxed" > Solidity Invaders</ h1 >
92- < p className = "mx-auto mt-6 text-lg md:text-xl/8" >
93- ALERT! Invaders have taken { TOTAL_CHALLENGES } flags from the BuidlGuidl Fortress across multiple seasons. Your
94- mission is to complete Ethereum coding challenges and reclaim all of the flags. Each season brings new
95- invaders and tougher challenges!
96- </ p >
154+
155+ { /* Telegram CTA */ }
156+ < div className = "mt-16 text-center" >
157+ < p className = "text-gray-400 mb-4" > Got questions or need help?</ p >
158+ < a
159+ href = "https://t.me/+B9dXIETeXBswOWYy"
160+ target = "_blank"
161+ rel = "noopener noreferrer"
162+ className = "btn btn-outline btn-sm"
163+ >
164+ Join our Telegram
165+ </ a >
97166 </ div >
98167 </ >
99168 ) ;
0 commit comments