This commit is contained in:
gpt-engineer-app[bot]
2026-01-06 23:55:01 +00:00
parent 49abc06046
commit d13fa4f454
9 changed files with 84 additions and 1486 deletions
+65 -55
View File
@@ -148,10 +148,17 @@ const Tetris = () => {
const maxHeight = window.innerHeight - 440;
return Math.min(Math.floor(maxWidth / BOARD_WIDTH), Math.floor(maxHeight / BOARD_HEIGHT), 22);
}
// Desktop: calculate based on available height (subtract header ~60px, margins ~40px)
const availableHeight = window.innerHeight - 100;
const maxCellFromHeight = Math.floor(availableHeight / BOARD_HEIGHT);
if (gameMode === '2p') {
return isFullscreen ? 22 : 18;
// 2P needs two boards side by side plus controls (~500px for both boards + gaps)
const availableWidth = window.innerWidth - 300; // space for controls
const maxCellFromWidth = Math.floor(availableWidth / (BOARD_WIDTH * 2 + 4));
return Math.min(maxCellFromHeight, maxCellFromWidth, 28);
}
return isFullscreen ? 30 : 24;
// 1P mode - maximize based on height
return Math.min(maxCellFromHeight, 32);
}, [isFullscreen, gameMode]);
const [cellSize, setCellSize] = useState(getCellSize);
@@ -598,7 +605,7 @@ const Tetris = () => {
</button>
</div>
<div className={`flex ${isMobile ? 'flex-col items-center' : 'flex-row gap-4'} flex-1 ${isFullscreen ? 'justify-center items-center' : ''}`}>
<div className={`flex ${isMobile ? 'flex-col items-center' : 'flex-row gap-3 items-start justify-center'} flex-1`}>
{gameMode === '1p' ? (
<>
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard1P()}</div>
@@ -629,42 +636,44 @@ const Tetris = () => {
)}
</>
) : (
/* 2P Layout: P1 Board with Next | Controls | P2 Board with Next */
<>
{/* P1 Board */}
<div className="flex flex-col items-center gap-2">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm bg-primary" />
<span className="font-pixel text-xs text-primary">P1 (WASD/Q)</span>
{/* P1 Section */}
<div className="flex gap-2 items-start">
<div className="flex flex-col items-center gap-1">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm bg-primary" />
<span className="font-pixel text-xs text-primary">P1 (WASD/Q)</span>
</div>
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard2P(player1, 'border-primary/20')}</div>
<div className="flex gap-2 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{player1.score}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-primary">{player1.lines}</p></div>
</div>
{player1.gameOver && <span className="font-pixel text-xs text-destructive">GAME OVER</span>}
</div>
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard2P(player1, 'border-primary/20')}</div>
<div className="flex gap-2 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{player1.score}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-primary">{player1.lines}</p></div>
</div>
{player1.gameOver && <span className="font-pixel text-xs text-destructive">GAME OVER</span>}
</div>
{/* P1 Next Piece */}
<div className="border-2 border-primary/50 p-2 bg-background/50 flex flex-col items-center justify-center min-h-[60px]">
<p className="font-pixel text-[10px] text-foreground/60">P1 NEXT</p>
<div className="flex flex-col gap-1">
{player1.nextPiece.shape.map((row, y) => (
<div key={y} className="flex gap-1">
{row.map((val, x) => (
<div key={`${y}-${x}`} className={`w-2 h-2 ${val ? 'bg-primary box-glow' : 'bg-transparent'}`} />
))}
</div>
))}
{/* P1 Next Piece */}
<div className="border border-primary/50 p-2 bg-background/50 flex flex-col items-center justify-center">
<p className="font-pixel text-[8px] text-foreground/60 mb-1">NEXT</p>
<div className="flex flex-col gap-0.5">
{player1.nextPiece.shape.map((row, y) => (
<div key={y} className="flex gap-0.5">
{row.map((val, x) => (
<div key={`${y}-${x}`} className={`w-2 h-2 ${val ? 'bg-primary box-glow' : 'bg-transparent'}`} />
))}
</div>
))}
</div>
</div>
</div>
{/* Center controls */}
<div className="flex flex-col gap-2 min-w-[100px] items-center">
<div className="flex flex-col gap-2 min-w-[90px] items-center justify-center">
<div className="border border-primary/50 p-2 bg-background/50 text-center">
<p className="font-pixel text-[8px] text-foreground/60 mb-1">CONTROLS</p>
<p className="font-pixel text-[8px] text-primary">P1: WASD Q</p>
<p className="font-pixel text-[8px] text-purple-400">P2: /</p>
<p className="font-pixel text-[8px] text-foreground/60 mt-1">P: Pause</p>
<p className="font-pixel text-[7px] text-primary">P1: WASD Q</p>
<p className="font-pixel text-[7px] text-purple-400">P2: /</p>
<p className="font-pixel text-[7px] text-foreground/60 mt-1">P: Pause</p>
</div>
{!gameStarted || gameOver ? (
<button onClick={() => startGame('2p')} className="font-minecraft text-xs py-2 px-3 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
@@ -677,31 +686,32 @@ const Tetris = () => {
)}
</div>
{/* P2 Board */}
<div className="flex flex-col items-center gap-2">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: 'hsl(280 70% 50%)' }} />
<span className="font-pixel text-xs text-purple-400">P2 (/)</span>
{/* P2 Section */}
<div className="flex gap-2 items-start">
{/* P2 Next Piece */}
<div className="border border-purple-500/50 p-2 bg-background/50 flex flex-col items-center justify-center">
<p className="font-pixel text-[8px] text-purple-400 mb-1">NEXT</p>
<div className="flex flex-col gap-0.5">
{player2.nextPiece.shape.map((row, y) => (
<div key={y} className="flex gap-0.5">
{row.map((val, x) => (
<div key={`${y}-${x}`} className={`w-2 h-2 ${val ? 'bg-purple-400 box-glow' : 'bg-transparent'}`} />
))}
</div>
))}
</div>
</div>
<div className="border-2 border-purple-500 p-1 bg-background/80" style={{ boxShadow: '0 0 10px hsl(280 70% 50% / 0.5)' }}>{renderBoard2P(player2, 'border-purple-500/20')}</div>
<div className="flex gap-2 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-purple-400">{player2.score}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-purple-400">{player2.lines}</p></div>
</div>
{player2.gameOver && <span className="font-pixel text-xs text-destructive">GAME OVER</span>}
</div>
{/* P2 Next Piece */}
<div className="border-2 border-purple-500/50 p-2 bg-background/50 flex flex-col items-center justify-center min-h-[60px]">
<p className="font-pixel text-[10px] text-purple-400">P2 NEXT</p>
<div className="flex flex-col gap-1">
{player2.nextPiece.shape.map((row, y) => (
<div key={y} className="flex gap-1">
{row.map((val, x) => (
<div key={`${y}-${x}`} className={`w-2 h-2 ${val ? 'bg-purple-400 box-glow' : 'bg-transparent'}`} />
))}
</div>
))}
<div className="flex flex-col items-center gap-1">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: 'hsl(280 70% 50%)' }} />
<span className="font-pixel text-xs text-purple-400">P2 (/)</span>
</div>
<div className="border-2 border-purple-500 p-1 bg-background/80" style={{ boxShadow: '0 0 10px hsl(280 70% 50% / 0.5)' }}>{renderBoard2P(player2, 'border-purple-500/20')}</div>
<div className="flex gap-2 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-purple-400">{player2.score}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-purple-400">{player2.lines}</p></div>
</div>
{player2.gameOver && <span className="font-pixel text-xs text-destructive">GAME OVER</span>}
</div>
</div>
</>