working on unified API and major refactoring
This commit is contained in:
+4
-5
@@ -1,8 +1,8 @@
|
||||
import { useGame } from "@vimazing/vim-maze";
|
||||
import { useGame } from "../../src/useGame";
|
||||
import { useKeyBindings } from "./useKeyBindings";
|
||||
import { useMounted } from "./useMounted";
|
||||
import { useIsMobile } from "./useIsMobile";
|
||||
import { GameOverlay } from "./GameOverlay";
|
||||
import '../../src/game.css';
|
||||
|
||||
function App() {
|
||||
const isMobile = useIsMobile();
|
||||
@@ -10,13 +10,12 @@ function App() {
|
||||
const cols = isMobile ? 12 : 32;
|
||||
const rows = isMobile ? 8 : 24;
|
||||
|
||||
const gameManager = useGame(cols, rows, useKeyBindings);
|
||||
const { containerRef, gameStatus, scoreManager } = gameManager;
|
||||
const gameManager = useGame({ cols, rows }, useKeyBindings);
|
||||
const { containerRef, gameStatus } = gameManager;
|
||||
|
||||
return (
|
||||
<div className="relative mx-auto my-4 w-fit" id="maze_container">
|
||||
<div ref={containerRef} className="relative" />
|
||||
{mounted && <GameOverlay gameStatus={gameStatus} scoreManager={scoreManager} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import type { GameStatus } from "@vimazing/vim-maze";
|
||||
import type { UseScoreType } from "@vimazing/vim-maze";
|
||||
import { useIsMobile } from "./useIsMobile";
|
||||
import { MobileGameOverlay } from "./MobileGameOverlay";
|
||||
|
||||
type GameOverlayProps = {
|
||||
gameStatus: GameStatus;
|
||||
scoreManager: UseScoreType;
|
||||
};
|
||||
|
||||
export const GameOverlay = ({ gameStatus, scoreManager }: GameOverlayProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
if (isMobile) return <MobileGameOverlay gameStatus={gameStatus} scoreManager={scoreManager} />
|
||||
|
||||
// 🧠 Only show overlay when the game has ended
|
||||
if (['started', 'hasKey'].includes(gameStatus)) return null;
|
||||
// console.log('gameStatus:', gameStatus)
|
||||
|
||||
return (
|
||||
<GameOverlayContainer>
|
||||
{gameStatus === "waiting" && <GameWaitingContent />}
|
||||
{gameStatus === "game-over" && <GameOverContent />}
|
||||
{gameStatus === "game-won" && <GameWonContent scoreManager={scoreManager} />}
|
||||
</GameOverlayContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameWaitingContent = () => {
|
||||
return (
|
||||
<div
|
||||
className="text-[#c8d3f5] text-[2em] font-mono text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
<div className="flex flex-col gap-10">
|
||||
<p className="text-[3rem]">Press <strong className="text-[#ffc777]">i</strong> to play...</p>
|
||||
<p><strong className="text-[#ffc777]">h</strong>,<strong className="text-[#ffc777]">j</strong>,<strong className="text-[#ffc777]">k</strong>,<strong className="text-[#ffc777]">l</strong> to move around</p>
|
||||
<p>try other vim motions <br /> you're familiar with</p>
|
||||
<p>
|
||||
<strong className="text-[#ffc777]">$</strong>,<strong className="text-[#ffc777]">^</strong>,<strong className="text-[#ffc777]">0</strong>,<strong className="text-[#ffc777]">G</strong>,<strong className="text-[#ffc777]">gg</strong> only valid if <br />
|
||||
the edges are reachable
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameWonContent = ({ scoreManager }: { scoreManager: UseScoreType }) => {
|
||||
const finalScore = scoreManager.finalScore ?? 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="text-[#c8d3f5] text-[2em] grid gap-4 font-mono uppercase text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
<p className="text-[#c3e88d]">Congratulations!</p>
|
||||
<p>Final Score:</p>
|
||||
<p className="text-[#82aaff] text-[2.5em]">{finalScore.toLocaleString()}</p>
|
||||
<p className="text-[#828bb8] text-[0.65em] normal-case">
|
||||
<span className="text-[#c099ff]">min</span>
|
||||
<span className="text-[#c8d3f5]">(</span>
|
||||
<span className="text-[#ff966c]">100000</span>
|
||||
<span className="text-[#c8d3f5]">, (</span>
|
||||
<span className="text-[#82aaff]">optimalTime</span>
|
||||
<span className="text-[#c8d3f5]"> / </span>
|
||||
<span className="text-[#82aaff]">actualTime</span>
|
||||
<span className="text-[#c8d3f5]">) * </span>
|
||||
<span className="text-[#ff966c]">100000</span>
|
||||
<span className="text-[#c8d3f5]">)</span>
|
||||
</p>
|
||||
<p className="text-[#828bb8]">Press <strong className="text-[#ffc777] normal-case">i</strong> to play again</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameOverContent = () => {
|
||||
return (
|
||||
<div
|
||||
className="text-[#ff757f] font-mono uppercase text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
<p className="text-[5em]">Game Over</p>
|
||||
<p className="text-[2em] text-[#828bb8]">Press <strong className="text-[#ffc777] normal-case">i</strong> to play again</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameOverlayContainer = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
absolute inset-0
|
||||
flex justify-center items-center
|
||||
z-40
|
||||
pointer-events-none
|
||||
"
|
||||
style={{
|
||||
backgroundColor: 'rgba(27, 29, 43, 0.75)',
|
||||
backdropFilter: 'blur(1px)'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
import type { GameStatus } from "@vimazing/vim-maze";
|
||||
import type { UseScoreType } from "@vimazing/vim-maze";
|
||||
|
||||
type MobileGameOverlayProps = {
|
||||
gameStatus: GameStatus;
|
||||
scoreManager: UseScoreType;
|
||||
};
|
||||
|
||||
export const MobileGameOverlay = ({ gameStatus, scoreManager }: MobileGameOverlayProps) => {
|
||||
// 🧠 Only show overlay when the game has ended
|
||||
if (['started', 'hasKey'].includes(gameStatus)) return null;
|
||||
// console.log('gameStatus:', gameStatus)
|
||||
|
||||
return (
|
||||
<GameOverlayContainer>
|
||||
{gameStatus === "waiting" && <GameWaitingContent />}
|
||||
{gameStatus === "game-over" && <GameOverContent />}
|
||||
{gameStatus === "game-won" && <GameWonContent scoreManager={scoreManager} />}
|
||||
</GameOverlayContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameWaitingContent = () => {
|
||||
return (
|
||||
<div
|
||||
className="text-[#c8d3f5] text-[1em] font-mono text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
<p className="text-[1.5rem]">Press here to play</p>
|
||||
<p>all the vim motions <br /> available on desktop</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameWonContent = ({ scoreManager }: { scoreManager: UseScoreType }) => {
|
||||
const finalScore = scoreManager.finalScore ?? 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="text-[#c8d3f5] text-[1em] grid gap-4 font-mono uppercase text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
<p className="text-[#c3e88d]">Congratulations!</p>
|
||||
<p>Final Score:</p>
|
||||
<p className="text-[#82aaff] text-[2.5em]">{finalScore.toLocaleString()}</p>
|
||||
<p className="text-[#828bb8] text-[0.65em] normal-case">
|
||||
<span className="text-[#c099ff]">min</span>
|
||||
<span className="text-[#c8d3f5]">(</span>
|
||||
<span className="text-[#ff966c]">100000</span>
|
||||
<span className="text-[#c8d3f5]">, (</span>
|
||||
<span className="text-[#82aaff]">optimalTime</span>
|
||||
<span className="text-[#c8d3f5]"> / </span>
|
||||
<span className="text-[#82aaff]">actualTime</span>
|
||||
<span className="text-[#c8d3f5]">) * </span>
|
||||
<span className="text-[#ff966c]">100000</span>
|
||||
<span className="text-[#c8d3f5]">)</span>
|
||||
</p>
|
||||
<p className="text-[#828bb8]">Press to play again</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameOverContent = () => {
|
||||
return (
|
||||
<div
|
||||
className="text-[#ff757f] text-[5em] font-mono uppercase text-center select-none"
|
||||
style={{ textShadow: "2px 2px 4px rgba(27, 29, 43, 0.9)" }}
|
||||
>
|
||||
Game Over
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GameOverlayContainer = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
absolute inset-0
|
||||
flex justify-center items-center
|
||||
z-40
|
||||
pointer-events-none
|
||||
"
|
||||
style={{
|
||||
backgroundColor: 'rgba(27, 29, 43, 0.75)',
|
||||
backdropFilter: 'blur(1px)'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* === Environment === */
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"jsx": "react-jsx",
|
||||
@@ -8,14 +7,12 @@
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
|
||||
/* === Bundler / Vite === */
|
||||
"noEmit": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"types": ["vite/client"],
|
||||
|
||||
/* === Code Style & Safety === */
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
@@ -23,12 +20,10 @@
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
|
||||
/* === Module Behavior === */
|
||||
"allowImportingTsExtensions": false,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
/* === Path aliases (optional) === */
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@vimazing/vim-maze": ["../dist/index.d.ts"],
|
||||
|
||||
Reference in New Issue
Block a user