Skip to content

Commit b5780cd

Browse files
committed
feat(games): add game modes and typed input for flag guessing
1 parent 253dc20 commit b5780cd

10 files changed

Lines changed: 307 additions & 61 deletions

File tree

src/App.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Detailed from "./components/Main/Detailed";
55
import NotFound from "./components/NotFound";
66
import { useState, useEffect, createContext } from "react";
77
import Game from "./games/Game";
8+
import FlagModeSelect from "./games/FlagModeSelect";
89
import GameDashboard from "./games/GameDashboard";
910
import GameC from "./games/GameC";
1011
import GameHL from "./games/GameHL";
@@ -54,7 +55,8 @@ function App() {
5455
<Route path="/" element={<Home data={data} />} />
5556
<Route path="/country/:id" element={<Detailed data={data} />} />
5657
<Route path="/games" element={<GameDashboard />} />
57-
<Route path="/guesstheflag" element={<Game />} />
58+
<Route path="/guesstheflag" element={<FlagModeSelect />} />
59+
<Route path="/guesstheflag/:mode" element={<Game />} />
5860
<Route path="/guessthecountry" element={<GameC />} />
5961
<Route path="/higherlower" element={<GameHL />} />
6062
<Route path="/worldle" element={<Worldle />} />

src/components/Switch.jsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Switch({ checked, onChange, label }) {
2+
return (
3+
<button
4+
type="button"
5+
onClick={() => onChange(!checked)}
6+
className={`px-3 py-1.5 rounded-full text-sm border transition-all cursor-pointer mx-auto
7+
${checked
8+
? "bg-blue-500 text-white border-blue-500 shadow-md"
9+
: "bg-transparent border-dashed border-black/30 dark:border-white/30 hover:border-solid hover:border-blue-400"
10+
}`}
11+
>
12+
{checked ? "● " : "○ "}{label}
13+
</button>
14+
);
15+
}

src/games/FlagModeSelect.jsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Link, useSearchParams } from "react-router-dom";
2+
import { useState } from "react";
3+
import GameLayout from "./GameLayout";
4+
import Switch from "../components/Switch";
5+
import usePageMeta from "../hooks/usePageMeta";
6+
7+
const MODES = [
8+
{ key: "classic", label: "Classic", desc: "10s per flag, 5 options, skip allowed", icon: "🎯" },
9+
{ key: "endless", label: "Endless", desc: "Infinite flags, one wrong and it's over", icon: "♾️" },
10+
{ key: "speed", label: "Speed Run", desc: "60s total, answer as many as you can", icon: "⚡" },
11+
{ key: "zen", label: "Zen", desc: "No timer, just accuracy", icon: "🧘" },
12+
{ key: "hardcore", label: "Hardcore", desc: "5s, 6 options, no skipping", icon: "💀" },
13+
];
14+
15+
export default function FlagModeSelect() {
16+
const [searchParams] = useSearchParams();
17+
const [typed, setTyped] = useState(false);
18+
const [suggestions, setSuggestions] = useState(true);
19+
20+
const buildLink = (modeKey) => {
21+
const params = new URLSearchParams(searchParams);
22+
if (typed) {
23+
params.set("typed", "true");
24+
if (!suggestions) params.set("noSuggestions", "true");
25+
} else {
26+
params.delete("typed");
27+
params.delete("noSuggestions");
28+
}
29+
const qs = params.toString();
30+
return `/guesstheflag/${modeKey}${qs ? `?${qs}` : ""}`;
31+
};
32+
33+
usePageMeta(
34+
"Where in the world? - Guess the Flag",
35+
"Choose a game mode for the flag guessing game"
36+
);
37+
38+
return (
39+
<GameLayout>
40+
<h1 className="text-2xl font-bold text-center">Guess the Flag</h1>
41+
<p className="text-sm text-center opacity-60">Choose a game mode</p>
42+
43+
<div className="flex flex-col gap-2">
44+
{MODES.map((mode) => (
45+
<Link
46+
key={mode.key}
47+
to={buildLink(mode.key)}
48+
className="border p-3 rounded-lg shadow hover:bg-black/10 dark:hover:bg-white/10 transition-all flex items-center gap-3"
49+
>
50+
<span className="text-2xl">{mode.icon}</span>
51+
<div className="flex flex-col">
52+
<span className="font-semibold">{mode.label}</span>
53+
<small className="opacity-70">{mode.desc}</small>
54+
</div>
55+
</Link>
56+
))}
57+
</div>
58+
59+
<div className="flex flex-col items-center gap-2">
60+
<Switch checked={typed} onChange={setTyped} label="Type answers (no multiple choice)" />
61+
{typed && (
62+
<Switch checked={suggestions} onChange={setSuggestions} label="Show suggestions" />
63+
)}
64+
</div>
65+
</GameLayout>
66+
);
67+
}

0 commit comments

Comments
 (0)