front: basic ui mockup
- more components - more navigation [bugfix] proxy routing
This commit is contained in:
		
							parent
							
								
									375af0798e
								
							
						
					
					
						commit
						8056c38ad5
					
				
							
								
								
									
										5026
									
								
								webapp/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5026
									
								
								webapp/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -2,21 +2,6 @@
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.App-header {
 | 
			
		||||
  background-color: #282c34;
 | 
			
		||||
  min-height: 100vh;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  font-size: calc(10px + 2vmin);
 | 
			
		||||
  color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.App-link {
 | 
			
		||||
  color: #61dafb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Container {
 | 
			
		||||
  margin-top: 25px;
 | 
			
		||||
}
 | 
			
		||||
@ -9,6 +9,7 @@ import {
 | 
			
		||||
import Header from "./components/Header"
 | 
			
		||||
import Leaderboard from "./components/Leaderboard"
 | 
			
		||||
import Game from "./components/Game"
 | 
			
		||||
import GameProposal from './components/Game/Proposal'
 | 
			
		||||
 | 
			
		||||
function App() { 
 | 
			
		||||
 | 
			
		||||
@ -19,6 +20,7 @@ function App() {
 | 
			
		||||
          <Routes>
 | 
			
		||||
            <Route path="/leaderboard" element={<Leaderboard/>} />
 | 
			
		||||
            <Route path="/game" element={<Game/>} />
 | 
			
		||||
            <Route path="/game/proposal" element={<GameProposal/>} />
 | 
			
		||||
          </Routes>
 | 
			
		||||
        </div>
 | 
			
		||||
    </BrowserRouter>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								webapp/src/components/Board/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								webapp/src/components/Board/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
.tile {
 | 
			
		||||
    border: 1px solid #e4e4e4;
 | 
			
		||||
    float: left;
 | 
			
		||||
    font-size: 200%;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    line-height: 34px;
 | 
			
		||||
    height: 34px;
 | 
			
		||||
    width: 34px; 
 | 
			
		||||
    margin-right: -1px;
 | 
			
		||||
    margin-top: -1px;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
   
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.black {
 | 
			
		||||
    background: lightgray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.board {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    /* scale: 15%; */
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.white:hover {
 | 
			
		||||
    background-color:azure;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								webapp/src/components/Board/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								webapp/src/components/Board/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
import './index.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { WhiteStone, BlackStone } from '../Stone' 
 | 
			
		||||
 | 
			
		||||
export default function Board() {
 | 
			
		||||
 | 
			
		||||
  return <div className='board'>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={0} stone={WhiteStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={1} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={2} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={4} stone={WhiteStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={5} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={6} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={7} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={8} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={ 9} stone={WhiteStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={10} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={11} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={12} stone={WhiteStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={13} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={14} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={15} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={16} stone={null} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={17} stone={null} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={18} stone={null} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={19} stone={null} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={20} stone={null} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={21} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={22} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={23} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={24} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={25} stone={BlackStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={26} stone={BlackStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={27} stone={BlackStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={28} stone={BlackStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={29} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={30} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={31} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={32} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function WhiteTile({ id, stone }) {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div 
 | 
			
		||||
      className='tile white'
 | 
			
		||||
      onClick={() => handleClick(id)}
 | 
			
		||||
    >
 | 
			
		||||
      {stone}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function BlackTile() {
 | 
			
		||||
  return <div className='tile black'/>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleClick(i) {
 | 
			
		||||
  console.log("click", i)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								webapp/src/components/Game/Proposal/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								webapp/src/components/Game/Proposal/index.css
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										22
									
								
								webapp/src/components/Game/Proposal/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								webapp/src/components/Game/Proposal/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
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>
 | 
			
		||||
};
 | 
			
		||||
@ -1,47 +1,21 @@
 | 
			
		||||
.GameProposal {
 | 
			
		||||
.split {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.split .left {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 45%;
 | 
			
		||||
    /* max-width: 400px; */
 | 
			
		||||
 | 
			
		||||
  /* height: 100px; */
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .li {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    margin-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .li p {
 | 
			
		||||
    margin: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .li p q {
 | 
			
		||||
    color: gray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .li p i {
 | 
			
		||||
    font-size: 70%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .li button.action {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.GameProposal .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 {
 | 
			
		||||
    font-size: 140%;
 | 
			
		||||
    vertical-align: -3px;
 | 
			
		||||
.split .right {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 55%;
 | 
			
		||||
}
 | 
			
		||||
@ -1,83 +1,22 @@
 | 
			
		||||
import './index.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import {Accept} from './GameProposalAction';
 | 
			
		||||
import Reject from './Reject'
 | 
			
		||||
import Cancel from './GameProposalCancel'
 | 
			
		||||
import GameHeader from '../GameHeader'
 | 
			
		||||
import GameSelector from '../GameSelector'
 | 
			
		||||
import Board from '../Board' 
 | 
			
		||||
 | 
			
		||||
import { AppData } from "../../context/data"
 | 
			
		||||
// import { AppData } from "../../context/data"
 | 
			
		||||
 | 
			
		||||
export default function Game() {
 | 
			
		||||
  const [data] = React.useContext(AppData)
 | 
			
		||||
 | 
			
		||||
  if (data.games == null)
 | 
			
		||||
    return <div>Loading..</div>
 | 
			
		||||
 | 
			
		||||
  // for (const [key, value] of Object.entries(data.games))
 | 
			
		||||
  //   console.log(key, value);
 | 
			
		||||
   
 | 
			
		||||
  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="GameProposal">
 | 
			
		||||
    {waitForYou}
 | 
			
		||||
    {WaitForOpponent.length > 0 && 
 | 
			
		||||
      <div className="separator">
 | 
			
		||||
        waiting for opponent ({WaitForOpponent.length})
 | 
			
		||||
      </div>
 | 
			
		||||
    }
 | 
			
		||||
    {WaitForOpponent}
 | 
			
		||||
  return <div className="split">
 | 
			
		||||
    
 | 
			
		||||
    <div className='split left'>
 | 
			
		||||
      <GameHeader/>
 | 
			
		||||
      <GameSelector/>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div className='split right'></div>
 | 
			
		||||
      <Board/>
 | 
			
		||||
    </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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								webapp/src/components/GameHeader/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								webapp/src/components/GameHeader/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
.game-header {
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
    background-color: lightgrey;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px;
 | 
			
		||||
    color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-header a {
 | 
			
		||||
    color:darkgrey;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .25s ease;
 | 
			
		||||
    margin-left: 5px;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-header .active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    background-color: cadetblue;
 | 
			
		||||
    opacity: 80%;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-header a:hover:not(.active) {
 | 
			
		||||
    color: cadetblue; 
 | 
			
		||||
 | 
			
		||||
    /* box-shadow: 0 1.5px 0 0 currentColor; */
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								webapp/src/components/GameHeader/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								webapp/src/components/GameHeader/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
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>
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										47
									
								
								webapp/src/components/GameSelector/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								webapp/src/components/GameSelector/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
.Games {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .li {
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    margin-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .li p {
 | 
			
		||||
    margin: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .li p q {
 | 
			
		||||
    color: gray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .li p 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 {
 | 
			
		||||
    font-size: 140%;
 | 
			
		||||
    vertical-align: -3px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								webapp/src/components/GameSelector/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								webapp/src/components/GameSelector/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
@ -8,7 +8,7 @@ h1 {
 | 
			
		||||
    height: 1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav {
 | 
			
		||||
.app-header {
 | 
			
		||||
    padding: auto;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
@ -16,18 +16,18 @@ nav {
 | 
			
		||||
    flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav a {
 | 
			
		||||
.app-header a {
 | 
			
		||||
    color: lightgray;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .25s ease;
 | 
			
		||||
    width: 100px; 
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
 | 
			
		||||
    margin-left: 5px;
 | 
			
		||||
    margin-right: 5px; 
 | 
			
		||||
    padding: 0.25rem 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav .active {
 | 
			
		||||
.app-header .active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    background-color: cadetblue;
 | 
			
		||||
@ -35,18 +35,17 @@ nav .active {
 | 
			
		||||
    padding: 0.25rem 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav a:hover:not(.active) {
 | 
			
		||||
.app-header a:hover:not(.active) {
 | 
			
		||||
    color: cadetblue;
 | 
			
		||||
 | 
			
		||||
    box-shadow: 0 1.5px 0 0 currentcolor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[data-darkreader-scheme="dark"] nav a {
 | 
			
		||||
[data-darkreader-scheme="dark"] .app-header a {
 | 
			
		||||
    color: darkslategrey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[data-darkreader-scheme="dark"] nav .active {
 | 
			
		||||
[data-darkreader-scheme="dark"] .app-header .active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    box-shadow: 0 1.5px 0 0 currentcolor;
 | 
			
		||||
}
 | 
			
		||||
@ -2,7 +2,7 @@ import './index.css';
 | 
			
		||||
import './wave.css'
 | 
			
		||||
import React from "react"
 | 
			
		||||
import { NavLink } from "react-router-dom";
 | 
			
		||||
import OfflineToggle from '../OnlineTgl';
 | 
			
		||||
import OnlineToggle from '../OnlineTgl';
 | 
			
		||||
import { AppData } from "../../context/data"
 | 
			
		||||
 | 
			
		||||
export default function Header() {
 | 
			
		||||
@ -10,9 +10,9 @@ export default function Header() {
 | 
			
		||||
 | 
			
		||||
  return <div>
 | 
			
		||||
    <h1>
 | 
			
		||||
      CordaCheckers<OfflineToggle />
 | 
			
		||||
      CordaCheckers<OnlineToggle />
 | 
			
		||||
    </h1>
 | 
			
		||||
    <nav>
 | 
			
		||||
    <nav className='app-header'>
 | 
			
		||||
      <NavLink to="/leaderboard" className={data.leaderboardFetching && "woble"}>
 | 
			
		||||
        <span>L</span>
 | 
			
		||||
        <span>e</span>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								webapp/src/components/Stone/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webapp/src/components/Stone/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
.white-stone {
 | 
			
		||||
    cursor: default;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.black-stone {
 | 
			
		||||
    cursor: default;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								webapp/src/components/Stone/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								webapp/src/components/Stone/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
import './index.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export function Stone( color ) {
 | 
			
		||||
    switch (color) {
 | 
			
		||||
        case WHITE():
 | 
			
		||||
            return WhiteStone()
 | 
			
		||||
 | 
			
		||||
        case BLACK():
 | 
			
		||||
            return BlackStone()
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            console.warn("Unknown color: ", color)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WhiteStone() {
 | 
			
		||||
    return <span className="white-stone">⛀</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BlackStone() {
 | 
			
		||||
    return <span className="black-stone">⛂</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function oppositeColor(color) {
 | 
			
		||||
    if (color === WHITE())
 | 
			
		||||
        return BLACK()
 | 
			
		||||
 | 
			
		||||
    if (color === BLACK())
 | 
			
		||||
        return WHITE()
 | 
			
		||||
 | 
			
		||||
    return color
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WHITE() {
 | 
			
		||||
    return "WHITE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BLACK() {
 | 
			
		||||
    return "BLACK"
 | 
			
		||||
}
 | 
			
		||||
@ -12,8 +12,8 @@ export const AppDataProvider = ({ children }) => {
 | 
			
		||||
 | 
			
		||||
  const [data, dispatchData] = React.useReducer(reducer, initialState)
 | 
			
		||||
 | 
			
		||||
  const [games,       gamesFetching       ] = Poll('api/gamestate'  , 30, data.offlineMode)
 | 
			
		||||
  const [leaderboard, leaderboardFetching ] = Poll('api/leaderboard', 60, data.offlineMode)
 | 
			
		||||
  const [games,       gamesFetching       ] = Poll('/api/gamestate'  , 30, data.offlineMode)
 | 
			
		||||
  const [leaderboard, leaderboardFetching ] = Poll('/api/leaderboard', 60, data.offlineMode)
 | 
			
		||||
 | 
			
		||||
  data.games         = games
 | 
			
		||||
  data.gamesFetching = gamesFetching
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user