Improve desktop UI for games
Refine layouts for all game pages (desktop only) with cleaner stats panels, enhanced spacing, borders, and consistent styling across Breakout, Snake, Tetris, Pac-Man, and overall Games listing. Includes updated grid/card layouts and improved control/info sections for a polished desktop experience. Screenshots generation not included. X-Lovable-Edit-ID: edt-de05423f-1c7e-4035-bbac-bc3a979354f9
This commit is contained in:
+42
-8
@@ -267,16 +267,50 @@ const Breakout = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<div className="flex flex-col gap-2 min-w-[140px]">
|
<div className="flex flex-col gap-3 min-w-[160px]">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">SCORE</p><p className="font-minecraft text-xl text-primary text-glow">{score.toLocaleString()}</p></div>
|
{/* Score Panel */}
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">HIGH SCORE</p><p className="font-minecraft text-lg text-primary text-glow">{highScore.toLocaleString()}</p><p className="font-pixel text-[8px] text-foreground/30">max: 4,294,967,296</p></div>
|
<div className="border-2 border-primary/50 p-4 bg-background/60">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">LEVEL</p><p className="font-minecraft text-lg text-primary text-glow">{level}</p></div>
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider">Score</p>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">LIVES</p><p className="font-minecraft text-lg text-primary text-glow">{'♥'.repeat(lives)}</p></div>
|
<p className="font-minecraft text-2xl text-primary text-glow-strong">{score.toLocaleString()}</p>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p><p className="font-pixel text-[10px] text-foreground/80">← → / A D</p><p className="font-pixel text-[10px] text-foreground/80">P: Pause</p></div>
|
</div>
|
||||||
|
|
||||||
|
{/* High Score */}
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">High Score</p>
|
||||||
|
<p className="font-minecraft text-lg text-primary/80">{highScore.toLocaleString()}</p>
|
||||||
|
<p className="font-pixel text-[8px] text-foreground/30 mt-1">max: 4,294,967,296</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Level & Lives */}
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40 text-center">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Level</p>
|
||||||
|
<p className="font-minecraft text-xl text-primary">{level}</p>
|
||||||
|
</div>
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40 text-center">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Lives</p>
|
||||||
|
<p className="font-minecraft text-lg text-primary text-glow">{'♥'.repeat(lives)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Controls */}
|
||||||
|
<div className="border border-primary/20 p-3 bg-background/30">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider mb-2">Controls</p>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">← → / A D</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">P: Pause</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
{!gameStarted || gameOver ? (
|
{!gameStarted || gameOver ? (
|
||||||
<button onClick={startGame} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameOver ? 'RETRY' : 'START'}</button>
|
<button onClick={startGame} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||||
|
{gameOver ? 'RETRY' : 'START GAME'}
|
||||||
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">{isPaused ? 'RESUME' : 'PAUSE'}</button>
|
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">
|
||||||
|
{isPaused ? 'RESUME' : 'PAUSE'}
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+36
-21
@@ -63,25 +63,27 @@ const Games = () => {
|
|||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.5 }}
|
||||||
className="flex flex-col h-full"
|
className="flex flex-col h-full"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
{/* Header */}
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="font-minecraft text-3xl md:text-4xl text-primary text-glow-strong mb-1">
|
<h1 className="font-minecraft text-3xl md:text-4xl text-primary text-glow-strong mb-2">
|
||||||
<GlitchText text="Arcade" />
|
<GlitchText text="Arcade" />
|
||||||
</h1>
|
</h1>
|
||||||
<p className="font-pixel text-sm text-foreground/70">
|
<p className="font-pixel text-sm text-foreground/60">
|
||||||
Select a game. High scores saved locally.
|
Select a game to play. High scores saved locally.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
to="/games/leaderboard"
|
to="/games/leaderboard"
|
||||||
className="flex items-center gap-2 font-pixel text-sm text-primary border border-primary/50 px-3 py-2 hover:bg-primary/20 transition-colors"
|
className="flex items-center gap-2 font-pixel text-sm text-primary border-2 border-primary/50 px-4 py-2.5 hover:bg-primary/20 hover:border-primary transition-all box-glow-subtle"
|
||||||
>
|
>
|
||||||
<Trophy size={16} />
|
<Trophy size={18} />
|
||||||
Leaderboard
|
<span className="hidden sm:inline">Leaderboard</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
{/* Game Grid */}
|
||||||
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6">
|
||||||
{games.map((game, index) => (
|
{games.map((game, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={game.id}
|
key={game.id}
|
||||||
@@ -89,19 +91,28 @@ const Games = () => {
|
|||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ delay: index * 0.1 }}
|
transition={{ delay: index * 0.1 }}
|
||||||
>
|
>
|
||||||
<Link to={`/games/${game.id}`} className="block">
|
<Link to={`/games/${game.id}`} className="block h-full">
|
||||||
<div className="border border-primary/50 hover:border-primary bg-background/50 hover:bg-primary/10 p-4 transition-all duration-300 group cursor-pointer relative">
|
<div className="border-2 border-primary/40 hover:border-primary bg-background/60 hover:bg-primary/10 p-5 transition-all duration-300 group cursor-pointer relative h-full flex flex-col hover:shadow-[0_0_20px_rgba(0,255,0,0.2)]">
|
||||||
<pre className="font-mono text-sm text-primary/70 group-hover:text-primary transition-colors mb-3 leading-tight">
|
{/* ASCII Preview */}
|
||||||
{game.ascii}
|
<div className="flex-1 flex items-center justify-center mb-4">
|
||||||
</pre>
|
<pre className="font-mono text-xs md:text-sm text-primary/60 group-hover:text-primary transition-colors leading-tight whitespace-pre">
|
||||||
<h2 className="font-minecraft text-xl text-primary text-glow group-hover:text-glow-strong">
|
{game.ascii}
|
||||||
<GlitchText text={game.name} />
|
</pre>
|
||||||
</h2>
|
</div>
|
||||||
<p className="font-pixel text-xs text-foreground/60 mt-2">
|
|
||||||
{game.description}
|
{/* Game Info */}
|
||||||
</p>
|
<div className="border-t border-primary/20 pt-3">
|
||||||
|
<h2 className="font-minecraft text-lg md:text-xl text-primary text-glow group-hover:text-glow-strong">
|
||||||
|
<GlitchText text={game.name} />
|
||||||
|
</h2>
|
||||||
|
<p className="font-pixel text-[10px] md:text-xs text-foreground/50 mt-1.5 line-clamp-2">
|
||||||
|
{game.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Multiplayer Badge */}
|
||||||
{game.hasMultiplayer && (
|
{game.hasMultiplayer && (
|
||||||
<span className="absolute top-2 right-2 font-pixel text-[8px] text-purple-400 border border-purple-500/50 px-1 py-0.5">
|
<span className="absolute top-3 right-3 font-pixel text-[10px] text-purple-400 border border-purple-500/60 bg-purple-500/10 px-2 py-1 rounded-sm">
|
||||||
2P
|
2P
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -111,11 +122,15 @@ const Games = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border border-primary/30 p-2 bg-background/30 mt-4">
|
{/* Footer */}
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/30 mt-6 flex items-center justify-between">
|
||||||
<p className="font-pixel text-xs text-foreground/50">
|
<p className="font-pixel text-xs text-foreground/50">
|
||||||
<span className="text-primary">{'>'}</span> Max score: 4,294,967,296
|
<span className="text-primary">{'>'}</span> Max score: 4,294,967,296
|
||||||
<span className="text-foreground/30 ml-2">(uint32 overflow)</span>
|
<span className="text-foreground/30 ml-2">(uint32 overflow)</span>
|
||||||
</p>
|
</p>
|
||||||
|
<p className="font-pixel text-xs text-foreground/40 hidden md:block">
|
||||||
|
Arrow keys / WASD to control
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|||||||
+76
-36
@@ -604,57 +604,97 @@ const Pacman = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<div className="flex flex-col gap-2 min-w-[140px]">
|
<div className="flex flex-col gap-3 min-w-[160px]">
|
||||||
|
{/* Score Panel */}
|
||||||
{gameMode === '2p' ? (
|
{gameMode === '2p' ? (
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
<div className="border-2 border-primary/50 p-4 bg-background/60">
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 mb-1">SCORES</p>
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider mb-2">Scores</p>
|
||||||
<div className="flex gap-2 justify-center">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div className="text-center"><p className="font-pixel text-[8px] text-foreground/80">P1</p><p className="font-minecraft text-lg text-primary text-glow">{score.toLocaleString()}</p></div>
|
<div className="text-center">
|
||||||
<div className="text-center"><p className="font-pixel text-[8px] text-foreground/80">P2</p><p className="font-minecraft text-lg text-primary text-glow">{score2.toLocaleString()}</p></div>
|
<p className="font-pixel text-[8px] text-primary">P1</p>
|
||||||
|
<p className="font-minecraft text-lg text-primary text-glow">{score.toLocaleString()}</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="font-pixel text-[8px]" style={{ color: 'hsl(120 70% 50%)' }}>P2</p>
|
||||||
|
<p className="font-minecraft text-lg" style={{ color: 'hsl(120 70% 50%)', textShadow: '0 0 10px hsl(120 70% 50%)' }}>{score2.toLocaleString()}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">SCORE</p><p className="font-minecraft text-xl text-primary text-glow">{score.toLocaleString()}</p></div>
|
<div className="border-2 border-primary/50 p-4 bg-background/60">
|
||||||
)}
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider">Score</p>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">HIGH SCORE</p><p className="font-minecraft text-lg text-primary text-glow">{highScore.toLocaleString()}</p><p className="font-pixel text-[8px] text-foreground/30">max: 4,294,967,296</p></div>
|
<p className="font-minecraft text-2xl text-primary text-glow-strong">{score.toLocaleString()}</p>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">LEVEL</p><p className="font-minecraft text-lg text-primary text-glow">{level}</p></div>
|
|
||||||
{gameMode === '2p' && (
|
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 mb-1">LIVES</p>
|
|
||||||
<div className="flex gap-2 justify-center">
|
|
||||||
<div className="text-center"><p className="font-pixel text-[8px] text-foreground/80">P1</p><p className="font-minecraft text-sm text-primary">{lives}</p></div>
|
|
||||||
<div className="text-center"><p className="font-pixel text-[8px] text-foreground/80">P2</p><p className="font-minecraft text-sm text-primary">{lives2}</p></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{gameMode === '1p' && (
|
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">LIVES</p><p className="font-minecraft text-lg text-primary text-glow">{lives}</p></div>
|
{/* High Score */}
|
||||||
)}
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">High Score</p>
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p>
|
<p className="font-minecraft text-lg text-primary/80">{highScore.toLocaleString()}</p>
|
||||||
|
<p className="font-pixel text-[8px] text-foreground/30 mt-1">max: 4,294,967,296</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Level & Lives */}
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40 text-center">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Level</p>
|
||||||
|
<p className="font-minecraft text-xl text-primary">{level}</p>
|
||||||
|
</div>
|
||||||
{gameMode === '2p' ? (
|
{gameMode === '2p' ? (
|
||||||
<>
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
<p className="font-pixel text-[8px] text-foreground/80">P1: WASD / ←→↑↓</p>
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider text-center">Lives</p>
|
||||||
<p className="font-pixel text-[8px] text-foreground/80">P2: I J K L</p>
|
<div className="flex justify-center gap-2 mt-1">
|
||||||
<p className="font-pixel text-[8px] text-foreground/80">P: Pause</p>
|
<span className="font-minecraft text-sm text-primary">{lives}</span>
|
||||||
</>
|
<span className="text-foreground/30">/</span>
|
||||||
|
<span className="font-minecraft text-sm" style={{ color: 'hsl(120 70% 50%)' }}>{lives2}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<div className="border border-primary/30 p-3 bg-background/40 text-center">
|
||||||
<p className="font-pixel text-[10px] text-foreground/80">WASD / ←→↑↓</p>
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Lives</p>
|
||||||
<p className="font-pixel text-[10px] text-foreground/80">P: Pause</p>
|
<p className="font-minecraft text-lg text-primary text-glow">{'♥'.repeat(lives)}</p>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Controls */}
|
||||||
|
<div className="border border-primary/20 p-3 bg-background/30">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider mb-2">Controls</p>
|
||||||
|
{gameMode === '2p' ? (
|
||||||
|
<div className="grid grid-cols-2 gap-2 text-center">
|
||||||
|
<div>
|
||||||
|
<p className="font-pixel text-[8px] text-primary">P1</p>
|
||||||
|
<p className="font-pixel text-[9px] text-foreground/60">WASD</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-pixel text-[8px]" style={{ color: 'hsl(120 70% 50%)' }}>P2</p>
|
||||||
|
<p className="font-pixel text-[9px] text-foreground/60">IJKL</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">WASD / ←→↑↓</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">P: Pause</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{gameMode === '2p' && <p className="font-pixel text-[9px] text-foreground/40 text-center mt-2">P: Pause</p>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
{showModeSelection ? (
|
{showModeSelection ? (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 text-center">SELECT MODE</p>
|
<p className="font-pixel text-[10px] text-foreground/50 text-center uppercase tracking-wider">Select Mode</p>
|
||||||
<button onClick={() => { setGameMode('1p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">1 PLAYER</button>
|
<button onClick={() => { setGameMode('1p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">1 PLAYER</button>
|
||||||
<button onClick={() => { setGameMode('2p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">2 PLAYERS</button>
|
<button onClick={() => { setGameMode('2p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">2 PLAYERS</button>
|
||||||
</div>
|
</div>
|
||||||
) : !gameStarted || gameOver || gameComplete ? (
|
) : !gameStarted || gameOver || gameComplete ? (
|
||||||
<button onClick={startGame} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}</button>
|
<button onClick={startGame} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||||
|
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START GAME'}
|
||||||
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">{isPaused ? 'RESUME' : 'PAUSE'}</button>
|
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">
|
||||||
|
{isPaused ? 'RESUME' : 'PAUSE'}
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+64
-39
@@ -546,31 +546,42 @@ const Snake = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isMobile && gameMode === '1p' && (
|
{!isMobile && gameMode === '1p' && (
|
||||||
<div className="flex flex-col gap-2 min-w-[140px]">
|
<div className="flex flex-col gap-3 min-w-[160px]">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
{/* Score Panel */}
|
||||||
<p className="font-pixel text-[10px] text-foreground/60">SCORE</p>
|
<div className="border-2 border-primary/50 p-4 bg-background/60 space-y-1">
|
||||||
<p className="font-minecraft text-xl text-primary text-glow">{score.toLocaleString()}</p>
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider">Score</p>
|
||||||
|
<p className="font-minecraft text-2xl text-primary text-glow-strong">{score.toLocaleString()}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
|
||||||
<p className="font-pixel text-[10px] text-foreground/60">HIGH SCORE</p>
|
{/* High Score Panel */}
|
||||||
<p className="font-minecraft text-lg text-primary text-glow">{highScore.toLocaleString()}</p>
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
<p className="font-pixel text-[8px] text-foreground/30">max: 4,294,967,296</p>
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">High Score</p>
|
||||||
|
<p className="font-minecraft text-lg text-primary/80">{highScore.toLocaleString()}</p>
|
||||||
|
<p className="font-pixel text-[8px] text-foreground/30 mt-1">max: 4,294,967,296</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
|
||||||
<p className="font-pixel text-[10px] text-foreground/60">LENGTH</p>
|
{/* Stats */}
|
||||||
<p className="font-minecraft text-lg text-primary text-glow">{snake.length}</p>
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Length</p>
|
||||||
|
<p className="font-minecraft text-xl text-primary">{snake.length}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p>
|
{/* Controls */}
|
||||||
<p className="font-pixel text-[10px] text-foreground/80">← → ↑ ↓ / WASD</p>
|
<div className="border border-primary/20 p-3 bg-background/30">
|
||||||
<p className="font-pixel text-[10px] text-foreground/80">P: Pause</p>
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider mb-2">Controls</p>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">← → ↑ ↓ / WASD</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">P: Pause</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
{!gameStarted || gameOver || gameComplete ? (
|
{!gameStarted || gameOver || gameComplete ? (
|
||||||
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||||
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}
|
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START GAME'}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">
|
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">
|
||||||
{isPaused ? 'RESUME' : 'PAUSE'}
|
{isPaused ? 'RESUME' : 'PAUSE'}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -578,38 +589,52 @@ const Snake = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!isMobile && gameMode === '2p' && (
|
{!isMobile && gameMode === '2p' && (
|
||||||
<div className="flex flex-col gap-2 min-w-[160px]">
|
<div className="flex flex-col gap-3 min-w-[180px]">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
{/* Player 1 */}
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="border-2 border-primary/60 p-4 bg-background/60">
|
||||||
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[0].color }} />
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<p className="font-pixel text-[10px] text-foreground/60">P1 (WASD)</p>
|
<div className="w-4 h-4 rounded-sm" style={{ backgroundColor: players[0].color, boxShadow: '0 0 8px ' + players[0].color }} />
|
||||||
|
<p className="font-pixel text-xs text-primary">Player 1</p>
|
||||||
|
<span className="font-pixel text-[8px] text-foreground/40 ml-auto">WASD</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="font-minecraft text-lg text-primary text-glow">{players[0].score}</p>
|
<p className="font-minecraft text-2xl text-primary text-glow-strong">{players[0].score}</p>
|
||||||
{!players[0].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
|
{!players[0].alive && <p className="font-pixel text-[10px] text-destructive mt-1 animate-pulse">☠ ELIMINATED</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border border-purple-500/50 p-3 bg-background/50">
|
{/* Player 2 */}
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="border-2 border-purple-500/60 p-4 bg-background/60">
|
||||||
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[1].color }} />
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<p className="font-pixel text-[10px] text-foreground/60">P2 (↑↓←→)</p>
|
<div className="w-4 h-4 rounded-sm" style={{ backgroundColor: players[1].color, boxShadow: '0 0 8px ' + players[1].color }} />
|
||||||
|
<p className="font-pixel text-xs text-purple-400">Player 2</p>
|
||||||
|
<span className="font-pixel text-[8px] text-foreground/40 ml-auto">Arrows</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="font-minecraft text-lg text-purple-400">{players[1].score}</p>
|
<p className="font-minecraft text-2xl text-purple-400" style={{ textShadow: '0 0 10px hsl(280 70% 50%)' }}>{players[1].score}</p>
|
||||||
{!players[1].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
|
{!players[1].alive && <p className="font-pixel text-[10px] text-destructive mt-1 animate-pulse">☠ ELIMINATED</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border border-primary/50 p-3 bg-background/50">
|
{/* Controls Summary */}
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p>
|
<div className="border border-primary/20 p-3 bg-background/30">
|
||||||
<p className="font-pixel text-[9px] text-primary">P1: W A S D</p>
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider mb-2">Controls</p>
|
||||||
<p className="font-pixel text-[9px] text-purple-400">P2: ↑ ↓ ← →</p>
|
<div className="grid grid-cols-2 gap-2 text-center">
|
||||||
<p className="font-pixel text-[9px] text-foreground/80 mt-1">P: Pause</p>
|
<div>
|
||||||
|
<p className="font-pixel text-[8px] text-primary">P1</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">W A S D</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-pixel text-[8px] text-purple-400">P2</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">↑ ↓ ← →</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="font-pixel text-[9px] text-foreground/40 text-center mt-2">P: Pause</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
{!gameStarted || gameOver ? (
|
{!gameStarted || gameOver ? (
|
||||||
<button onClick={() => startGame('2p')} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
<button onClick={() => startGame('2p')} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||||
{gameOver ? 'PLAY AGAIN' : 'START'}
|
{gameOver ? 'PLAY AGAIN' : 'START GAME'}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">
|
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">
|
||||||
{isPaused ? 'RESUME' : 'PAUSE'}
|
{isPaused ? 'RESUME' : 'PAUSE'}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+51
-17
@@ -603,27 +603,61 @@ const Tetris = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard1P()}</div>
|
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard1P()}</div>
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<div className="flex flex-col gap-2 min-w-[140px]">
|
<div className="flex flex-col gap-3 min-w-[160px]">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50 flex flex-col items-center justify-center min-h-[80px]">
|
{/* Next Piece Preview */}
|
||||||
<p className="font-pixel text-[10px] text-foreground/60 w-full mb-2">NEXT</p>
|
<div className="border-2 border-primary/50 p-4 bg-background/60">
|
||||||
<div className="flex flex-col gap-1">
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider mb-3">Next</p>
|
||||||
{nextPiece.shape.map((row, y) => (
|
<div className="flex justify-center">
|
||||||
<div key={y} className="flex gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
{row.map((val, x) => (
|
{nextPiece.shape.map((row, y) => (
|
||||||
<div key={`${y}-${x}`} className={`w-3 h-3 ${val ? 'bg-primary box-glow' : 'bg-transparent'}`} />
|
<div key={y} className="flex gap-1">
|
||||||
))}
|
{row.map((val, x) => (
|
||||||
</div>
|
<div key={`${y}-${x}`} className={`w-4 h-4 ${val ? 'bg-primary box-glow' : 'bg-transparent'}`} />
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">SCORE</p><p className="font-minecraft text-xl text-primary text-glow">{score.toLocaleString()}</p></div>
|
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">HIGH SCORE</p><p className="font-minecraft text-lg text-primary text-glow">{highScore.toLocaleString()}</p><p className="font-pixel text-[8px] text-foreground/30">max: 4,294,967,296</p></div>
|
{/* Score Panel */}
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60">LINES</p><p className="font-minecraft text-lg text-primary text-glow">{lines}</p></div>
|
<div className="border-2 border-primary/50 p-4 bg-background/60">
|
||||||
<div className="border border-primary/50 p-3 bg-background/50"><p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p><p className="font-pixel text-[10px] text-foreground/80">← → ↑ ↓ / WASD</p><p className="font-pixel text-[10px] text-foreground/80">Space: Drop</p><p className="font-pixel text-[10px] text-foreground/80">P: Pause</p></div>
|
<p className="font-pixel text-[10px] text-foreground/50 uppercase tracking-wider">Score</p>
|
||||||
|
<p className="font-minecraft text-2xl text-primary text-glow-strong">{score.toLocaleString()}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* High Score */}
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">High Score</p>
|
||||||
|
<p className="font-minecraft text-lg text-primary/80">{highScore.toLocaleString()}</p>
|
||||||
|
<p className="font-pixel text-[8px] text-foreground/30 mt-1">max: 4,294,967,296</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Lines */}
|
||||||
|
<div className="border border-primary/30 p-3 bg-background/40">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider">Lines</p>
|
||||||
|
<p className="font-minecraft text-xl text-primary">{lines}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Controls */}
|
||||||
|
<div className="border border-primary/20 p-3 bg-background/30">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/40 uppercase tracking-wider mb-2">Controls</p>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">← → ↑ ↓ / WASD</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">Space: Hard Drop</p>
|
||||||
|
<p className="font-pixel text-[10px] text-foreground/60">P: Pause</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
{!gameStarted || gameOver || gameComplete ? (
|
{!gameStarted || gameOver || gameComplete ? (
|
||||||
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}</button>
|
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-3 px-4 border-2 border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||||
|
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START GAME'}
|
||||||
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={togglePause} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">{isPaused ? 'RESUME' : 'PAUSE'}</button>
|
<button onClick={togglePause} className="font-minecraft text-sm py-3 px-4 border-2 border-primary/60 bg-background/50 text-primary hover:bg-primary/20 transition-all">
|
||||||
|
{isPaused ? 'RESUME' : 'PAUSE'}
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user