diff options
| author | SOGYO\bvdoord <bvdoord@sogyo.nl> | 2021-01-26 11:22:58 +0100 |
|---|---|---|
| committer | SOGYO\bvdoord <bvdoord@sogyo.nl> | 2021-01-26 11:22:58 +0100 |
| commit | f382ec567e1292cedee7c01e721ddc38bdc4dc4e (patch) | |
| tree | 3012b3343d24c4d52f4370ca1f2efc4c78dbd84f /client/src | |
| parent | 9fb9913bc5ccc49d738481fa71c5ba75c43ed532 (diff) | |
Front-end met Snowpack toegevoegd
Diffstat (limited to 'client/src')
| -rw-r--r-- | client/src/About/About.tsx | 12 | ||||
| -rw-r--r-- | client/src/App.css | 9 | ||||
| -rw-r--r-- | client/src/App.tsx | 29 | ||||
| -rw-r--r-- | client/src/Header/Header.css | 30 | ||||
| -rw-r--r-- | client/src/Header/Header.tsx | 20 | ||||
| -rw-r--r-- | client/src/Header/logo.jpg | bin | 0 -> 5184 bytes | |||
| -rw-r--r-- | client/src/Mancala/Mancala.css | 1 | ||||
| -rw-r--r-- | client/src/Mancala/Mancala.tsx | 24 | ||||
| -rw-r--r-- | client/src/Mancala/Play.css | 1 | ||||
| -rw-r--r-- | client/src/Mancala/Play.tsx | 17 | ||||
| -rw-r--r-- | client/src/Mancala/StartGame.css | 10 | ||||
| -rw-r--r-- | client/src/Mancala/StartGame.tsx | 74 | ||||
| -rw-r--r-- | client/src/gameState.ts | 19 | ||||
| -rw-r--r-- | client/src/index.tsx | 15 |
14 files changed, 261 insertions, 0 deletions
diff --git a/client/src/About/About.tsx b/client/src/About/About.tsx new file mode 100644 index 0000000..e7a9c69 --- /dev/null +++ b/client/src/About/About.tsx @@ -0,0 +1,12 @@ +import React from "react"; + +export function About() { + return <div> + <h2>Mancala</h2> + <p> + Mancala is one of the oldest known board games. It has many different variations and is known under several different names. + The objective of the game is obtaining as many stones, beads or seeds as possible. + It is a game of skill that does not rely on any sort of randomness, making it similar to chess. + </p> + </div> +}
\ No newline at end of file diff --git a/client/src/App.css b/client/src/App.css new file mode 100644 index 0000000..8eebe3a --- /dev/null +++ b/client/src/App.css @@ -0,0 +1,9 @@ +body { + margin: 0px; + padding: 0px; + background-color: #eeeeee; +} + +.main-content { + padding: 8px; +}
\ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 0000000..edd9504 --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; +import { Header } from "./Header/Header"; +import { About } from "./About/About"; +import { Mancala } from "./Mancala/Mancala"; +import "./App.css"; + +export function App() { + return ( + <Router> + {/* The header with navigation options is always on top of every page */} + <Header /> + + <div className="main-content"> + <Switch> + {/* If the user goes to the url /about, show the about page */} + <Route path="/about"> + <About /> + </Route> + + {/* If the user goes to any other url, show the play page */} + <Route path="/"> + <Mancala /> + </Route> + </Switch> + </div> + </Router> + ) +}
\ No newline at end of file diff --git a/client/src/Header/Header.css b/client/src/Header/Header.css new file mode 100644 index 0000000..6744f32 --- /dev/null +++ b/client/src/Header/Header.css @@ -0,0 +1,30 @@ +.main-header { + background-color: white; + color: green; + font-size: 2rem; + margin-bottom: 8px; +} + +.main-navigation { + display: flex; + justify-content: space-around; + align-items: center; + background-color: green; + font-size: 1.3rem; + height: 45px; +} + +.main-navigation a { + color: white; + text-decoration: none; +} + +.main-header div { + display: flex; + align-items: center; +} + +.main-header img { + height: 50px; + margin: 6px; +}
\ No newline at end of file diff --git a/client/src/Header/Header.tsx b/client/src/Header/Header.tsx new file mode 100644 index 0000000..9f96d0c --- /dev/null +++ b/client/src/Header/Header.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import "./Header.css"; +import urlLogo from "./logo.jpg"; + +/** + * A Header component with a Sogyo logo, the name of the application and several links to different pages + */ +export function Header() { + return <header className="main-header"> + <div> + <img src={urlLogo} /> + Mancala + </div> + <div className="main-navigation"> + <Link to="/">Play</Link> + <Link to="/about">About</Link> + </div> + </header> +}
\ No newline at end of file diff --git a/client/src/Header/logo.jpg b/client/src/Header/logo.jpg Binary files differnew file mode 100644 index 0000000..9104922 --- /dev/null +++ b/client/src/Header/logo.jpg diff --git a/client/src/Mancala/Mancala.css b/client/src/Mancala/Mancala.css new file mode 100644 index 0000000..8f73945 --- /dev/null +++ b/client/src/Mancala/Mancala.css @@ -0,0 +1 @@ +/** Add some styles */
\ No newline at end of file diff --git a/client/src/Mancala/Mancala.tsx b/client/src/Mancala/Mancala.tsx new file mode 100644 index 0000000..42c31a2 --- /dev/null +++ b/client/src/Mancala/Mancala.tsx @@ -0,0 +1,24 @@ +import React, { useState } from "react"; +import { StartGame } from "./StartGame"; +import { Play } from "./Play"; +import type { GameState } from "../gameState"; +import "./Mancala.css"; + +/** + * The base component for the Mancala game. If there's no active game, the `StartGame` component allows + * users to enter two player names and start a new game. + * If there's an active game this component holds the game state. This game state can be passed as a prop + * to child components as needed. + * + * Child components can modify the game state by calling the setGameState (which they recieve as prop.) + */ +export function Mancala() { + + const [ gameState, setGameState ] = useState<GameState | undefined>(undefined); + + if (!gameState) { + return <StartGame setGameState={setGameState} /> + } + + return <Play gameState={gameState} setGameState={setGameState} /> +}
\ No newline at end of file diff --git a/client/src/Mancala/Play.css b/client/src/Mancala/Play.css new file mode 100644 index 0000000..8f73945 --- /dev/null +++ b/client/src/Mancala/Play.css @@ -0,0 +1 @@ +/** Add some styles */
\ No newline at end of file diff --git a/client/src/Mancala/Play.tsx b/client/src/Mancala/Play.tsx new file mode 100644 index 0000000..3b8ff25 --- /dev/null +++ b/client/src/Mancala/Play.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import type { GameState } from "../gameState"; +import "./Play.css"; + +type PlayProps = { + gameState: GameState; + setGameState(newGameState: GameState): void; +} + +export function Play({ gameState, setGameState }: PlayProps) { + return ( + <div> + <p>{gameState.players[0].name} vs {gameState.players[1].name}</p> + To do... + </div> + ) +}
\ No newline at end of file diff --git a/client/src/Mancala/StartGame.css b/client/src/Mancala/StartGame.css new file mode 100644 index 0000000..3ab5872 --- /dev/null +++ b/client/src/Mancala/StartGame.css @@ -0,0 +1,10 @@ +.startGameButton { + font-size: 2em; + background-color: lightgreen; + border: 2px solid black; +} + +.errorMessage { + height: 1em; + color: red; +}
\ No newline at end of file diff --git a/client/src/Mancala/StartGame.tsx b/client/src/Mancala/StartGame.tsx new file mode 100644 index 0000000..9d5be2c --- /dev/null +++ b/client/src/Mancala/StartGame.tsx @@ -0,0 +1,74 @@ +import React, { useState } from "react"; +import type { GameState } from "../gameState"; +import "./StartGame.css"; + +type StartGameProps = { + setGameState(newGameState: GameState): void; +} + +/** + * Allows the players to enter their name. A name is required for both players. They can't have the same names. + */ +export function StartGame({ setGameState }: StartGameProps) { + + const [errorMessage, setErrorMessage] = useState(""); + const [playerOne, setPlayerOne] = useState(""); + const [playerTwo, setPlayerTwo] = useState(""); + + async function tryStartGame(e: React.FormEvent) { + e.preventDefault(); // Prevent default browser behavior of submitting forms + if (!playerOne) { + setErrorMessage("A name is required for player 1"); + return; + } + if (!playerTwo) { + setErrorMessage("A name is required for player 2"); + return; + } + if (playerOne === playerTwo) { + setErrorMessage("Each player should have a unique name"); + return; + } + setErrorMessage(""); + + try { + const response = await fetch('mancala/api/start', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ nameplayer1: playerOne, nameplayer2: playerTwo }) + }); + + if (response.ok) { + const gameState = await response.json(); + setGameState(gameState); + } else { + console.error(response.statusText); + } + } catch (error) { + console.error(error.toString()); + } + } + + return ( + <form onSubmit={(e) => tryStartGame(e)}> + <input value={playerOne} + placeholder="Player 1 name" + onChange={(e) => setPlayerOne(e.target.value)} + /> + + <input value={playerTwo} + placeholder="Player 2 name" + onChange={(e) => setPlayerTwo(e.target.value)} + /> + + <p className="errorMessage">{errorMessage}</p> + + <button className="startGameButton" type="submit"> + Play Mancala! + </button> + </form> + ) +}
\ No newline at end of file diff --git a/client/src/gameState.ts b/client/src/gameState.ts new file mode 100644 index 0000000..2d5ec3e --- /dev/null +++ b/client/src/gameState.ts @@ -0,0 +1,19 @@ + +export interface GameState { + players: [ Player, Player ]; // a player array contains exactly two Players + gameStatus: { + endOfGame: boolean; + }; +} + +interface Player { + name: string; + pits: Pit[]; + type: "player1" | "player2"; // only "player1" and "player2" are valid options for this string + hasTurn: boolean; +} + +interface Pit { + index: number; + nrOfStones: number; +} diff --git a/client/src/index.tsx b/client/src/index.tsx new file mode 100644 index 0000000..c92ef7e --- /dev/null +++ b/client/src/index.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import ReactDOM from "react-dom"; +import { App } from "./App"; + +ReactDOM.render( + <App/>, + document.getElementById("root") +) + +// Hot Module Replacement (HMR) - Remove this snippet to remove HMR. +// Learn more: https://www.snowpack.dev/#hot-module-replacement +const hotMudleReplacement = import.meta.hot; +if (hotMudleReplacement) { + hotMudleReplacement.accept(); +} |
