Fix UI colors and fullscreen
- AIChat: switch non-user message bg to muted; ensure loading indicator uses muted bg - Breakout: slow paddle/body speed for single/multiplayer; adjust fullscreen sizing logic - Pacman/Snake/Tetromino color behavior: align P2 coloring to secondary theme; enlarge fullscreen game canvases - Pacman 2P: invert Pacman2 color to secondary; adjust scoreboard visuals accordingly - Breakout fullscreen canvases now fill screen correctly in 1P/2P modes X-Lovable-Edit-ID: edt-81d11f66-89cd-4fdc-b76d-cca9bff1ac10
This commit is contained in:
@@ -578,7 +578,7 @@ const AIChat = () => {
|
||||
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'
|
||||
: 'bg-muted border border-primary/30'
|
||||
}`}
|
||||
>
|
||||
<MessageContent
|
||||
@@ -607,7 +607,7 @@ const AIChat = () => {
|
||||
<div className="w-8 h-8 rounded border border-primary/50 flex items-center justify-center bg-primary/10">
|
||||
<Bot className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<div className="p-3 rounded-lg bg-secondary/50 border border-primary/30">
|
||||
<div className="p-3 rounded-lg bg-muted border border-primary/30">
|
||||
<Loader2 className="w-4 h-4 text-primary animate-spin" />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
+20
-4
@@ -106,10 +106,26 @@ const Breakout = () => {
|
||||
if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; }
|
||||
return { width: Math.floor(width), height: Math.floor(height) };
|
||||
}
|
||||
if (isTwoPlayer) {
|
||||
return isFullscreen ? { width: 480, height: 580 } : { width: 400, height: 500 };
|
||||
if (isFullscreen) {
|
||||
const aspectRatio = 560 / 680;
|
||||
if (isTwoPlayer) {
|
||||
// Two canvases side by side
|
||||
const maxWidth = (window.innerWidth - 100) / 2;
|
||||
const maxHeight = window.innerHeight - 120;
|
||||
let width = maxWidth;
|
||||
let height = width / aspectRatio;
|
||||
if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; }
|
||||
return { width: Math.floor(width), height: Math.floor(height) };
|
||||
}
|
||||
// Single player - fill screen
|
||||
const maxWidth = window.innerWidth - 280;
|
||||
const maxHeight = window.innerHeight - 100;
|
||||
let width = maxWidth;
|
||||
let height = width / aspectRatio;
|
||||
if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; }
|
||||
return { width: Math.floor(width), height: Math.floor(height) };
|
||||
}
|
||||
return isFullscreen ? { width: 700, height: 840 } : { width: 560, height: 680 };
|
||||
return isTwoPlayer ? { width: 400, height: 500 } : { width: 560, height: 680 };
|
||||
}, [isFullscreen, isTwoPlayer]);
|
||||
|
||||
const [canvasSize, setCanvasSize] = useState(getCanvasSize);
|
||||
@@ -304,7 +320,7 @@ const Breakout = () => {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const paddleSpeed = isMobile ? 6 : (isFullscreen ? 10 : 8);
|
||||
const paddleSpeed = isMobile ? 4 : (isFullscreen ? 6 : 5);
|
||||
if (keysRef.current.has(leftKey)) paddleRefParam.current = Math.max(0, paddleRefParam.current - paddleSpeed);
|
||||
if (keysRef.current.has(rightKey)) paddleRefParam.current = Math.min(canvasSize.width - paddleWidth, paddleRefParam.current + paddleSpeed);
|
||||
|
||||
|
||||
+13
-7
@@ -122,7 +122,13 @@ const Pacman = () => {
|
||||
const maxHeight = window.innerHeight - 420;
|
||||
return Math.min(Math.floor(maxWidth / GRID_WIDTH), Math.floor(maxHeight / GRID_HEIGHT), 18);
|
||||
}
|
||||
return isFullscreen ? 30 : 24;
|
||||
if (isFullscreen) {
|
||||
// Fill screen more in fullscreen - calculate based on available space
|
||||
const maxWidth = window.innerWidth - 240; // Space for side panel
|
||||
const maxHeight = window.innerHeight - 100; // Space for header
|
||||
return Math.min(Math.floor(maxWidth / GRID_WIDTH), Math.floor(maxHeight / GRID_HEIGHT));
|
||||
}
|
||||
return 24;
|
||||
}, [isFullscreen]);
|
||||
|
||||
const [cellSize, setCellSize] = useState(getCellSize);
|
||||
@@ -678,7 +684,7 @@ const Pacman = () => {
|
||||
|
||||
const renderPacman2 = () => (
|
||||
<svg viewBox="0 0 100 100" className="w-full h-full transition-transform duration-100 ease-out" style={{ transform: `rotate(${getPacmanRotation2()}deg)` }}>
|
||||
<circle cx="50" cy="50" r="45" fill="hsl(120 70% 50%)" className="transition-all duration-100 ease-out" />
|
||||
<circle cx="50" cy="50" r="45" fill="hsl(var(--secondary))" className="transition-all duration-100 ease-out" />
|
||||
{mouthOpen2 && <path d="M 50 50 L 95 25 L 95 75 Z" fill="hsl(var(--background))" className="transition-all duration-100 ease-out" />}
|
||||
<circle cx="50" cy="25" r="6" fill="hsl(var(--background))" className="transition-all duration-100 ease-out" />
|
||||
</svg>
|
||||
@@ -713,7 +719,7 @@ const Pacman = () => {
|
||||
cells.push(
|
||||
<div key={`${x}-${y}`} className={`flex items-center justify-center transition-all duration-200 ease-out ${isWall ? 'bg-primary/20 border border-primary/40' : isTunnel ? 'bg-background/30' : 'bg-background/50 border border-primary/5'}`} style={{ width: cellSize, height: cellSize }}>
|
||||
{isPacmanHere && <div className={`drop-shadow-lg ${p1Invulnerable ? 'animate-pulse' : ''}`} style={{ width: spriteSize, height: spriteSize, transition: 'all 0.2s ease-out', filter: 'drop-shadow(0 0 4px hsl(var(--primary)))', opacity: p1Invulnerable ? 0.5 : 1 }}>{renderPacman()}</div>}
|
||||
{isPacman2Here && <div className={`drop-shadow-lg ${p2Invulnerable ? 'animate-pulse' : ''}`} style={{ width: spriteSize, height: spriteSize, transition: 'all 0.2s ease-out', filter: 'drop-shadow(0 0 4px hsl(120 70% 50%))', opacity: p2Invulnerable ? 0.5 : 1 }}>{renderPacman2()}</div>}
|
||||
{isPacman2Here && <div className={`drop-shadow-lg ${p2Invulnerable ? 'animate-pulse' : ''}`} style={{ width: spriteSize, height: spriteSize, transition: 'all 0.2s ease-out', filter: 'drop-shadow(0 0 4px hsl(var(--secondary)))', opacity: p2Invulnerable ? 0.5 : 1 }}>{renderPacman2()}</div>}
|
||||
{ghostIndex !== -1 && !isPacmanHere && !isPacman2Here && <div style={{ width: spriteSize, height: spriteSize, transition: 'all 0.2s ease-out' }}>{renderGhost(ghostIndex, ghosts[ghostIndex].eaten)}</div>}
|
||||
{isFruitHere && !isPacmanHere && !isPacman2Here && ghostIndex === -1 && (
|
||||
<div className="animate-bounce text-lg" style={{ fontSize: `${Math.max(cellSize * 0.7, 14)}px` }} title={`${fruit.points} points`}>
|
||||
@@ -764,8 +770,8 @@ const Pacman = () => {
|
||||
<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>
|
||||
<p className="font-pixel text-[8px] text-secondary">P2</p>
|
||||
<p className="font-minecraft text-lg text-secondary" style={{ textShadow: '0 0 10px hsl(var(--secondary))' }}>{score2.toLocaleString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -795,7 +801,7 @@ const Pacman = () => {
|
||||
<div className="flex justify-center gap-2 mt-1">
|
||||
<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>
|
||||
<span className="font-minecraft text-sm text-secondary">{lives2}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
@@ -816,7 +822,7 @@ const Pacman = () => {
|
||||
<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-[8px] text-secondary">P2</p>
|
||||
<p className="font-pixel text-[9px] text-foreground/60">IJKL</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+13
-4
@@ -13,7 +13,7 @@ import GameTouchButton from '@/components/GameTouchButton';
|
||||
import MatrixCursor from '@/components/MatrixCursor';
|
||||
|
||||
const GRID_SIZE = 20;
|
||||
const TICK_SPEED = 120;
|
||||
const TICK_SPEED = 150;
|
||||
const MAX_SCORE = 4294967296;
|
||||
const HIGHSCORE_KEY = 'snake-highscore';
|
||||
|
||||
@@ -78,10 +78,19 @@ const Snake = () => {
|
||||
const maxHeight = window.innerHeight - 420;
|
||||
return Math.min(Math.floor(maxWidth / GRID_SIZE), Math.floor(maxHeight / GRID_SIZE), 20);
|
||||
}
|
||||
if (gameMode === '2p') {
|
||||
return isFullscreen ? 24 : 20;
|
||||
if (isFullscreen) {
|
||||
if (gameMode === '2p') {
|
||||
// Two grids side by side
|
||||
const maxWidth = (window.innerWidth - 100) / 2;
|
||||
const maxHeight = window.innerHeight - 150;
|
||||
return Math.min(Math.floor(maxWidth / GRID_SIZE), Math.floor(maxHeight / GRID_SIZE));
|
||||
}
|
||||
// Single player - fill screen
|
||||
const maxWidth = window.innerWidth - 280;
|
||||
const maxHeight = window.innerHeight - 100;
|
||||
return Math.min(Math.floor(maxWidth / GRID_SIZE), Math.floor(maxHeight / GRID_SIZE));
|
||||
}
|
||||
return isFullscreen ? 32 : 28;
|
||||
return gameMode === '2p' ? 20 : 28;
|
||||
}, [isFullscreen, gameMode]);
|
||||
|
||||
const [cellSize, setCellSize] = useState(getCellSize);
|
||||
|
||||
Reference in New Issue
Block a user