This commit is contained in:
gpt-engineer-app[bot]
2026-01-15 09:53:27 +00:00
parent ea9c60ab34
commit 037d88d44a
5 changed files with 198 additions and 43 deletions
+2 -2
View File
@@ -389,7 +389,7 @@ const AIChat = () => {
transition={{ duration: 0.5 }}
className={`flex flex-col ${
isFullscreen
? 'fixed inset-0 z-50 bg-background p-3 md:p-8 overflow-hidden'
? 'fixed inset-0 z-50 bg-background p-2 sm:p-3 md:p-8 overflow-hidden w-screen h-screen'
: 'h-full'
}`}
>
@@ -559,7 +559,7 @@ const AIChat = () => {
</div>
)}
<div
className={`max-w-[85%] sm:max-w-[80%] p-2 sm:p-3 rounded-lg text-sm ${
className={`max-w-[90%] sm:max-w-[85%] md:max-w-[80%] p-2 sm:p-3 rounded-lg text-xs sm:text-sm overflow-x-auto ${
message.role === 'user'
? 'bg-primary/20 border border-primary/50'
: 'bg-secondary/50 border border-primary/30'
+24 -14
View File
@@ -6,8 +6,8 @@ import { Link } from 'react-router-dom';
import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
import { useSwipeControls } from '@/hooks/useSwipeControls';
const GRID_WIDTH = 21;
const GRID_HEIGHT = 21;
@@ -105,6 +105,19 @@ const Pacman = () => {
const [cellSize, setCellSize] = useState(getCellSize);
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
// Swipe controls for mobile
const { getSwipeHandlers } = useSwipeControls({
onSwipe: (dir) => {
if (gameMode === '1p' && gameStarted && !gameOver && !gameComplete && !isPaused) {
setNextDirection(dir as Direction);
}
},
onTap: () => {
if (gameStarted && !gameOver && !gameComplete) setIsPaused(p => !p);
},
enabled: isMobile && gameStarted && !gameOver && !gameComplete,
});
useEffect(() => {
const handleResize = () => setCellSize(getCellSize());
window.addEventListener('resize', handleResize);
@@ -731,21 +744,18 @@ const Pacman = () => {
{showModeSelection ? (
<div className="flex flex-col gap-2 mt-2">
<p className="font-pixel text-[10px] text-foreground/60 text-center">SELECT MODE</p>
<button onClick={() => { setGameMode('1p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-3 px-8 border 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-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">2 PLAYERS</button>
<p className="font-pixel text-[10px] text-foreground/60 text-center">MOBILE: 1 PLAYER ONLY</p>
<button onClick={() => { setGameMode('1p'); setShowModeSelection(false); }} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">START GAME</button>
</div>
) : gameStarted && !gameOver && !gameComplete ? (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => setNextDirection('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => setNextDirection('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<div
className="w-full h-24 border border-primary/30 rounded-lg bg-primary/5 flex items-center justify-center touch-none mt-2"
{...getSwipeHandlers()}
>
<p className="font-pixel text-xs text-primary/60 text-center pointer-events-none">
SWIPE TO MOVE<br />
<span className="text-[10px] text-foreground/40">TAP TO PAUSE</span>
</p>
</div>
) : (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
+22 -11
View File
@@ -6,8 +6,8 @@ import { Link } from 'react-router-dom';
import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2, Users, User } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
import { useSwipeControls } from '@/hooks/useSwipeControls';
const GRID_SIZE = 20;
const TICK_SPEED = 120;
@@ -84,6 +84,19 @@ const Snake = () => {
const [cellSize, setCellSize] = useState(getCellSize);
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
// Swipe controls for mobile
const handleSwipe = useCallback((direction: Direction) => {
if (gameMode === '1p') {
directionQueueRef.current.push(direction);
}
}, [gameMode]);
const { getSwipeHandlers } = useSwipeControls({
onSwipe: (dir) => handleSwipe(dir as Direction),
onTap: () => setIsPaused(p => !p),
enabled: isMobile && gameStarted && !gameOver && !gameComplete,
});
useEffect(() => {
const handleResize = () => setCellSize(getCellSize());
window.addEventListener('resize', handleResize);
@@ -653,16 +666,14 @@ const Snake = () => {
</div>
{gameStarted && !gameOver && !gameComplete ? (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => directionQueueRef.current.push('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<div
className="w-full h-24 border border-primary/30 rounded-lg bg-primary/5 flex items-center justify-center touch-none"
{...getSwipeHandlers()}
>
<p className="font-pixel text-xs text-primary/60 text-center pointer-events-none">
SWIPE TO MOVE<br />
<span className="text-[10px] text-foreground/40">TAP TO PAUSE</span>
</p>
</div>
) : (
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
+43 -16
View File
@@ -6,8 +6,8 @@ import { Link } from 'react-router-dom';
import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2, Users, User } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
import { useSwipeControls, SwipeDirection } from '@/hooks/useSwipeControls';
const BOARD_WIDTH = 10;
const BOARD_HEIGHT = 20;
@@ -300,6 +300,39 @@ const Tetris = () => {
playSound('click');
};
// Swipe controls for mobile - must be after function declarations
const moveLeftRef = useRef(moveLeft);
const moveRightRef = useRef(moveRight);
const moveDownRef = useRef(moveDown);
const hardDropRef = useRef(hardDrop);
const rotatePieceRef = useRef(rotatePiece);
useEffect(() => {
moveLeftRef.current = moveLeft;
moveRightRef.current = moveRight;
moveDownRef.current = moveDown;
hardDropRef.current = hardDrop;
rotatePieceRef.current = rotatePiece;
});
const { getSwipeHandlers } = useSwipeControls({
onSwipe: (dir, isFastSwipe) => {
if (gameMode !== '1p' || gameOver || gameComplete || isPaused || !gameStarted) return;
switch (dir) {
case 'left': moveLeftRef.current(); break;
case 'right': moveRightRef.current(); break;
case 'down':
if (isFastSwipe) hardDropRef.current();
else moveDownRef.current();
break;
case 'up': rotatePieceRef.current(); break;
}
},
onTap: togglePause,
enabled: isMobile && gameStarted && !gameOver && !gameComplete,
fastSwipeThreshold: 1.2,
});
const movePlayer = useCallback((playerNum: 1 | 2, action: 'left' | 'right' | 'down' | 'rotate' | 'drop') => {
if (gameOver || isPaused || !gameStarted || gameMode !== '2p') return;
const setPlayer = playerNum === 1 ? setPlayer1 : setPlayer2;
@@ -603,21 +636,15 @@ const Tetris = () => {
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-primary">{lines}</p></div>
</div>
{gameStarted && !gameOver ? (
<div className="flex gap-3 items-center mt-1">
{/* D-pad style controls */}
<div className="grid grid-cols-3 gap-1">
<div />
<button onClick={rotatePiece} className="p-3 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg select-none"></button>
<div />
<GameTouchButton onAction={moveLeft} className="p-3 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={100}></GameTouchButton>
<button onClick={hardDrop} className="p-3 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg select-none"></button>
<GameTouchButton onAction={moveRight} className="p-3 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={100}></GameTouchButton>
<div />
<GameTouchButton onAction={moveDown} className="p-3 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={100}></GameTouchButton>
<div />
</div>
{/* Pause button on the side */}
<button onClick={togglePause} className="p-3 px-5 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<div
className="w-full h-24 border border-primary/30 rounded-lg bg-primary/5 flex items-center justify-center touch-none mt-1"
{...getSwipeHandlers()}
>
<p className="font-pixel text-xs text-primary/60 text-center pointer-events-none">
SWIPE TO MOVE<br />
SOFT DROP · FAST HARD DROP<br />
<span className="text-[10px] text-foreground/40"> ROTATE · TAP TO PAUSE</span>
</p>
</div>
) : (
<button onClick={() => startGame('1p')} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameOver ? 'RETRY' : 'START'}</button>