Basic interactivity
This commit is contained in:
parent
3525d06ed0
commit
9865717012
3 changed files with 38 additions and 20 deletions
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"use-immer": "^0.9.0",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -3232,6 +3233,15 @@
|
||||||
"browserslist": ">= 4.21.0"
|
"browserslist": ">= 4.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-immer": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-/L+enLi0nvuZ6j4WlyK0US9/ECUtV5v9RUbtxnn5+WbtaXYUaOBoKHDNL9I5AETdurQ4rIFIj/s+Z5X80ATyKw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"immer": ">=2.0.0",
|
||||||
|
"react": "^16.8.0 || ^17.0.1 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/use-sync-external-store": {
|
"node_modules/use-sync-external-store": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"use-immer": "^0.9.0",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
47
src/game.jsx
47
src/game.jsx
|
@ -1,33 +1,34 @@
|
||||||
|
import { useImmer } from "use-immer";
|
||||||
|
|
||||||
|
import Cross from "../assets/icon-x.svg?react";
|
||||||
|
import CrossOutline from "../assets/icon-x-outline.svg?react";
|
||||||
|
import Oval from "../assets/icon-o.svg?react";
|
||||||
|
import OvalOutline from "../assets/icon-o-outline.svg?react";
|
||||||
import logo from "../assets/logo.svg";
|
import logo from "../assets/logo.svg";
|
||||||
import restart from "../assets/icon-restart.svg";
|
import restart from "../assets/icon-restart.svg";
|
||||||
|
|
||||||
import Cross from "../assets/icon-x.svg?react";
|
|
||||||
import Oval from "../assets/icon-o.svg?react";
|
|
||||||
import CrossOutline from "../assets/icon-x-outline.svg?react";
|
|
||||||
import OvalOutline from "../assets/icon-o-outline.svg?react";
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const grid = ["", "X", "O", "X", "O", "X", "", "O", "X"];
|
const [grid, updateGrid] = useImmer(Array(9).fill(""));
|
||||||
|
const turn = grid.filter((s) => s == "").length % 2 != 0 ? "X" : "O";
|
||||||
|
|
||||||
|
const TurnOutline = turn == "X" ? CrossOutline : OvalOutline;
|
||||||
|
const TurnIndicator = turn == "X" ? Cross : Oval;
|
||||||
|
|
||||||
const renderSymbol = (symbol) => {
|
const renderSymbol = (symbol) => {
|
||||||
let Component;
|
if (symbol == "") {
|
||||||
let colorClass;
|
let colorClass = turn == "X" ? "text-blue-700" : "text-yellow-700";
|
||||||
|
|
||||||
if (symbol == "X") {
|
|
||||||
Component = Cross;
|
|
||||||
colorClass = "text-blue-700";
|
|
||||||
} else if (symbol == "O") {
|
|
||||||
Component = Oval;
|
|
||||||
colorClass = "text-yellow-700";
|
|
||||||
} else {
|
|
||||||
return (
|
return (
|
||||||
<CrossOutline
|
<TurnOutline
|
||||||
className={`hidden size-16 text-blue-700 group-hover:block`}
|
className={`hidden size-16 group-hover:block ${colorClass}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Component className={`size-16 ${colorClass}`} />;
|
let Symbol = symbol == "X" ? Cross : Oval;
|
||||||
|
let colorClass = symbol == "X" ? "text-blue-700" : "text-yellow-700";
|
||||||
|
|
||||||
|
return <Symbol className={`size-16 ${colorClass}`} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -38,7 +39,7 @@ export default () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="h-14 w-36 rounded-xl bg-navy-400 px-8 py-4 inner-shadow-1-navy-900">
|
<div className="h-14 w-36 rounded-xl bg-navy-400 px-8 py-4 inner-shadow-1-navy-900">
|
||||||
<div className="flex items-center justify-between text-silver-700">
|
<div className="flex items-center justify-between text-silver-700">
|
||||||
<Cross className="size-5" />
|
<TurnIndicator className="size-5" />
|
||||||
<p className="text-h-xs uppercase">Turn</p>
|
<p className="text-h-xs uppercase">Turn</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,10 +51,16 @@ export default () => {
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="grid grid-cols-3 grid-rows-3 gap-5">
|
<main className="grid grid-cols-3 grid-rows-3 gap-5">
|
||||||
{grid.map((symbol) => (
|
{grid.map((symbol, index) => (
|
||||||
<button
|
<button
|
||||||
|
key={index}
|
||||||
disabled={symbol != ""}
|
disabled={symbol != ""}
|
||||||
className="group flex size-36 items-center justify-center rounded-2xl bg-navy-400 inner-shadow-2-navy-900"
|
className="group flex size-36 items-center justify-center rounded-2xl bg-navy-400 inner-shadow-2-navy-900"
|
||||||
|
onClick={() => {
|
||||||
|
updateGrid((grid) => {
|
||||||
|
grid[index] = turn;
|
||||||
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{renderSymbol(symbol)}
|
{renderSymbol(symbol)}
|
||||||
</button>
|
</button>
|
||||||
|
|
Reference in a new issue