diff --git a/src/app.jsx b/src/app.jsx index 1f12d13..c8415f1 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -1,5 +1,6 @@ import MainMenu from "./mainMenu"; import Game from "./game"; +import Modal from "./modal"; export default () => { return ( diff --git a/src/game.jsx b/src/game.jsx index 8ad2a06..db21c47 100644 --- a/src/game.jsx +++ b/src/game.jsx @@ -1,4 +1,5 @@ import { useImmer } from "use-immer"; +import { useState } from "react"; import Cross from "../assets/icon-x.svg?react"; import CrossOutline from "../assets/icon-x-outline.svg?react"; @@ -7,10 +8,13 @@ import OvalOutline from "../assets/icon-o-outline.svg?react"; import logo from "../assets/logo.svg"; import restart from "../assets/icon-restart.svg"; +import Modal from "./modal"; + export default () => { const [grid, updateGrid] = useImmer(Array(9).fill("")); - const turn = grid.filter((s) => s == "").length % 2 != 0 ? "X" : "O"; + const [modal, setModal] = useState(false); + const turn = grid.filter((s) => s == "").length % 2 != 0 ? "X" : "O"; const TurnOutline = turn == "X" ? CrossOutline : OvalOutline; const TurnIndicator = turn == "X" ? Cross : Oval; @@ -32,58 +36,85 @@ export default () => { }; return ( - <div className="flex flex-col space-y-4"> - <header className="flex items-center justify-between px-1"> - <div className="flex-1"> - <img src={logo} alt="logo" /> - </div> - <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"> - <TurnIndicator className="size-5" /> - <p className="text-h-xs uppercase">Turn</p> + <> + <div className="flex flex-col space-y-4"> + <header className="flex items-center justify-between px-1"> + <div className="flex-1"> + <img src={logo} alt="logo" /> </div> - </div> - <div className="flex-1"> - <button - onClick={() => updateGrid(() => Array(9).fill(""))} - className="ml-auto flex size-14 items-center justify-center rounded-xl bg-silver-700 inner-shadow-1-silver-900 hover:bg-silver-400" - > - <img src={restart} alt="restart" /> - </button> - </div> - </header> + <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"> + <TurnIndicator className="size-5" /> + <p className="text-h-xs uppercase">Turn</p> + </div> + </div> + <div className="flex-1"> + <button + onClick={() => setModal(true)} + className="ml-auto flex size-14 items-center justify-center rounded-xl bg-silver-700 inner-shadow-1-silver-900 hover:bg-silver-400" + > + <img src={restart} alt="restart" /> + </button> + </div> + </header> - <main className="grid grid-cols-3 grid-rows-3 gap-5"> - {grid.map((symbol, index) => ( + <main className="grid grid-cols-3 grid-rows-3 gap-5"> + {grid.map((symbol, index) => ( + <button + key={index} + disabled={symbol != ""} + 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)} + </button> + ))} + </main> + + <footer className="flex items-center justify-between text-navy-700"> + <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-blue-700"> + <p className="text-base uppercase">X (you)</p> + <p className="text-h-m uppercase">14</p> + </div> + <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-silver-700"> + <p className="text-base uppercase">Ties</p> + <p className="text-h-m uppercase">32</p> + </div> + <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-yellow-700"> + <p className="text-base uppercase">O (cpu)</p> + <p className="text-h-m uppercase">11</p> + </div> + </footer> + </div> + <Modal + isOpen={modal} + className="space-y-8" + onClose={() => { + setModal(false); + }} + > + <h2 className="text-h-l uppercase text-silver-700">Restart game?</h2> + <form + className="flex items-center justify-around text-navy-700" + method="dialog" + > + <button className="rounded-xl bg-silver-700 px-5 py-4 inner-shadow-1-silver-900 hover:bg-silver-400"> + <p className="text-h-xs uppercase">No, cancel</p> + </button> <button - key={index} - disabled={symbol != ""} - 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; - }); + updateGrid(() => Array(9).fill("")); }} + className="rounded-xl bg-yellow-700 px-5 py-4 inner-shadow-1-yellow-900 hover:bg-yellow-400" > - {renderSymbol(symbol)} + <p className="text-h-xs uppercase">Yes, restart</p> </button> - ))} - </main> - - <footer className="flex items-center justify-between text-navy-700"> - <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-blue-700"> - <p className="text-base uppercase">X (you)</p> - <p className="text-h-m uppercase">14</p> - </div> - <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-silver-700"> - <p className="text-base uppercase">Ties</p> - <p className="text-h-m uppercase">32</p> - </div> - <div className="flex h-20 w-36 flex-col items-center justify-center rounded-2xl bg-yellow-700"> - <p className="text-base uppercase">O (cpu)</p> - <p className="text-h-m uppercase">11</p> - </div> - </footer> - </div> + </form> + </Modal> + </> ); }; diff --git a/src/mainMenu.jsx b/src/mainMenu.jsx index b0ab6f5..6dbe016 100644 --- a/src/mainMenu.jsx +++ b/src/mainMenu.jsx @@ -3,7 +3,7 @@ import * as RadioGroup from "@radix-ui/react-radio-group"; import logo from "../assets/logo.svg"; import Cross from "../assets/icon-x.svg?react"; import Oval from "../assets/icon-o.svg?react"; -import { useStore, setPlayerOneSymbol } from "./store.jsx"; +import { useStore, setPlayerOneSymbol } from "./store"; export default () => { const playerOneSymbol = useStore((state) => state.playerOneSymbol); @@ -11,7 +11,7 @@ export default () => { return ( <div className="m-6 flex w-full max-w-lg flex-col items-center space-y-10"> <img src={logo} alt="logo" /> - <div className="inner-shadow-2-navy-900 flex w-full flex-col items-center justify-center rounded-2xl bg-navy-400 p-6"> + <div className="flex w-full flex-col items-center justify-center rounded-2xl bg-navy-400 p-6 inner-shadow-2-navy-900"> <h2 className="mb-6 text-h-xs uppercase text-silver-700"> Pick player 1's mark </h2> @@ -43,10 +43,10 @@ export default () => { </p> </div> <div className="w-full space-y-5"> - <button className="inner-shadow-2-yellow-900 flex w-full items-center justify-center rounded-2xl bg-yellow-700 p-4 hover:bg-yellow-400"> + <button className="flex w-full items-center justify-center rounded-2xl bg-yellow-700 p-4 inner-shadow-2-yellow-900 hover:bg-yellow-400"> <p className="text-h-s uppercase text-navy-700">New game (vs cpu)</p> </button> - <button className="inner-shadow-2-blue-900 flex w-full items-center justify-center rounded-2xl bg-blue-700 p-4 hover:bg-blue-400"> + <button className="flex w-full items-center justify-center rounded-2xl bg-blue-700 p-4 inner-shadow-2-blue-900 hover:bg-blue-400"> <p className="text-h-s uppercase text-navy-700"> New game (vs player) </p> diff --git a/src/modal.jsx b/src/modal.jsx new file mode 100644 index 0000000..8d238e5 --- /dev/null +++ b/src/modal.jsx @@ -0,0 +1,28 @@ +import { useEffect, useRef } from "react"; + +export default ({ isOpen, children, className, onClose }) => { + const ref = useRef(null); + + useEffect(() => { + if (isOpen) { + ref.current.showModal(); + + if (onClose) { + ref.current.addEventListener("close", onClose); + } + } else { + ref.current.close(); + } + }, [isOpen]); + + return ( + <dialog + className="backdrop:bg-black/50 h-64 w-screen max-w-[100vw] bg-navy-700" + ref={ref} + > + <div className="flex h-full w-full items-center justify-center"> + <div className={className}>{children}</div> + </div> + </dialog> + ); +}; diff --git a/tailwind.config.js b/tailwind.config.js index 11299f7..c97370f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -46,6 +46,7 @@ export default { "yellow-900": "#CC8B13", "yellow-700": "#F2B137", "yellow-400": "#FFC860", + black: "#000", }, fontFamily: { sans: ["Outfit", "sans-serif"], @@ -80,7 +81,7 @@ export default { }, ], "h-l": [ - "24px", + "40px", { letterSpacing: "2.5px", fontWeight: "700",