404lab 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,479 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef, useState, useCallback } from 'react';
4
+ import Link from 'next/link';
5
+ import { cn } from '@/components/ui/cn';
6
+
7
+ export default function BugGame404() {
8
+ const canvasRef = useRef<HTMLCanvasElement>(null);
9
+ const containerRef = useRef<HTMLDivElement>(null);
10
+ const [gameState, setGameState] = useState<'start' | 'play' | 'gameover' | 'victory'>('start');
11
+ const [score, setScore] = useState(0);
12
+ const [highScore, setHighScore] = useState(0);
13
+
14
+ const stateRef = useRef<'start' | 'play' | 'gameover' | 'victory'>('start');
15
+ const scoreRef = useRef(0);
16
+ const speedRef = useRef(3);
17
+
18
+ const obstaclesRef = useRef<Array<{ x: number; gapY: number; gapHeight: number; label: string; passed: boolean }>>([]);
19
+
20
+ const particlesRef = useRef<Array<{ x: number; y: number; vx: number; vy: number; life: number; size: number; color: string; decay: number }>>([]);
21
+ const bgParticlesRef = useRef<Array<{ x: number; y: number; size: number; speed: number; opacity: number }>>([]);
22
+
23
+ const playerRef = useRef({
24
+ x: 100, y: 300, w: 34, h: 24, vy: 0,
25
+ rotation: 0, wingAngle: 0
26
+ });
27
+
28
+ const animationFrameRef = useRef<number>(0);
29
+ const scaleRef = useRef(1);
30
+
31
+ const GRAVITY = 0.25;
32
+ const JUMP_FORCE = -5.5;
33
+ const MAX_SPEED = 4;
34
+ const OBSTACLE_SPACING = 300;
35
+ const OBSTACLE_WIDTH = 60;
36
+ const MAX_SCORE = 404;
37
+
38
+ const ERROR_TEXTS = [
39
+ "404", "NULL", "NaN", "VOID", "ERR",
40
+ "FAIL", "LOST", "BUG", "GONE", "???",
41
+ "END", "NIL", "STOP", "NOPE", "ZERO"
42
+ ];
43
+
44
+ useEffect(() => {
45
+ const saved = localStorage.getItem('bugHigh');
46
+ if (saved) setHighScore(parseInt(saved, 10));
47
+ }, []);
48
+
49
+ const initBackground = useCallback((width: number, height: number) => {
50
+ bgParticlesRef.current = Array.from({ length: 60 }, () => ({
51
+ x: Math.random() * width,
52
+ y: Math.random() * height,
53
+ size: Math.random() * 2 + 0.5,
54
+ speed: Math.random() * 0.2 + 0.05,
55
+ opacity: Math.random() * 0.4 + 0.1
56
+ }));
57
+ }, []);
58
+
59
+ const spawnObstacle = (x: number, height: number) => {
60
+ const minGap = 180;
61
+ const maxGap = 260;
62
+ const gapHeight = Math.random() * (maxGap - minGap) + minGap;
63
+ const minGapY = 100 + gapHeight/2;
64
+ const maxGapY = height - 100 - gapHeight/2;
65
+ const gapY = Math.random() * (maxGapY - minGapY) + minGapY;
66
+
67
+ obstaclesRef.current.push({
68
+ x,
69
+ gapY,
70
+ gapHeight,
71
+ label: ERROR_TEXTS[Math.floor(Math.random() * ERROR_TEXTS.length)],
72
+ passed: false
73
+ });
74
+ };
75
+
76
+ const initGame = useCallback(() => {
77
+ if (!canvasRef.current) return;
78
+ const { width, height } = canvasRef.current;
79
+
80
+ obstaclesRef.current = [];
81
+ particlesRef.current = [];
82
+ scoreRef.current = 0;
83
+ speedRef.current = 2.5;
84
+ setScore(0);
85
+
86
+ initBackground(width, height);
87
+
88
+ playerRef.current = {
89
+ x: width * 0.2,
90
+ y: height / 2,
91
+ w: 34, h: 24, vy: 0,
92
+ rotation: 0, wingAngle: 0
93
+ };
94
+
95
+ for (let i = 0; i < 3; i++) {
96
+ spawnObstacle(width + 500 + i * OBSTACLE_SPACING, height);
97
+ }
98
+ }, [initBackground]);
99
+
100
+ const createBurst = (x: number, y: number, color: string, count = 8) => {
101
+ for (let i = 0; i < count; i++) {
102
+ const angle = Math.random() * Math.PI * 2;
103
+ const speed = Math.random() * 3 + 1;
104
+ particlesRef.current.push({
105
+ x, y,
106
+ vx: Math.cos(angle) * speed,
107
+ vy: Math.sin(angle) * speed,
108
+ life: 1.0,
109
+ size: Math.random() * 3 + 1,
110
+ color,
111
+ decay: Math.random() * 0.04 + 0.02
112
+ });
113
+ }
114
+ };
115
+
116
+ const jump = () => {
117
+ if (stateRef.current !== 'play') return;
118
+ const p = playerRef.current;
119
+ p.vy = JUMP_FORCE;
120
+ createBurst(p.x, p.y + p.h/2, 'rgba(255,255,255,0.4)', 4);
121
+ };
122
+
123
+ const update = () => {
124
+ if (stateRef.current !== 'play' || !canvasRef.current) return;
125
+ const { width, height } = canvasRef.current;
126
+
127
+ const p = playerRef.current;
128
+
129
+ p.vy += GRAVITY;
130
+ p.y += p.vy;
131
+
132
+ if (p.vy < 0) {
133
+ p.rotation = Math.max(-0.5, p.rotation - 0.1);
134
+ } else {
135
+ p.rotation = Math.min(Math.PI / 2, p.rotation + 0.08);
136
+ }
137
+ p.wingAngle += 0.8;
138
+
139
+ if (p.y + p.h > height || p.y < 0) {
140
+ handleGameOver();
141
+ return;
142
+ }
143
+
144
+ obstaclesRef.current.forEach(obs => {
145
+ obs.x -= speedRef.current;
146
+
147
+ const pInset = 4;
148
+ const pl = p.x + pInset;
149
+ const pr = p.x + p.w - pInset;
150
+ const pt = p.y + pInset;
151
+ const pb = p.y + p.h - pInset;
152
+
153
+ const gapTop = obs.gapY - obs.gapHeight / 2;
154
+ const gapBottom = obs.gapY + obs.gapHeight / 2;
155
+
156
+ if (
157
+ pr > obs.x &&
158
+ pl < obs.x + OBSTACLE_WIDTH
159
+ ) {
160
+ if (pt < gapTop || pb > gapBottom) {
161
+ handleGameOver();
162
+ }
163
+ }
164
+
165
+ if (!obs.passed && pl > obs.x + OBSTACLE_WIDTH) {
166
+ obs.passed = true;
167
+ scoreRef.current += 1;
168
+ setScore(scoreRef.current);
169
+ if (speedRef.current < MAX_SPEED) speedRef.current += 0.05;
170
+
171
+ if (scoreRef.current >= 404) {
172
+ stateRef.current = 'victory';
173
+ setGameState('victory');
174
+ }
175
+ }
176
+ });
177
+
178
+ if (obstaclesRef.current[0] && obstaclesRef.current[0].x < -100) {
179
+ obstaclesRef.current.shift();
180
+ }
181
+
182
+ const lastObs = obstaclesRef.current[obstaclesRef.current.length - 1];
183
+ if (lastObs && lastObs.x < width - 100) {
184
+ spawnObstacle(lastObs.x + OBSTACLE_SPACING, height);
185
+ }
186
+
187
+ particlesRef.current.forEach(pt => {
188
+ pt.x += pt.vx;
189
+ pt.y += pt.vy;
190
+ pt.life -= pt.decay;
191
+ });
192
+ particlesRef.current = particlesRef.current.filter(pt => pt.life > 0);
193
+
194
+ bgParticlesRef.current.forEach(bg => {
195
+ bg.x -= bg.speed * (speedRef.current * 0.2);
196
+ if (bg.x < 0) bg.x = width;
197
+ });
198
+ };
199
+
200
+ const draw = () => {
201
+ if (!canvasRef.current) return;
202
+ const ctx = canvasRef.current.getContext('2d');
203
+ if (!ctx) return;
204
+ const { width, height } = canvasRef.current;
205
+
206
+ const bgGrad = ctx.createLinearGradient(0, 0, 0, height);
207
+ bgGrad.addColorStop(0, '#020617');
208
+ bgGrad.addColorStop(1, '#1e1b4b');
209
+ ctx.fillStyle = bgGrad;
210
+ ctx.fillRect(0, 0, width, height);
211
+
212
+ ctx.strokeStyle = '#3b82f6';
213
+ ctx.lineWidth = 1;
214
+ ctx.globalAlpha = 0.1;
215
+
216
+ ctx.fillStyle = '#94a3b8';
217
+ bgParticlesRef.current.forEach(bg => {
218
+ ctx.globalAlpha = bg.opacity;
219
+ ctx.beginPath();
220
+ const sz = bg.size;
221
+ ctx.rect(bg.x, bg.y, sz, sz);
222
+ ctx.fill();
223
+ });
224
+ ctx.globalAlpha = 1;
225
+
226
+ obstaclesRef.current.forEach(obs => {
227
+ const gapTop = obs.gapY - obs.gapHeight / 2;
228
+ const gapBottom = obs.gapY + obs.gapHeight / 2;
229
+
230
+ const pipeGrad = ctx.createLinearGradient(obs.x, 0, obs.x + OBSTACLE_WIDTH, 0);
231
+ pipeGrad.addColorStop(0, '#334155');
232
+ pipeGrad.addColorStop(0.5, '#475569');
233
+ pipeGrad.addColorStop(1, '#1e293b');
234
+
235
+ ctx.fillStyle = pipeGrad;
236
+ ctx.fillRect(obs.x, 0, OBSTACLE_WIDTH, gapTop);
237
+ ctx.fillRect(obs.x, gapBottom, OBSTACLE_WIDTH, height - gapBottom);
238
+
239
+ ctx.shadowBlur = 10;
240
+ ctx.shadowColor = '#f43f5e';
241
+ ctx.strokeStyle = '#e11d48';
242
+ ctx.lineWidth = 2;
243
+ ctx.strokeRect(obs.x, 0, OBSTACLE_WIDTH, gapTop);
244
+ ctx.strokeRect(obs.x, gapBottom, OBSTACLE_WIDTH, height - gapBottom);
245
+ ctx.shadowBlur = 0;
246
+
247
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
248
+ ctx.font = 'bold 16px monospace';
249
+ ctx.textAlign = 'center';
250
+ if (gapTop > 50) {
251
+ ctx.fillText(obs.label, obs.x + OBSTACLE_WIDTH/2, gapTop - 20);
252
+ }
253
+ if (height - gapBottom > 50) {
254
+ ctx.fillText(obs.label, obs.x + OBSTACLE_WIDTH/2, gapBottom + 30);
255
+ }
256
+
257
+ ctx.fillStyle = '#0f172a';
258
+ ctx.fillRect(obs.x - 2, gapTop - 20, OBSTACLE_WIDTH + 4, 20);
259
+ ctx.fillRect(obs.x - 2, gapBottom, OBSTACLE_WIDTH + 4, 20);
260
+ });
261
+
262
+ const p = playerRef.current;
263
+ ctx.save();
264
+ ctx.translate(p.x + p.w/2, p.y + p.h/2);
265
+ ctx.rotate(p.rotation);
266
+
267
+ ctx.shadowBlur = 15;
268
+ ctx.shadowColor = '#a855f7';
269
+
270
+ ctx.fillStyle = '#9333ea';
271
+ ctx.beginPath();
272
+ ctx.roundRect(-p.w/2, -p.h/2, p.w, p.h, 6);
273
+ ctx.fill();
274
+
275
+ ctx.fillStyle = '#fff';
276
+ ctx.beginPath();
277
+ ctx.arc(6, -4, 8, 0, Math.PI * 2);
278
+ ctx.fill();
279
+ ctx.fillStyle = '#000';
280
+ ctx.beginPath();
281
+ ctx.arc(8, -4, 3, 0, Math.PI * 2);
282
+ ctx.fill();
283
+
284
+ const wingY = Math.sin(p.wingAngle) * 6;
285
+ ctx.fillStyle = '#f3e8ff';
286
+ ctx.beginPath();
287
+ ctx.ellipse(-8, -2 + wingY, 8, 5, -0.4, 0, Math.PI * 2);
288
+ ctx.fill();
289
+
290
+ ctx.restore();
291
+ ctx.shadowBlur = 0;
292
+
293
+ particlesRef.current.forEach(pt => {
294
+ ctx.globalAlpha = pt.life;
295
+ ctx.fillStyle = pt.color;
296
+ ctx.beginPath();
297
+ ctx.arc(pt.x, pt.y, pt.size, 0, Math.PI * 2);
298
+ ctx.fill();
299
+ });
300
+ ctx.globalAlpha = 1;
301
+
302
+ if (stateRef.current === 'play') {
303
+ ctx.fillStyle = 'rgba(255,255,255,0.8)';
304
+ ctx.font = '900 48px sans-serif';
305
+ ctx.textAlign = 'center';
306
+ ctx.fillText(scoreRef.current.toString(), width/2, 80);
307
+ }
308
+ };
309
+
310
+ const loop = () => {
311
+ update();
312
+ draw();
313
+ animationFrameRef.current = requestAnimationFrame(loop);
314
+ };
315
+
316
+ const handleResize = useCallback(() => {
317
+ if (!containerRef.current || !canvasRef.current) return;
318
+ const { clientWidth, clientHeight } = containerRef.current;
319
+
320
+ scaleRef.current = window.devicePixelRatio || 1;
321
+ canvasRef.current.width = clientWidth * scaleRef.current;
322
+ canvasRef.current.height = clientHeight * scaleRef.current;
323
+ canvasRef.current.style.width = `${clientWidth}px`;
324
+ canvasRef.current.style.height = `${clientHeight}px`;
325
+
326
+ const ctx = canvasRef.current.getContext('2d');
327
+ if (ctx) ctx.scale(scaleRef.current, scaleRef.current);
328
+
329
+ initBackground(clientWidth, clientHeight);
330
+ }, [initBackground]);
331
+
332
+ useEffect(() => {
333
+ window.addEventListener('resize', handleResize);
334
+ handleResize();
335
+ initGame();
336
+ loop();
337
+
338
+ return () => {
339
+ window.removeEventListener('resize', handleResize);
340
+ cancelAnimationFrame(animationFrameRef.current);
341
+ };
342
+ }, [handleResize, initGame]);
343
+
344
+ const handleInput = (e: React.MouseEvent | React.TouchEvent | KeyboardEvent) => {
345
+ if (stateRef.current === 'start' || stateRef.current === 'gameover' || stateRef.current === 'victory') {
346
+ if (e.type === 'keydown' && (e as KeyboardEvent).code !== 'Space' && (e as KeyboardEvent).code !== 'Enter') return;
347
+ if (stateRef.current === 'start') {
348
+ stateRef.current = 'play';
349
+ setGameState('play');
350
+ jump();
351
+ }
352
+ return;
353
+ }
354
+ jump();
355
+ };
356
+
357
+ useEffect(() => {
358
+ const handleKey = (e: KeyboardEvent) => {
359
+ if (e.code === 'Space' || e.code === 'Enter') {
360
+ e.preventDefault();
361
+ handleInput(e);
362
+ }
363
+ };
364
+ window.addEventListener('keydown', handleKey);
365
+ return () => window.removeEventListener('keydown', handleKey);
366
+ }, []);
367
+
368
+ const handleGameOver = () => {
369
+ stateRef.current = 'gameover';
370
+ setGameState('gameover');
371
+ if (scoreRef.current > highScore) {
372
+ setHighScore(scoreRef.current);
373
+ localStorage.setItem('bugHigh', scoreRef.current.toString());
374
+ }
375
+ }
376
+
377
+ const resetGame = () => {
378
+ initGame();
379
+ stateRef.current = 'start';
380
+ setGameState('start');
381
+ }
382
+
383
+ return (
384
+ <div
385
+ ref={containerRef}
386
+ className="relative w-full h-screen overflow-hidden bg-slate-950 select-none font-sans"
387
+ onMouseDown={handleInput}
388
+ onTouchStart={(e) => {
389
+ handleInput(e);
390
+ }}
391
+ >
392
+ <canvas
393
+ ref={canvasRef}
394
+ className="block w-full h-full touch-none"
395
+ />
396
+
397
+ {gameState === 'start' && (
398
+ <div className="absolute inset-0 flex flex-col items-center justify-center z-20 animate-in fade-in bg-black/40 backdrop-blur-sm px-4">
399
+ <div className="relative mb-6 sm:mb-8">
400
+ <div className="absolute -inset-4 bg-purple-500/30 blur-xl rounded-full animate-pulse" />
401
+ <span className="relative text-5xl sm:text-7xl select-none">👾</span>
402
+ </div>
403
+ <h1 className="text-3xl sm:text-5xl font-black text-white tracking-tighter mb-2 drop-shadow-xl text-center">
404
+ <span className="text-purple-400">404</span> GLITCH JUMP
405
+ </h1>
406
+ <p className="text-slate-400 mb-6 sm:mb-8 font-mono text-xs sm:text-sm tracking-widest text-center max-w-xs">
407
+ PROTOCOL: AVOID_THE_VOID<br/>
408
+ TARGET: SCORE_404
409
+ </p>
410
+ <button
411
+ onClick={(e) => { e.stopPropagation(); setGameState('play'); stateRef.current = 'play'; }}
412
+ className="px-8 sm:px-10 py-3 sm:py-4 bg-white text-black font-black text-base sm:text-lg rounded-full hover:scale-110 transition-transform shadow-[0_0_20px_rgba(255,255,255,0.4)]"
413
+ >
414
+ START DEBUGGING
415
+ </button>
416
+ <div className="absolute bottom-6 sm:bottom-10 text-slate-500 text-[10px] sm:text-xs uppercase animate-pulse">
417
+ Tap / Space / Click to Fly
418
+ </div>
419
+ </div>
420
+ )}
421
+
422
+ {(gameState === 'gameover' || gameState === 'victory') && (
423
+ <div className="absolute inset-0 flex flex-col items-center justify-center z-30 bg-black/70 backdrop-blur-md animate-in zoom-in-95">
424
+ <div className="bg-slate-900/90 border border-slate-700 p-8 rounded-3xl shadow-2xl text-center max-w-sm mx-6 relative overflow-hidden">
425
+
426
+ <div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-red-500 to-transparent opacity-50" />
427
+
428
+ <div className="mb-4">
429
+ {gameState === 'victory' ? (
430
+ <span className="text-6xl">🎉</span>
431
+ ) : (
432
+ <span className="text-6xl">💀</span>
433
+ )}
434
+ </div>
435
+
436
+ <h2 className="text-3xl font-black text-white mb-1">
437
+ {gameState === 'victory' ? "ERROR RESOLVED" : "CONNECTION LOST"}
438
+ </h2>
439
+ <div className="text-slate-400 text-xs font-mono mb-6 uppercase tracking-widest">
440
+ {gameState === 'victory' ? "System Restored Successfully" : "The Bug Was Squashed"}
441
+ </div>
442
+
443
+ <div className="w-full bg-slate-800 rounded-xl p-4 mb-6">
444
+ <div className="flex justify-between items-end mb-2">
445
+ <span className="text-slate-400 text-xs uppercase font-bold">Score</span>
446
+ <span className="text-4xl font-black text-white leading-none">{score}</span>
447
+ </div>
448
+ <div className="w-full h-px bg-slate-700 my-2" />
449
+ <div className="flex justify-between items-end">
450
+ <span className="text-slate-500 text-xs uppercase font-bold">Best</span>
451
+ <span className="text-xl font-bold text-slate-300 leading-none">{highScore}</span>
452
+ </div>
453
+ </div>
454
+
455
+ <div className="flex gap-3">
456
+ <button
457
+ onClick={(e) => { e.stopPropagation(); resetGame(); }}
458
+ className="flex-1 py-3 bg-purple-600 hover:bg-purple-500 text-white font-bold rounded-xl transition-colors shadow-lg shadow-purple-900/20"
459
+ >
460
+ RETRY
461
+ </button>
462
+ <Link
463
+ href="/"
464
+ onClick={(e) => e.stopPropagation()}
465
+ className="flex-1 py-3 bg-slate-700 hover:bg-slate-600 text-white font-bold rounded-xl transition-colors"
466
+ >
467
+ HOME
468
+ </Link>
469
+ </div>
470
+
471
+ <div className="mt-6 text-[10px] text-slate-600 font-mono">
472
+ ERROR_CODE_404_PAGE_NOT_FOUND
473
+ </div>
474
+ </div>
475
+ </div>
476
+ )}
477
+ </div>
478
+ );
479
+ }
@@ -2,26 +2,10 @@
2
2
 
3
3
  import Image from "next/image";
4
4
  import Link from "next/link";
5
- import { motion } from "framer-motion";
6
5
  import { Search, GraduationCap, Code2, Terminal, BookOpen } from "lucide-react";
7
6
  import { cn } from "@/components/ui/cn";
8
7
 
9
8
  const GeeksforGeeks = ({ className }: { className?: string }) => {
10
- const containerVariants = {
11
- hidden: { opacity: 0 },
12
- visible: {
13
- opacity: 1,
14
- transition: {
15
- staggerChildren: 0.1,
16
- },
17
- },
18
- };
19
-
20
- const itemVariants = {
21
- hidden: { opacity: 0, y: 20 },
22
- visible: { opacity: 1, y: 0 },
23
- };
24
-
25
9
  return (
26
10
  <div
27
11
  className={cn(
@@ -29,16 +13,30 @@ const GeeksforGeeks = ({ className }: { className?: string }) => {
29
13
  className
30
14
  )}
31
15
  >
16
+ <style jsx global>{`
17
+ @keyframes fadeIn {
18
+ from { opacity: 0; transform: translateY(20px); }
19
+ to { opacity: 1; transform: translateY(0); }
20
+ }
21
+
22
+ .animate-fade-in {
23
+ animation: fadeIn 0.6s ease-out forwards;
24
+ opacity: 0;
25
+ }
26
+
27
+ .delay-100 { animation-delay: 100ms; }
28
+ .delay-200 { animation-delay: 200ms; }
29
+ .delay-300 { animation-delay: 300ms; }
30
+ .delay-400 { animation-delay: 400ms; }
31
+ `}</style>
32
+
32
33
  <div className="absolute inset-0 z-0 opacity-[0.03] pointer-events-none"
33
34
  style={{ backgroundImage: 'radial-gradient(#2f8d46 1px, transparent 1px)', backgroundSize: '30px 30px' }} />
34
35
 
35
- <motion.div
36
+ <div
36
37
  className="z-10 w-full max-w-5xl flex flex-col items-center"
37
- variants={containerVariants}
38
- initial="hidden"
39
- animate="visible"
40
38
  >
41
- <motion.div variants={itemVariants} className="mb-8">
39
+ <div className="mb-8 animate-fade-in">
42
40
  <Image
43
41
  src="https://media.geeksforgeeks.org/auth-dashboard-uploads/Illustration.svg"
44
42
  alt="404 Illustration"
@@ -47,26 +45,23 @@ const GeeksforGeeks = ({ className }: { className?: string }) => {
47
45
  priority
48
46
  className="w-full max-w-[380px] h-auto drop-shadow-2xl"
49
47
  />
50
- </motion.div>
48
+ </div>
51
49
 
52
- <motion.h1
53
- variants={itemVariants}
54
- className="text-4xl md:text-5xl font-bold text-[#2f8d46] mb-4 text-center"
50
+ <h1
51
+ className="text-3xl md:text-5xl font-bold text-[#2f8d46] mb-4 text-center animate-fade-in delay-100 px-4"
55
52
  >
56
53
  Data Structure Not Found
57
- </motion.h1>
54
+ </h1>
58
55
 
59
- <motion.p
60
- variants={itemVariants}
61
- className="text-gray-600 text-center max-w-xl mb-12 text-lg"
56
+ <p
57
+ className="text-gray-600 text-center max-w-xl mb-8 sm:mb-12 text-base sm:text-lg animate-fade-in delay-200 px-4"
62
58
  >
63
59
  Even the most efficient algorithms occasionally hit a null pointer.
64
60
  While we garbage collect this error, why not explore these popular topics?
65
- </motion.p>
61
+ </p>
66
62
 
67
- <motion.div
68
- variants={itemVariants}
69
- className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 w-full mb-12"
63
+ <div
64
+ className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 w-full mb-12 animate-fade-in delay-300"
70
65
  >
71
66
  <Card
72
67
  title="DSA Self Paced"
@@ -92,28 +87,28 @@ const GeeksforGeeks = ({ className }: { className?: string }) => {
92
87
  color="bg-emerald-50 text-emerald-600 border-emerald-100"
93
88
  description="For Data Science"
94
89
  />
95
- </motion.div>
90
+ </div>
96
91
 
97
- <motion.div variants={itemVariants} className="flex flex-col sm:flex-row gap-4 items-center">
98
- <div className="relative group">
92
+ <div className="flex flex-col sm:flex-row gap-4 items-center animate-fade-in delay-400 p-4">
93
+ <div className="relative group w-full sm:w-auto">
99
94
  <div className="absolute inset-y-0 left-3 flex items-center pointer-events-none">
100
95
  <Search className="w-4 h-4 text-gray-400" />
101
96
  </div>
102
97
  <input
103
98
  type="text"
104
99
  placeholder="Search for tutorials..."
105
- className="pl-10 pr-4 py-3 bg-white border border-gray-200 rounded-full w-64 md:w-80 focus:outline-none focus:ring-2 focus:ring-[#2f8d46]/20 focus:border-[#2f8d46] transition-all shadow-sm"
100
+ className="pl-10 pr-4 py-3 bg-white border border-gray-200 rounded-full w-full sm:w-64 md:w-80 focus:outline-none focus:ring-2 focus:ring-[#2f8d46]/20 focus:border-[#2f8d46] transition-all shadow-sm"
106
101
  />
107
102
  </div>
108
103
 
109
104
  <Link
110
105
  href="/"
111
- className="px-8 py-3 bg-[#2f8d46] text-white font-semibold rounded-full hover:bg-[#267339] transition-all shadow-md hover:shadow-lg active:scale-95"
106
+ className="w-full sm:w-auto px-8 py-3 bg-[#2f8d46] text-white font-semibold rounded-full hover:bg-[#267339] transition-all shadow-md hover:shadow-lg active:scale-95 text-center"
112
107
  >
113
108
  Back to Dashboard
114
109
  </Link>
115
- </motion.div>
116
- </motion.div>
110
+ </div>
111
+ </div>
117
112
 
118
113
  <div className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#2f8d46]/20 to-transparent" />
119
114
  </div>
@@ -122,10 +117,9 @@ const GeeksforGeeks = ({ className }: { className?: string }) => {
122
117
 
123
118
  const Card = ({ title, icon, color, description }: { title: string; icon: React.ReactNode; color: string; description: string }) => {
124
119
  return (
125
- <motion.div
126
- whileHover={{ y: -8, scale: 1.02 }}
120
+ <div
127
121
  className={cn(
128
- "p-6 rounded-2xl border bg-white flex flex-col items-center text-center shadow-sm hover:shadow-xl transition-all duration-300 cursor-pointer group"
122
+ "p-6 rounded-2xl border bg-white flex flex-col items-center text-center shadow-sm hover:shadow-xl transition-all duration-300 cursor-pointer group hover:-translate-y-2 hover:scale-[1.02]"
129
123
  )}
130
124
  >
131
125
  <div className={cn("p-4 rounded-xl mb-4 transition-colors group-hover:scale-110", color)}>
@@ -133,7 +127,7 @@ const Card = ({ title, icon, color, description }: { title: string; icon: React.
133
127
  </div>
134
128
  <h3 className="font-bold text-gray-900 mb-1">{title}</h3>
135
129
  <p className="text-sm text-gray-500">{description}</p>
136
- </motion.div>
130
+ </div>
137
131
  );
138
132
  };
139
133