Compare commits

...

5 Commits

Author SHA1 Message Date
a2de2331cf front: Game section sceleton 2023-10-25 18:18:56 +02:00
0c24d8c3ac front: minore updates 2023-10-25 17:00:33 +02:00
b261b45014 front: better CSS selectors 2023-10-25 12:12:11 +02:00
9f4bb9454e front: use ReactRouting to manage Component's contetnt 2023-10-25 10:28:56 +02:00
6c46e8fb98 front: about page 2023-10-25 09:16:15 +02:00
22 changed files with 243 additions and 165 deletions

View File

@ -1,15 +1,11 @@
import './App.css';
import React from 'react'
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom"
import { BrowserRouter, Routes, Route } from "react-router-dom"
import Header from "./components/Header"
import Leaderboard from "./components/Leaderboard"
import Game from "./components/Game"
import GameProposal from './components/Game/Proposal'
import About from "./components/About"
function App() {
@ -18,9 +14,14 @@ function App() {
<Header/>
<div className="Container">
<Routes>
<Route path="/leaderboard" element={<Leaderboard/>} />
{/* https://stackoverflow.com/questions/40541994/multiple-path-names-for-a-same-component-in-react-router */}
<Route path="/game" element={<Game/>} />
<Route path="/game/proposal" element={<GameProposal/>} />
<Route path="/game/proposal" element={<Game/>} />
<Route path="/game/active" element={<Game/>} />
<Route path="/game/archive" element={<Game/>} />
<Route path="/leaderboard" element={<Leaderboard/>} />
<Route path="/about" element={<About/>} />
</Routes>
</div>
</BrowserRouter>

View File

@ -0,0 +1,5 @@
.Leaderboard {
display: flex;
justify-content: center;
align-items: center;
}

View File

@ -0,0 +1,9 @@
import React from "react"
import './index.css';
export default function Leaderboard() {
return <div className="About">
A simple american checkers game<br/>
</div>
};

View File

@ -1,3 +1,11 @@
.board {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/* scale: 15%; */
}
.tile {
border: 1px solid #e4e4e4;
float: left;
@ -10,22 +18,16 @@
margin-top: -1px;
padding: 0;
text-align: center;
}
.black {
.tile.black {
background: lightgray;
}
.board {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/* scale: 15%; */
}
.white:hover {
.tile.white:hover {
background-color:azure;
}
.stone {
font-size: 120%;
}

View File

@ -1,7 +1,7 @@
import './index.css';
import React from 'react';
import { WhiteStone, BlackStone } from '../Stone'
import { WhiteStone, BlackStone } from '../Game/Stone'
export default function Board() {

View File

@ -0,0 +1,14 @@
import './GameHeader.css';
import React from 'react';
import { NavLink } from "react-router-dom";
export default function GameHeader() {
return (
<nav className='game-header'>
<NavLink to="/game/proposal">Proposal</NavLink>
<NavLink to="/game/active">Active</NavLink>
<NavLink to="/game/archive">Archive</NavLink>
</nav>
)
}

View File

@ -40,8 +40,3 @@
padding-left: 50%;
margin-bottom: 7px;
}
.stone {
font-size: 140%;
vertical-align: -3px;
}

View File

@ -0,0 +1,26 @@
import './GameSelector.css';
import React from 'react';
import { useLocation, matchPath } from "react-router";
import { AppData } from "../../context/data"
import Proposal from './GameSelector/GameProposal';
export default function Game() {
const [data] = React.useContext(AppData)
const { pathname } = useLocation();
const isProposalPath = matchPath("/game/proposal/*", pathname);
const isActivelPath = matchPath("/game/active/*", pathname);
const isArchivePath = matchPath("/game/archive/*", pathname);
if (!data.games)
return <div>Loading..</div>
return (
<div className='game-selector'>
{isProposalPath && <Proposal games={data.games} />}
{isActivelPath && <div>TBD #1</div>}
{isArchivePath && <div>TBD #2</div>}
</div>
)
}

View File

@ -0,0 +1,32 @@
import './ProposalSelector.css'
import React from 'react';
import Selectable from './Selectable';
export default function ProposalSelector({ games }) {
const waitForYou = games
.filter(game => game.status === Status.WaitForYou)
.map(game => <Selectable game={game} />)
const WaitForOpponent = games
.filter(game => game.status === Status.WaitForOpponent)
.map(game => <Selectable game={game} />)
return <div className="Container">
<div className="Games">
{waitForYou}
{WaitForOpponent.length > 0 &&
<div className="separator">
waiting for opponent ({WaitForOpponent.length})
</div>
}
{WaitForOpponent}
</div>
</div>
};
const Status = {
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
}

View File

@ -0,0 +1,32 @@
import './ProposalSelector.css'
import React from 'react';
import Selectable from './Selectable';
export default function ProposalSelector({ games }) {
const waitForYou = games
.filter(game => game.status === Status.WaitForYou)
.map(game => <Selectable game={game} />)
const WaitForOpponent = games
.filter(game => game.status === Status.WaitForOpponent)
.map(game => <Selectable game={game} />)
return <div className="Container">
<div className="Games">
{waitForYou}
{WaitForOpponent.length > 0 &&
<div className="separator">
waiting for opponent ({WaitForOpponent.length})
</div>
}
{WaitForOpponent}
</div>
</div>
};
const Status = {
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
}

View File

@ -0,0 +1,30 @@
import React from 'react';
import Selectable from './Selectable';
export default function ProposalSelector({ games }) {
const waitForYou = games
.filter(game => game.status === Status.WaitForYou)
.map(game => <Selectable game={game} />)
const WaitForOpponent = games
.filter(game => game.status === Status.WaitForOpponent)
.map(game => <Selectable game={game} />)
return (
<div className="Games">
{waitForYou}
{WaitForOpponent.length > 0 &&
<div className="separator">
waiting for opponent ({WaitForOpponent.length})
</div>
}
{WaitForOpponent}
</div>
)
}
const Status = {
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
}

View File

@ -0,0 +1,35 @@
.selectable {
border: 1px solid black;
margin-bottom: 5px;
}
.selectable q {
color: gray;
}
.selectable i {
font-size: 70%;
}
/* .Games .li button.action {
display: none;
}
.Games .li:hover button.action {
display: initial;
} */
.separator {
/* width: 20%; */
/* height: 20px; */
border-bottom: 1px dotted black;
text-align: center;
font-size: 50%;
padding-left: 50%;
margin-bottom: 7px;
}
.stone {
vertical-align: -3px;
margin: 3px 3px;
}

View File

@ -0,0 +1,19 @@
import './Selectable.css'
import React from 'react';
import { Stone, oppositeColor } from '../Stone';
export default function Selectable({game}) {
return (
<div className='selectable' key={game.uuid}>
<div className='tiltle'>
{Stone(game.myColor)}
<i>vs</i>
{Stone(oppositeColor(game.myColor))}
{game.opponentName}
</div>
<q>{game.message}</q>
</div>
)
};

View File

@ -1,22 +0,0 @@
import './index.css';
import React from 'react';
// import { NavLink } from "react-router-dom";
// import { AppData } from "../../../context/data"
import GameHeader from '../../GameHeader'
import GameSelector from '../../GameSelector'
import Board from '../../Board'
export default function Proposal() {
// const [data] = React.useContext(AppData)
return <div className="split">
<div className='split left'>
<GameHeader/>
<button>+ Create</button>
<GameSelector/>
</div>
<div className='split right'></div>
<Board/>
</div>
};

View File

@ -0,0 +1,3 @@
.stone {
cursor: default; /* disable 'I beam' cursor change */
}

View File

@ -1,4 +1,4 @@
import './index.css';
import './Stone.css';
import React from 'react';
export function Stone( color ) {
@ -15,11 +15,11 @@ export function Stone( color ) {
}
export function WhiteStone() {
return <span className="white-stone"></span>
return <span className="stone white"></span>
}
export function BlackStone() {
return <span className="black-stone"></span>
return <span className="stone black"></span>
}
export function oppositeColor(color) {

View File

@ -1,7 +1,7 @@
import './index.css';
import React from 'react';
import GameHeader from '../GameHeader'
import GameSelector from '../GameSelector'
import GameHeader from './GameHeader'
import GameSelector from './GameSelector'
import Board from '../Board'
// import { AppData } from "../../context/data"
@ -15,8 +15,9 @@ export default function Game() {
<GameSelector />
</div>
<div className='split right'></div>
<div className='split right'>
<Board />
</div>
</div>
};
}

View File

@ -1,15 +0,0 @@
import './index.css';
import React from 'react';
import { NavLink } from "react-router-dom";
// import { AppData } from "../../context/data"
export default function GameHeader() {
// const [data] = React.useContext(AppData)
return <nav className="game-header">
<NavLink to="/game/proposal">Proposal</NavLink>
<NavLink to="/game/active">Active</NavLink>
<NavLink to="/game/archive">Archive</NavLink>
</nav>
};

View File

@ -1,82 +0,0 @@
import './index.css';
import React from 'react';
import { AppData } from "../../context/data"
export default function Game() {
const [data] = React.useContext(AppData)
if (!data?.games)
return <div>Loading..</div>
// for (const [key, value] of Object.entries(data.games))
// console.log(key, value);
console.log("data.games", data.games)
const waitForYou = data.games
.filter(game => game.status === Status.WaitForYou)
.map(game => {
return <div className="li" key={game.uuid}>
<p>
You {Stone(game.myColor)} <i>vs</i> {game.opponentName} {Stone(oppositeColor(game.myColor))}
<br/>
<q>{game.message}</q>
<br/>
{/* <Accept uuid={game.uuid}/>
<Reject uuid={game.uuid}/> */}
</p>
</div>
});
const WaitForOpponent = data.games
.filter(game => game.status === Status.WaitForOpponent)
.map(game => {
return <div className="li" key={game.uuid}>
<p>
You {Stone(game.myColor)} <i>vs</i> {game.opponentName} {Stone(oppositeColor(game.myColor))}
<br/>
<q>{game.message}</q>
<br/>
{/* <Cancel uuid={game.uuid}/> */}
</p>
</div>
});
return <div className="Container">
<div className="Games">
{waitForYou}
{WaitForOpponent.length > 0 &&
<div className="separator">
waiting for opponent ({WaitForOpponent.length})
</div>
}
{WaitForOpponent}
</div>
</div>
};
const Status = {
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
}
function Stone(color) {
if (color === "WHITE")
return <span className="stone"></span>
if (color === "BLACK")
return <span className="stone"></span>
return <span className="stone">{color}</span>
}
function oppositeColor(color) {
if (color === "WHITE")
return "BLACK"
if (color === "BLACK")
return "WHITE"
return color
}

View File

@ -1,7 +0,0 @@
.white-stone {
cursor: default;
}
.black-stone {
cursor: default;
}