Skip to content

Commit 5e18e7f

Browse files
committed
feat: reimagined achievements page.
1 parent 9573ace commit 5e18e7f

File tree

1 file changed

+91
-98
lines changed

1 file changed

+91
-98
lines changed

src/pages/AchievementsPage.js

Lines changed: 91 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import {
88
BellSlash,
99
FunnelIcon,
1010
XCircle,
11+
CalendarBlank,
1112
} from '@phosphor-icons/react';
1213
import useSeo from '../hooks/useSeo';
1314
import { useAchievements } from '../context/AchievementContext';
1415
import { 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

1718
const 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

Comments
 (0)