@@ -8,11 +8,12 @@ import {
88 BellSlash ,
99 FunnelIcon ,
1010 XCircle ,
11+ CalendarBlank ,
1112} from '@phosphor-icons/react' ;
1213import useSeo from '../hooks/useSeo' ;
1314import { useAchievements } from '../context/AchievementContext' ;
1415import { ACHIEVEMENTS } from '../config/achievements' ;
15- import colors from '../config/colors' ;
16+ // import colors from '../config/colors'; // Unused in this snippet, but kept if you need it elsewhere
1617
1718const AchievementsPage = ( ) => {
1819 useSeo ( {
@@ -33,7 +34,7 @@ const AchievementsPage = () => {
3334
3435 // Extract unique categories for filter pills
3536 const uniqueCategories = [
36- 'All' , // Add 'All' category to display all achievements
37+ 'All' ,
3738 ...new Set ( ACHIEVEMENTS . map ( ( ach ) => ach . category ) ) ,
3839 ] . sort ( ) ;
3940
@@ -62,31 +63,35 @@ const AchievementsPage = () => {
6263
6364 const filteredAchievements = ACHIEVEMENTS . filter ( ( achievement ) => {
6465 const matchesCategory =
65- selectedCategories . length === 0 || // If no categories selected, show all
66+ selectedCategories . length === 0 ||
6667 selectedCategories . includes ( achievement . category ) ;
6768 return matchesCategory ;
6869 } ) ;
6970
7071 return (
71- < div className = "py-16 sm:py-24" >
72+ < div className = "py-16 sm:py-24 bg-gray-950 " >
7273 < div className = "mx-auto max-w-7xl px-6 lg:px-8" >
74+ { /* Header Section - Kept mostly the same for consistency */ }
7375 < Link
7476 to = "/"
75- className = "group text-primary-400 hover:underline flex items-center justify-center gap-2 text-lg mb-4"
77+ className = "group text-primary-400 hover:underline flex items-center justify-center gap-2 text-lg mb-4 transition-all "
7678 >
7779 < ArrowLeftIcon className = "text-xl transition-transform group-hover:-translate-x-1" /> { ' ' }
7880 Back to Home
7981 </ Link >
80- < div className = "mx-auto max-w-2xl text-center" >
81- < h1 className = "text-4xl font-semibold tracking-tight text-white sm:text-6xl flex items-center justify-center gap-4" >
82- < Trophy size = { 48 } weight = "duotone" className = "text-yellow-400" />
82+ < div className = "mx-auto max-w-2xl text-center relative z-10" >
83+ < h1 className = "text-4xl font-bold tracking-tight text-white sm:text-6xl flex flex-col sm:flex-row items-center justify-center gap-4" >
84+ < div className = "relative" >
85+ < div className = "absolute inset-0 bg-yellow-500 blur-2xl opacity-20 rounded-full" > </ div >
86+ < Trophy size = { 56 } weight = "duotone" className = "text-yellow-400 relative z-10 drop-shadow-[0_0_10px_rgba(234,179,8,0.5)]" />
87+ </ div >
8388 Achievements
8489 </ h1 >
8590 < p className = "mt-6 text-lg leading-8 text-gray-300" >
8691 Discover hidden features and explore the depths of Fezcodex.
8792 </ p >
8893
89- { /* Filter Pills */ }
94+ { /* Filters & Progress section (Kept identical to your code) */ }
9095 < div className = "flex flex-wrap items-center justify-center gap-2 mt-8 max-w-2xl mx-auto" >
9196 < div className = "flex items-center gap-2 mr-2 text-gray-500 font-mono text-sm" >
9297 < FunnelIcon size = { 16 } />
@@ -96,138 +101,126 @@ const AchievementsPage = () => {
96101 const isSelected = selectedCategories . includes ( category ) || ( category === 'All' && selectedCategories . length === 0 ) ;
97102 const colorClass = isSelected ? 'bg-yellow-500/20 text-yellow-300 border-yellow-500/50' : 'bg-gray-900/50 text-gray-400 border-gray-700 hover:border-gray-500 hover:text-gray-200' ;
98103 return (
99- < button
100- key = { category }
101- onClick = { ( ) => toggleCategory ( category ) }
102- className = { `px-3 py-1 rounded-full text-sm font-medium border transition-colors duration-200 ${ colorClass } ` }
103- >
104+ < button key = { category } onClick = { ( ) => toggleCategory ( category ) } className = { `px-3 py-1 rounded-full text-sm font-medium border transition-colors duration-200 ${ colorClass } ` } >
104105 { category }
105106 </ button >
106107 ) ;
107108 } ) }
108-
109109 { selectedCategories . length > 0 && (
110- < button
111- onClick = { clearFilters }
112- className = "ml-2 text-sm text-red-400 hover:text-red-300 flex items-center gap-1 transition-colors"
113- >
110+ < button onClick = { clearFilters } className = "ml-2 text-sm text-red-400 hover:text-red-300 flex items-center gap-1 transition-colors" >
114111 < XCircle size = { 20 } /> Clear
115112 </ button >
116113 ) }
117114 </ div >
118115
119- { /* Progress Bar */ }
120116 < div className = "mt-8 max-w-md mx-auto" >
121117 < div className = "flex justify-between text-sm text-gray-400 mb-2" >
122118 < span > Progress</ span >
123- < span >
124- { unlockedCount } / { totalCount }
125- </ span >
119+ < span > { unlockedCount } / { totalCount } </ span >
126120 </ div >
127- < div className = "w-full bg-gray-700 rounded-full h-4 overflow-hidden border border-gray-600" >
128- < div
129- className = "bg-gradient-to-r from-yellow-600 to-yellow-400 h-4 rounded-full transition-all duration-1000 ease-out"
130- style = { { width : `${ progressPercentage } %` } }
131- > </ div >
121+ < div className = "w-full bg-gray-800 rounded-full h-4 overflow-hidden border border-gray-700 shadow-inner" >
122+ < div className = "bg-gradient-to-r from-yellow-600 to-yellow-300 h-4 rounded-full transition-all duration-1000 ease-out shadow-[0_0_10px_rgba(234,179,8,0.5)]" style = { { width : `${ progressPercentage } %` } } > </ div >
132123 </ div >
133- { /* Achievement Toast Status */ }
134- < div
135- className = { `mt-8 flex items-center gap-4 p-4 rounded-xl border backdrop-blur-sm transition-all duration-300 shadow-lg ${
136- showAchievementToast
137- ? 'bg-emerald-900/20 border-emerald-500/30 text-emerald-100 shadow-emerald-900/10'
138- : 'bg-rose-900/20 border-rose-500/30 text-rose-100 shadow-rose-900/10'
139- } `}
140- >
141- < div
142- className = { `p-2.5 rounded-full shrink-0 ${
143- showAchievementToast
144- ? 'bg-emerald-500/20 text-emerald-400'
145- : 'bg-rose-500/20 text-rose-400'
146- } `}
147- >
148- { showAchievementToast ? (
149- < Info size = { 24 } weight = "duotone" />
150- ) : (
151- < BellSlash size = { 24 } weight = "duotone" />
152- ) }
124+ { /* Achievement Toast Status (Kept identical) */ }
125+ < div className = { `mt-8 flex items-center gap-4 p-4 rounded-xl border backdrop-blur-sm transition-all duration-300 shadow-lg ${ showAchievementToast ? 'bg-emerald-900/20 border-emerald-500/30 text-emerald-100 shadow-emerald-900/10' : 'bg-rose-900/20 border-rose-500/30 text-rose-100 shadow-rose-900/10' } ` } >
126+ < div className = { `p-2.5 rounded-full shrink-0 ${ showAchievementToast ? 'bg-emerald-500/20 text-emerald-400' : 'bg-rose-500/20 text-rose-400' } ` } >
127+ { showAchievementToast ? ( < Info size = { 24 } weight = "duotone" /> ) : ( < BellSlash size = { 24 } weight = "duotone" /> ) }
153128 </ div >
154129 < div className = "flex-1 text-left" >
155- < p className = "font-medium text-sm tracking-wide" >
156- ACHIEVEMENT NOTIFICATIONS ARE{ ' ' }
157- < span className = "font-bold" >
158- { showAchievementToast ? 'ACTIVE' : 'MUTED' }
159- </ span >
160- </ p >
161- < p
162- className = { `text-xs mt-1 ${
163- showAchievementToast
164- ? 'text-emerald-400/80'
165- : 'text-rose-400/80'
166- } `}
167- >
168- You can toggle these popups in the{ ' ' }
169- < Link
170- to = "/settings"
171- className = "underline underline-offset-2 hover:text-white transition-colors"
172- >
173- Settings
174- </ Link >
175- .
176- </ p >
130+ < p className = "font-medium text-sm tracking-wide" > ACHIEVEMENT NOTIFICATIONS ARE < span className = "font-bold" > { showAchievementToast ? 'ACTIVE' : 'MUTED' } </ span > </ p >
131+ < p className = { `text-xs mt-1 ${ showAchievementToast ? 'text-emerald-400/80' : 'text-rose-400/80' } ` } > You can toggle these popups in the < Link to = "/settings" className = "underline underline-offset-2 hover:text-white transition-colors" > Settings</ Link > .</ p >
177132 </ div >
178133 </ div >
179134 </ div >
180135 </ div >
181136
182- < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-16" >
137+ { /* NEW CARDS GRID */ }
138+ < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 mt-16" >
183139 { filteredAchievements . map ( ( achievement ) => {
184140 const isUnlocked = unlockedAchievements [ achievement . id ] ?. unlocked ;
141+ const unlockedDate = isUnlocked ? new Date ( unlockedAchievements [ achievement . id ] . unlockedAt ) : null ;
185142
186143 return (
187144 < div
188145 key = { achievement . id }
189- className = { `relative overflow-hidden rounded-xl border p-6 transition-all duration-300 ${
146+ // Container defining shape, height, and base hover movement
147+ className = { `relative group flex flex-col h-full overflow-hidden rounded-2xl border transition-all duration-500 ease-out ${
190148 isUnlocked
191- ? 'bg -yellow-800/30 border-yellow-600/30 shadow-[0_0_15px_rgba(252,211,77 ,0.3 )]'
192- : 'bg -gray-900/40 border -gray-800 opacity-70 grayscale '
149+ ? 'border -yellow-600/40 hover:-translate-y-2 hover: shadow-[0_10px_30px_-10px_rgba(234,179,8 ,0.5 )]'
150+ : 'border -gray-800 bg -gray-900/50 grayscale opacity-70 hover:opacity-100 hover:border-gray-700 '
193151 } `}
194152 >
195- < div className = "flex items-start justify-between" >
196- < div
197- className = { `p-3 rounded-lg ${ isUnlocked ? 'bg-yellow-500/20 text-yellow-400' : 'bg-gray-800 text-gray- 500' } ` }
198- >
199- { isUnlocked ? (
200- achievement . icon
201- ) : (
202- < Lock size = { 32 } weight = "fill" />
203- ) }
204- </ div >
153+ { /* Dynamic Background Layer */ }
154+ < div
155+ className = { `absolute inset-0 z-0 transition-all duration- 500 ${
156+ isUnlocked
157+ ? 'bg-gradient-to-br from-yellow-900/30 via-gray-950 to-black opacity-100 group-hover:opacity-100'
158+ // Subtle radial glow that follows mouse could go here, but keeping it simple for now
159+ : 'bg-gray-950'
160+ } ` }
161+ >
162+ { /* Subtle decorative pattern for unlocked cards */ }
205163 { isUnlocked && (
206- < span className = "text-xs font-mono text-yellow-400 bg-yellow-900/30 px-2 py-1 rounded border border-yellow-800" >
207- UNLOCKED
208- </ span >
164+ < div className = "absolute inset-0 opacity-10 bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-yellow-500 via-transparent to-transparent size-full" > </ div >
209165 ) }
210166 </ div >
211167
212- < div className = "mt-4" >
168+ { /* Card Content - Flex Column for vertical centering */ }
169+ < div className = "relative z-10 flex flex-col items-center text-center p-6 flex-grow font-sans" >
170+
171+ { /* Category Banner */ }
172+ < span className = { `mb-6 px-3 py-1 text-xs font-bold tracking-wider uppercase rounded-full border ${
173+ isUnlocked ? 'bg-yellow-500/10 text-yellow-400 border-yellow-500/30' : 'bg-gray-800 text-gray-400 border-gray-700'
174+ } `} >
175+ { achievement . category }
176+ </ span >
177+
178+ { /* Main Icon Container */ }
179+ < div className = "relative mb-6 group-hover:scale-105 transition-transform duration-300" >
180+ { /* Glowing Ring background for unlocked */ }
181+ { isUnlocked && < div className = "absolute inset-0 bg-yellow-500 blur-xl opacity-30 rounded-full animate-pulse-slow" > </ div > }
182+
183+ < div
184+ className = { `relative h-24 w-24 rounded-full flex items-center justify-center border-[3px] shadow-2xl ${
185+ isUnlocked
186+ ? 'bg-gradient-to-b from-yellow-800 to-yellow-950 border-yellow-400 text-yellow-300 shadow-yellow-900/50 ring-4 ring-yellow-500/20'
187+ : 'bg-gray-800 border-gray-700 text-gray-500 shadow-black/50'
188+ } `}
189+ >
190+ < div className = "scale-[1.4]" >
191+ { isUnlocked ? achievement . icon : < Lock weight = "fill" /> }
192+ </ div >
193+ </ div >
194+ </ div >
195+
196+ { /* Title & Description */ }
213197 < h3
214- className = { `text-xl font-bold ${ isUnlocked ? 'text-yellow-100' : 'text-gray-500' } ` }
198+ className = { `text-xl font-playfairDisplay tracking-tight mb-3 ${
199+ isUnlocked ? 'text-white drop-shadow-[0_2px_2px_rgba(0,0,0,0.8)]' : 'text-gray-400'
200+ } `}
215201 >
216202 { achievement . title }
217203 </ h3 >
218- < p className = "mt-2 text-sm text-gray-400" >
204+ < p className = { `text-sm font-arvo leading-relaxed ${ isUnlocked ? ' text-gray-300' : ' text-gray-500' } ` } >
219205 { achievement . description }
220206 </ p >
221207 </ div >
222208
223- { isUnlocked && (
224- < div className = "mt-4 text-xs text-gray-600 font-mono" >
225- Unlocked on:{ ' ' }
226- { new Date (
227- unlockedAchievements [ achievement . id ] . unlockedAt ,
228- ) . toLocaleDateString ( ) }
229- </ div >
230- ) }
209+ { /* Footer Section (Date or Locked Status) */ }
210+ < div className = { `relative z-10 mt-auto p-4 w-full border-t ${
211+ isUnlocked ? 'border-yellow-900/30 bg-yellow-950/30' : 'border-gray-800/50 bg-gray-900/30'
212+ } `} >
213+ { isUnlocked ? (
214+ < div className = "flex items-center justify-center gap-2 text-xs text-yellow-500/80 font-medium font-mono uppercase tracking-widest" >
215+ < CalendarBlank weight = "duotone" size = { 16 } />
216+ < span > Unlocked: { unlockedDate . toLocaleDateString ( undefined , { year : 'numeric' , month : 'short' , day : 'numeric' } ) } </ span >
217+ </ div >
218+ ) : (
219+ < div className = "text-center text-xs text-gray-600 font-mono uppercase tracking-widest flex items-center justify-center gap-2" >
220+ < Lock size = { 14 } /> Locked
221+ </ div >
222+ ) }
223+ </ div >
231224 </ div >
232225 ) ;
233226 } ) }
0 commit comments