diff --git a/src/App.component-integration.test.tsx b/src/App.component-integration.test.tsx index d8b85d9..9436151 100644 --- a/src/App.component-integration.test.tsx +++ b/src/App.component-integration.test.tsx @@ -292,7 +292,7 @@ describe("Component Integration Tests", () => { const muteButton = screen.getByTestId("mute-button"); // Initially unmuted - expect(muteButton).toHaveTextContent("Mute"); + expect(muteButton).toHaveTextContent("πŸ”Š"); // Mute await user.click(muteButton); @@ -300,7 +300,7 @@ describe("Component Integration Tests", () => { await waitFor(() => { expect(mockSetMuted).toHaveBeenCalledWith(true); }); - expect(muteButton).toHaveTextContent("Unmute"); + expect(muteButton).toHaveTextContent("πŸ”‡"); // Audio status indicator should hide expect(screen.queryByText(/Sound enabled/i)).not.toBeInTheDocument(); diff --git a/src/App.css b/src/App.css index 9bf3235..fb945c0 100644 --- a/src/App.css +++ b/src/App.css @@ -1,10 +1,4 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - +/* Animation for logo effects */ .logo { height: 6em; padding: 1.5em; @@ -41,55 +35,6 @@ color: #888; } -.app-container { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem; - width: 100%; - height: 100vh; - margin: 0; - padding: 0; - box-sizing: border-box; - background-color: #0d1117; - color: white; - overflow: hidden; -} - -.app-container h1 { - font-size: 2.5em; - line-height: 1.1; - margin: 0; - color: #646cff; - margin: 10px 0; - font-size: 24px; -} - -.app-container canvas { - border: 2px solid #646cff; - border-radius: 8px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - display: block; - width: 100% !important; - height: calc(100vh - 100px) !important; - max-height: none; - max-width: none; - border: none; -} - -.instructions { - color: #888; - font-style: italic; - margin: 0; - margin: 8px 0; - font-size: 14px; - color: #8b949e; -} - /* Ensure fullscreen across different devices */ html, body, @@ -99,6 +44,7 @@ body, margin: 0; padding: 0; overflow: hidden; + position: fixed; } body, @@ -114,31 +60,36 @@ html { .app-container { width: 100%; height: 100vh; + height: 100dvh; /* Use dynamic viewport height for mobile browsers */ display: flex; flex-direction: column; align-items: center; color: white; + position: relative; + overflow: hidden; } .app-container h1 { - margin: 10px 0; - font-size: 24px; + margin: 5px 0; + font-size: 20px; color: #646cff; + flex-shrink: 0; } .app-container canvas { display: block; width: 100% !important; - height: calc(100vh - 100px) !important; + height: 100% !important; max-height: none !important; max-width: none !important; cursor: crosshair; } .instructions { - margin: 8px 0; - font-size: 14px; + margin: 5px 0; + font-size: 12px; color: #8b949e; + flex-shrink: 0; } /* Animation for pulse effect */ @@ -163,13 +114,46 @@ html { } } -@media (max-width: 900px) { - .app-container { - padding: 1rem; +/* Mobile-specific adjustments */ +@media (max-width: 768px) { + .app-container h1 { + font-size: 16px; + margin: 3px 0; + } + + .instructions { + font-size: 10px; + margin: 3px 0; + } +} + +/* Portrait mode specific adjustments */ +@media (max-width: 768px) and (orientation: portrait) { + .app-container h1 { + font-size: 14px; + margin: 2px 0; + } + + .instructions { + display: none; /* Hide instructions in portrait mode to save space */ + } +} + +/* Landscape mode specific adjustments */ +@media (max-width: 900px) and (orientation: landscape) { + .app-container h1 { + font-size: 16px; + } +} + +/* Very small screens */ +@media (max-height: 600px) { + .app-container h1 { + font-size: 14px; + margin: 2px 0; } - .app-container canvas { - max-width: 100%; - height: auto; + .instructions { + display: none; } } diff --git a/src/App.interaction.test.tsx b/src/App.interaction.test.tsx index 9c4407b..b947699 100644 --- a/src/App.interaction.test.tsx +++ b/src/App.interaction.test.tsx @@ -174,14 +174,14 @@ describe("App Component Interactions", () => { render(); const muteButton = screen.getByTestId("mute-button"); - expect(muteButton).toHaveTextContent("Mute"); + expect(muteButton).toHaveTextContent("πŸ”Š"); await user.click(muteButton); await waitFor(() => { expect(mockSetMuted).toHaveBeenCalledWith(true); }); - expect(muteButton).toHaveTextContent("Unmute"); + expect(muteButton).toHaveTextContent("πŸ”‡"); }); it("should unmute audio when mute button is clicked again", async () => { @@ -201,7 +201,7 @@ describe("App Component Interactions", () => { await waitFor(() => { expect(mockSetMuted).toHaveBeenCalledWith(false); }); - expect(muteButton).toHaveTextContent("Mute"); + expect(muteButton).toHaveTextContent("πŸ”Š"); }); it("should hide audio status when muted", async () => { diff --git a/src/App.test.tsx b/src/App.test.tsx index bdeb8e3..20ebc6c 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -110,7 +110,7 @@ describe("App Component", () => { it("canvas has correct inline styles", () => { render(); const canvasContainer = screen.getByTestId("threejs-canvas-container"); - expect(canvasContainer).toHaveStyle({ width: "100%", height: "600px" }); + expect(canvasContainer).toHaveStyle({ width: "100%", height: "100%" }); }); it("renders all Three.js scene elements", () => { diff --git a/src/App.tsx b/src/App.tsx index fbf399a..cbb949f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,16 +23,20 @@ const OVERLAY_STYLES = { const INSTRUCTIONS_STYLES = { ...OVERLAY_STYLES, - bottom: "80px", + bottom: "10px", left: "50%", transform: "translateX(-50%)", - fontSize: "16px", + fontSize: "14px", textAlign: "center" as const, + maxWidth: "90%", + whiteSpace: "nowrap" as const, + overflow: "hidden", + textOverflow: "ellipsis", }; const AUDIO_STATUS_STYLES = { position: "absolute" as const, - bottom: "40px", + bottom: "35px", left: "50%", transform: "translateX(-50%)", zIndex: 10, @@ -40,7 +44,11 @@ const AUDIO_STATUS_STYLES = { padding: "6px 12px", borderRadius: "8px", color: "#00ff88", - fontSize: "12px", + fontSize: "11px", + maxWidth: "90%", + whiteSpace: "nowrap" as const, + overflow: "hidden", + textOverflow: "ellipsis", }; const VOLUME_CONTROL_STYLES = { @@ -522,44 +530,78 @@ function App(): JSX.Element { return (
-

🎯 Target Shooter

+

🎯 Target Shooter

{/* HUD Overlay for testing - outside canvas */} -
-
-
TIME
-
{gameState.timeLeft}s
+
+
+
TIME
+
{gameState.timeLeft}s
-
-
SCORE
-
{gameState.score}
- {gameState.combo > 0 &&
πŸ”₯ COMBO x{gameState.combo}
} +
+
SCORE
+
{gameState.score}
+ {gameState.combo > 0 &&
πŸ”₯ x{gameState.combo}
}
-
-
LEVEL
-
{gameState.level}
- {gameState.highScore > 0 &&
HIGH: {gameState.highScore}
} +
+
LEVEL
+
{gameState.level}
+ {gameState.highScore > 0 &&
HI: {gameState.highScore}
}
-
-
ACCURACY
-
+
+
ACC
+
{gameState.totalClicks > 0 ? Math.round((gameState.successfulHits / gameState.totalClicks) * 100) : 100}%
-
{gameState.successfulHits}/{gameState.totalClicks}
+
{gameState.successfulHits}/{gameState.totalClicks}
-
-
TARGETS
-
{gameState.targets.length}
+
+
TARGETS
+
{gameState.targets.length}
{/* Game Status and Controls */} -
-
0 ? "#00ff88" : "#ffa500", fontSize: "14px", fontWeight: "bold" }}> +
+
0 ? "#00ff88" : "#ffa500", + fontSize: "12px", + fontWeight: "bold", + whiteSpace: "nowrap" + }}> {gameState.timeLeft <= 0 ? "⏱️ Time's Up!" : gameState.isPlaying ? "🎯 Active" : "⏸️ Paused"}
-
-