Clean up old unused files from example/src
This commit is contained in:
@@ -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,167 +0,0 @@
|
||||
import type { GameMode } from '@vimazing/typing-chud';
|
||||
|
||||
export type ModeTransition = {
|
||||
fromMode: GameMode;
|
||||
threshold: number;
|
||||
targetMode: GameMode;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type ScoreTransition = {
|
||||
scoreThreshold: number;
|
||||
targetMode: GameMode;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type TestScenario = {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
initialMode: GameMode;
|
||||
transitions?: ModeTransition[];
|
||||
scoreTransitions?: ScoreTransition[];
|
||||
};
|
||||
|
||||
export const testScenarios: Record<string, TestScenario> = {
|
||||
scoreBasedProgression: {
|
||||
id: 'scoreBasedProgression',
|
||||
name: 'Score-Based Progression',
|
||||
description: 'Change modes based on score: score 10 → words, score 50 → sentences, score 100 → paragraphs. Tests delayed application until current item completes.',
|
||||
initialMode: 'letters',
|
||||
scoreTransitions: [
|
||||
{
|
||||
scoreThreshold: 10,
|
||||
targetMode: 'words',
|
||||
description: 'At score 10, request switch to words',
|
||||
},
|
||||
{
|
||||
scoreThreshold: 50,
|
||||
targetMode: 'sentences',
|
||||
description: 'At score 50, request switch to sentences',
|
||||
},
|
||||
{
|
||||
scoreThreshold: 100,
|
||||
targetMode: 'paragraphs',
|
||||
description: 'At score 100, request switch to paragraphs',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
progressive: {
|
||||
id: 'progressive',
|
||||
name: 'Progressive Mode Ladder',
|
||||
description: 'Automatically progress through all modes: 10 letters → 10 words → 5 sentences → 3 paragraphs',
|
||||
initialMode: 'letters',
|
||||
transitions: [
|
||||
{
|
||||
fromMode: 'letters',
|
||||
threshold: 10,
|
||||
targetMode: 'words',
|
||||
description: 'After 10 letters, switch to words',
|
||||
},
|
||||
{
|
||||
fromMode: 'words',
|
||||
threshold: 10,
|
||||
targetMode: 'sentences',
|
||||
description: 'After 10 words, switch to sentences',
|
||||
},
|
||||
{
|
||||
fromMode: 'sentences',
|
||||
threshold: 5,
|
||||
targetMode: 'paragraphs',
|
||||
description: 'After 5 sentences, switch to paragraphs',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
lettersOnly: {
|
||||
id: 'lettersOnly',
|
||||
name: 'Letters Only',
|
||||
description: 'Stay in letters mode (baseline)',
|
||||
initialMode: 'letters',
|
||||
transitions: [],
|
||||
},
|
||||
|
||||
wordsOnly: {
|
||||
id: 'wordsOnly',
|
||||
name: 'Words Only',
|
||||
description: 'Start in words mode (baseline)',
|
||||
initialMode: 'words',
|
||||
transitions: [],
|
||||
},
|
||||
|
||||
sentencesOnly: {
|
||||
id: 'sentencesOnly',
|
||||
name: 'Sentences Only',
|
||||
description: 'Start in sentences mode (baseline)',
|
||||
initialMode: 'sentences',
|
||||
transitions: [],
|
||||
},
|
||||
|
||||
paragraphsOnly: {
|
||||
id: 'paragraphsOnly',
|
||||
name: 'Paragraphs Only',
|
||||
description: 'Start in paragraphs mode (baseline)',
|
||||
initialMode: 'paragraphs',
|
||||
transitions: [],
|
||||
},
|
||||
|
||||
rapidTransitions: {
|
||||
id: 'rapidTransitions',
|
||||
name: 'Rapid Transitions',
|
||||
description: 'Quick transitions: 3 letters → 3 words → 2 sentences → 1 paragraph',
|
||||
initialMode: 'letters',
|
||||
transitions: [
|
||||
{
|
||||
fromMode: 'letters',
|
||||
threshold: 3,
|
||||
targetMode: 'words',
|
||||
description: 'After 3 letters, switch to words',
|
||||
},
|
||||
{
|
||||
fromMode: 'words',
|
||||
threshold: 3,
|
||||
targetMode: 'sentences',
|
||||
description: 'After 3 words, switch to sentences',
|
||||
},
|
||||
{
|
||||
fromMode: 'sentences',
|
||||
threshold: 2,
|
||||
targetMode: 'paragraphs',
|
||||
description: 'After 2 sentences, switch to paragraphs',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
backAndForth: {
|
||||
id: 'backAndForth',
|
||||
name: 'Back and Forth',
|
||||
description: 'Oscillate between modes: 5 letters ↔ 5 words ↔ 5 letters',
|
||||
initialMode: 'letters',
|
||||
transitions: [
|
||||
{
|
||||
fromMode: 'letters',
|
||||
threshold: 5,
|
||||
targetMode: 'words',
|
||||
description: 'After 5 letters, switch to words',
|
||||
},
|
||||
{
|
||||
fromMode: 'words',
|
||||
threshold: 5,
|
||||
targetMode: 'letters',
|
||||
description: 'After 5 words, switch back to letters',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export function getScenario(id: string): TestScenario {
|
||||
return testScenarios[id] || testScenarios.progressive;
|
||||
}
|
||||
|
||||
export function getScenarioNames(): { id: string; name: string }[] {
|
||||
return Object.entries(testScenarios).map(([id, scenario]) => ({
|
||||
id,
|
||||
name: scenario.name,
|
||||
}));
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
const MOBILE_BREAKPOINT = 768;
|
||||
|
||||
export function useIsMobile() {
|
||||
const [isMobile, setIsMobile] = React.useState<boolean>(
|
||||
typeof window !== "undefined"
|
||||
? window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`).matches
|
||||
: false
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
||||
|
||||
const onChange = (event: MediaQueryListEvent) => {
|
||||
setIsMobile(event.matches);
|
||||
};
|
||||
|
||||
// Set initial value
|
||||
setIsMobile(mql.matches);
|
||||
|
||||
// Add listener
|
||||
mql.addEventListener("change", onChange);
|
||||
|
||||
// Cleanup
|
||||
return () => mql.removeEventListener("change", onChange);
|
||||
}, []);
|
||||
|
||||
return isMobile;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
import type { GameManager } from "../../src";
|
||||
|
||||
export const useKeyBindings = (gameManager: GameManager) => {
|
||||
useEffect(() => {
|
||||
const handler = (ev: KeyboardEvent) => {
|
||||
// start game
|
||||
if (ev.code === "Space") {
|
||||
ev.preventDefault(); // Prevent button activation
|
||||
if (["waiting", "game-over", "game-won"].includes(gameManager.gameStatus)) {
|
||||
gameManager.clearKeyLog();
|
||||
gameManager.renderBoard();
|
||||
if (gameManager.gameStatus === "game-over" || gameManager.gameStatus === "game-won") {
|
||||
gameManager.quitGame();
|
||||
setTimeout(() => gameManager.startGame(), 0);
|
||||
} else {
|
||||
gameManager.startGame();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore other keys while waiting
|
||||
if (gameManager.gameStatus === "waiting") return;
|
||||
|
||||
// quit
|
||||
if (ev.key === "Escape") {
|
||||
ev.preventDefault();
|
||||
gameManager.quitGame();
|
||||
return;
|
||||
}
|
||||
|
||||
// handle letter and punctuation typing during game
|
||||
if (gameManager.gameStatus === "started") {
|
||||
if (ev.key.length === 1 && /[a-zA-Z.,!? ]/.test(ev.key)) {
|
||||
gameManager.handleTypedLetter(ev.key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handler);
|
||||
return () => window.removeEventListener("keydown", handler);
|
||||
}, [gameManager.gameStatus]);
|
||||
};
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export const useMounted = () => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
return mounted;
|
||||
};
|
||||
Reference in New Issue
Block a user