Build out flexbox layout
This commit is contained in:
parent
f80bcf9694
commit
b14ef63a4f
@ -14,7 +14,6 @@
|
|||||||
"formik": "^2.2.6",
|
"formik": "^2.2.6",
|
||||||
"ketchup-react": "^0.1.0",
|
"ketchup-react": "^0.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-bootstrap": "^1.6.0",
|
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.1.2",
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta name="description" content="Web site created using create-react-app" />
|
||||||
name="description"
|
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
@ -24,9 +22,10 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>7 Wonders</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
<!--
|
||||||
@ -39,5 +38,6 @@
|
|||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@ -1,38 +1,14 @@
|
|||||||
.App {
|
.wonder-outer {
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
height: 100vh;
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-link {
|
.wonder-top-bar {
|
||||||
color: #61dafb;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
.wonder-game-wrapper {
|
||||||
from {
|
overflow: auto;
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,10 +4,6 @@ import { addPlayerAction, loadSampleAction, reducer, removePlayerAction, resetAc
|
|||||||
import './App.css'
|
import './App.css'
|
||||||
import Game from '../Game/Game'
|
import Game from '../Game/Game'
|
||||||
import UserSelector from '../UserSelector/UserSelector'
|
import UserSelector from '../UserSelector/UserSelector'
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
|
||||||
import Container from 'react-bootstrap/Container'
|
|
||||||
import Row from 'react-bootstrap/Row'
|
|
||||||
import Col from 'react-bootstrap/Col'
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [state, dispatch] = useKetchup('ws://localhost:4000', reducer)
|
const [state, dispatch] = useKetchup('ws://localhost:4000', reducer)
|
||||||
@ -39,26 +35,20 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Container fluid>
|
return <div className='wonder-outer'>
|
||||||
<Row>
|
<div className='wonder-top-bar'>
|
||||||
<Col>
|
|
||||||
<UserSelector user={user} selectUser={selectUser} removeUser={removeUser} users={state?.players.map(p => p.name) ?? []} locked={state !== undefined && state.stage !== 'starting'} />
|
<UserSelector user={user} selectUser={selectUser} removeUser={removeUser} users={state?.players.map(p => p.name) ?? []} locked={state !== undefined && state.stage !== 'starting'} />
|
||||||
</Col>
|
<div>
|
||||||
</Row>
|
<button onClick={loadSample} disabled={!state}>Load sample</button>
|
||||||
{state
|
|
||||||
? <>
|
|
||||||
<Row>
|
|
||||||
<Col><Game state={state} dispatch={dispatch} playerName={user} /></Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col>
|
|
||||||
<button onClick={loadSample}>Load sample</button>
|
|
||||||
{' '}
|
{' '}
|
||||||
<button onClick={resetGame}>Reset</button>
|
<button onClick={resetGame} disabled={!state}>Reset</button>
|
||||||
</Col>
|
</div>
|
||||||
</Row>
|
</div>
|
||||||
</>
|
<div className='wonder-game-wrapper'>
|
||||||
: <Row><Col>Loading…</Col></Row>
|
{state
|
||||||
|
? <Game state={state} dispatch={dispatch} playerName={user} />
|
||||||
|
: <div>Loading…</div>
|
||||||
}
|
}
|
||||||
</Container>
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,35 @@
|
|||||||
.wonder-civ-outer {
|
.wonder-civ {
|
||||||
|
border: black solid;
|
||||||
|
margin: 1em;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wonder-civ-wonder {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
border: black solid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.wonder-civ-outer ol {
|
.wonder-civ-structs {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.wonder-civ-struct-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.wonder-civ-struct-group {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
width: 12em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wonder-civ-struct {
|
.wonder-civ-struct {
|
||||||
|
border: thin black solid;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.wonder-civ-struct-type-commerce { background-color: yellow; color: black; }
|
.wonder-civ-struct-type-commerce { background-color: yellow; color: black; }
|
||||||
.wonder-civ-struct-type-culture { background-color: blue; color: white; }
|
.wonder-civ-struct-type-culture { background-color: blue; color: white; }
|
||||||
.wonder-civ-struct-type-science { background-color: green; color: white; }
|
.wonder-civ-struct-type-science { background-color: green; color: white; }
|
||||||
.wonder-civ-struct-type-basic-industry { background-color: brown; color: white; }
|
.wonder-civ-struct-type-basic-industry { background-color: brown; color: white; }
|
||||||
.wonder-civ-struct-type-advanced-industry { background-color: gray; color: black; }
|
.wonder-civ-struct-type-advanced-industry { background-color: lightgray; color: black; }
|
||||||
.wonder-civ-struct-type-guild { background-color: purple; color: white; }
|
.wonder-civ-struct-type-guild { background-color: purple; color: white; }
|
||||||
.wonder-civ-struct-type-military { background-color: red; color: white; }
|
.wonder-civ-struct-type-military { background-color: red; color: white; }
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Player, playerStats, Resource, Science, Structure, structureTypes } from 'wonders-common'
|
import { Player, playerStats, Resource, Science, Structure, StructureType, wonders } from 'wonders-common'
|
||||||
import fill from 'lodash/fill'
|
import fill from 'lodash/fill'
|
||||||
import './Civ.css'
|
import './Civ.css'
|
||||||
import Container from 'react-bootstrap/Container'
|
|
||||||
import Row from 'react-bootstrap/Row'
|
type DisplayStyle = 'player' | 'neighbor' | 'distant'
|
||||||
import Col from 'react-bootstrap/Col'
|
|
||||||
|
|
||||||
const resEmojis = new Map<Resource, string>([
|
const resEmojis = new Map<Resource, string>([
|
||||||
['brick', '🧱'],
|
['brick', '🧱'],
|
||||||
@ -20,6 +19,21 @@ const sciEmojis = new Map<Science, string>([
|
|||||||
['engineering', '⚙️'],
|
['engineering', '⚙️'],
|
||||||
['research', '📚'],
|
['research', '📚'],
|
||||||
])
|
])
|
||||||
|
const structTypeLayout = new Map<DisplayStyle, StructureType[][]>([
|
||||||
|
['player', [
|
||||||
|
['basic industry'], ['advanced industry'], ['military'], ['science'], ['commerce'], ['guild'], ['culture'],
|
||||||
|
]],
|
||||||
|
['neighbor', [
|
||||||
|
['basic industry', 'advanced industry'],
|
||||||
|
['military', 'science'],
|
||||||
|
['commerce', 'guild', 'culture'],
|
||||||
|
]],
|
||||||
|
['distant', [
|
||||||
|
['basic industry', 'advanced industry', 'military'],
|
||||||
|
['science', 'commerce', 'guild', 'culture'],
|
||||||
|
]],
|
||||||
|
])
|
||||||
|
|
||||||
const wonderBgExts = ['jpg', 'webp']
|
const wonderBgExts = ['jpg', 'webp']
|
||||||
|
|
||||||
function structurePeek(struct: Structure): string {
|
function structurePeek(struct: Structure): string {
|
||||||
@ -40,29 +54,32 @@ function structurePeek(struct: Structure): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Civ({ player, civStyle }: { player: Player, civStyle: 'player' | 'neighbor' | 'compact' }) {
|
export default function Civ({ player, displayStyle }: { player: Player, displayStyle: DisplayStyle }) {
|
||||||
const pStats = useMemo(() => playerStats(player), [player])
|
const pStats = useMemo(() => playerStats(player), [player])
|
||||||
|
|
||||||
const outerStyle: React.CSSProperties = player.wonder === undefined ? {} : {
|
const wonderBgImage = ['linear-gradient(to left, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.75))', ...wonderBgExts.map(ext => `url("/assets/wonders/${player.wonder}.${ext}")`)].join(', ')
|
||||||
backgroundImage: ['linear-gradient(to left, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.75))', ...wonderBgExts.map(ext => `url("/assets/wonders/${player.wonder}.${ext}")`)].join(', '),
|
const wonder = player.wonder ? wonders.get(player.wonder) : undefined
|
||||||
}
|
|
||||||
|
|
||||||
return <Container fluid className='wonder-civ-outer' style={outerStyle}>
|
return <div className='wonder-civ'>
|
||||||
<Row>
|
<div>{player.name}</div>
|
||||||
<Col>{player.name}{player.wonder && ` • ${player.wonder}`}</Col>
|
<div className='wonder-civ-wonder' style={{ backgroundImage: wonderBgImage }}>
|
||||||
</Row>
|
<div>{player.wonder}</div>
|
||||||
<Row>
|
<div>{resEmojis.get(wonder!.innateResource)}</div>
|
||||||
{structureTypes.map(type =>
|
</div>
|
||||||
<Col key={type}>
|
<div className='wonder-civ-structs'>
|
||||||
<ol>
|
{structTypeLayout.get(displayStyle)!.map((col, i) =>
|
||||||
|
<div key={i} className='wonder-civ-struct-col'>
|
||||||
|
{col.filter(type => pStats.structObjs.some(s => s.type === type)).map(type =>
|
||||||
|
<ol key={type} className='wonder-civ-struct-group'>
|
||||||
{pStats.structObjs.filter(o => o.type === type).map((s, i) =>
|
{pStats.structObjs.filter(o => o.type === type).map((s, i) =>
|
||||||
<li key={i} className={`wonder-civ-struct wonder-civ-struct-type-${type.replaceAll(' ', '-')}`}>
|
<li key={i} className={`wonder-civ-struct wonder-civ-struct-type-${type.replaceAll(' ', '-')}`}>
|
||||||
{s.name} {structurePeek(s)}
|
{s.name} {structurePeek(s)}
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ol>
|
</ol>
|
||||||
</Col>
|
|
||||||
)}
|
)}
|
||||||
</Row>
|
</div>
|
||||||
</Container>
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
24
packages/wonders-client/src/components/Game/Game.css
Normal file
24
packages/wonders-client/src/components/Game/Game.css
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.wonder-game {
|
||||||
|
background-image: url(world.webp);
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wonder-lobby {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wonder-distant {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.wonder-neighbors {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.wonder-center {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
@ -2,9 +2,8 @@ import { Dispatch } from 'ketchup-react'
|
|||||||
import { Action, chooseWonderAction, maxPlayers, minPlayers, Player, startGameAction, State, structures, wonders } from 'wonders-common'
|
import { Action, chooseWonderAction, maxPlayers, minPlayers, Player, startGameAction, State, structures, wonders } from 'wonders-common'
|
||||||
import Civ from '../Civ/Civ'
|
import Civ from '../Civ/Civ'
|
||||||
import Card from '../Card/Card'
|
import Card from '../Card/Card'
|
||||||
import Row from 'react-bootstrap/Row'
|
|
||||||
import Col from 'react-bootstrap/Col'
|
|
||||||
import { ErrorMessage, Field, Form, Formik } from 'formik'
|
import { ErrorMessage, Field, Form, Formik } from 'formik'
|
||||||
|
import './Game.css'
|
||||||
|
|
||||||
function getDistant<T>(arr: T[], idx: number) {
|
function getDistant<T>(arr: T[], idx: number) {
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
@ -14,14 +13,6 @@ function getDistant<T>(arr: T[], idx: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DistantCivs({ players }: { players: Player[] }) {
|
|
||||||
return <Row>{players.map(p =>
|
|
||||||
<Col key={p.name}>
|
|
||||||
<Civ player={p} civStyle='compact' />
|
|
||||||
</Col>
|
|
||||||
)}</Row>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Game({ state, playerName, dispatch }: { state: State, playerName?: string, dispatch: Dispatch<Action> }) {
|
export default function Game({ state, playerName, dispatch }: { state: State, playerName?: string, dispatch: Dispatch<Action> }) {
|
||||||
const playerIdx: number | undefined = state.players.findIndex(p => p.name === playerName)
|
const playerIdx: number | undefined = state.players.findIndex(p => p.name === playerName)
|
||||||
const player: Player | undefined = state.players[playerIdx]
|
const player: Player | undefined = state.players[playerIdx]
|
||||||
@ -35,34 +26,16 @@ export default function Game({ state, playerName, dispatch }: { state: State, pl
|
|||||||
return state.players.filter(p => p.name !== playerName).map(p => p.wonder).includes(wonder)
|
return state.players.filter(p => p.name !== playerName).map(p => p.wonder).includes(wonder)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player) {
|
let gameElem: JSX.Element
|
||||||
return <DistantCivs players={state.players} />
|
if (!player || !started) {
|
||||||
} else if (started) {
|
gameElem = <div className='wonder-lobby'>
|
||||||
return <>
|
{state.players.map(p =>
|
||||||
<DistantCivs players={started.distant} />
|
<Civ key={p.name} player={p} displayStyle='distant' />
|
||||||
<Row>
|
)}
|
||||||
<Col><Civ player={started.left} civStyle='neighbor' /></Col>
|
</div>
|
||||||
<Col>
|
if (!started) {
|
||||||
<div>{state.age === undefined ? '' : `Age ${state.age + 1} ${state.age % 2 === 0 ? '🔃' : '🔄'}`}</div>
|
gameElem = <>
|
||||||
<div><button>Discards</button></div>
|
{gameElem}
|
||||||
</Col>
|
|
||||||
<Col><Civ player={started.right} civStyle='neighbor' /></Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col><Civ player={player} civStyle='player' /></Col>
|
|
||||||
</Row>
|
|
||||||
<Row>{player.hand?.map(s => structures.get(s)!)?.map(s =>
|
|
||||||
<Col>
|
|
||||||
<Card structure={s} />
|
|
||||||
</Col>
|
|
||||||
)}</Row>
|
|
||||||
</>
|
|
||||||
} else {
|
|
||||||
return <>
|
|
||||||
<Row>
|
|
||||||
<DistantCivs players={state.players} />
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={{ wonder: player.wonder ?? [...wonders.keys()][0] }}
|
initialValues={{ wonder: player.wonder ?? [...wonders.keys()][0] }}
|
||||||
validate={values => {
|
validate={values => {
|
||||||
@ -75,8 +48,8 @@ export default function Game({ state, playerName, dispatch }: { state: State, pl
|
|||||||
}
|
}
|
||||||
return errors
|
return errors
|
||||||
}}
|
}}
|
||||||
onSubmit={({ wonder }) => dispatch(chooseWonderAction(player.name, wonder))}
|
onSubmit={({ wonder }) => dispatch(chooseWonderAction(player.name, wonder))}>
|
||||||
>{() => <Form>
|
<Form>
|
||||||
<button type="submit">Choose wonder</button>
|
<button type="submit">Choose wonder</button>
|
||||||
{' '}
|
{' '}
|
||||||
<Field as="select" name="wonder">
|
<Field as="select" name="wonder">
|
||||||
@ -86,19 +59,40 @@ export default function Game({ state, playerName, dispatch }: { state: State, pl
|
|||||||
</Field>
|
</Field>
|
||||||
{' '}
|
{' '}
|
||||||
<ErrorMessage name="wonder" />
|
<ErrorMessage name="wonder" />
|
||||||
</Form>}
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</Row>
|
<div>
|
||||||
<Row>
|
<button onClick={() => dispatch(startGameAction(state.players.length))}
|
||||||
<Col><button onClick={() => dispatch(startGameAction(state.players.length))}
|
|
||||||
disabled={started !== undefined
|
disabled={started !== undefined
|
||||||
|| state.players.length < minPlayers
|
|| state.players.length < minPlayers
|
||||||
|| state.players.length > maxPlayers
|
|| state.players.length > maxPlayers
|
||||||
|| state.players.some(p => p.wonder === undefined)}>
|
|| state.players.some(p => p.wonder === undefined)}>
|
||||||
Start Game
|
Start Game
|
||||||
</button></Col>
|
</button>
|
||||||
</Row>
|
</div>
|
||||||
{/* TODO Pick wonder */}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
gameElem = <>
|
||||||
|
<div className='wonder-distant'>
|
||||||
|
{started.distant.map(p =>
|
||||||
|
<Civ key={p.name} player={p} displayStyle='distant' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='wonder-neighbors'>
|
||||||
|
<Civ player={started.left} displayStyle='neighbor' />
|
||||||
|
<div className='wonder-center'>
|
||||||
|
<div>{state.age === undefined ? '' : `Age ${state.age + 1} ${state.age % 2 === 0 ? '🔃' : '🔄'}`}</div>
|
||||||
|
<div><button>Discards</button></div>
|
||||||
|
</div>
|
||||||
|
<Civ player={started.right} displayStyle='neighbor' />
|
||||||
|
</div>
|
||||||
|
<Civ player={player} displayStyle='player' />
|
||||||
|
<div>{player.hand?.map(s => structures.get(s)!)?.map((s, i) =>
|
||||||
|
<Card key={i} structure={s} />
|
||||||
|
)}</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className='wonder-game'>{gameElem}</div>
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
packages/wonders-client/src/components/Game/world.webp
Normal file
BIN
packages/wonders-client/src/components/Game/world.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 878 KiB |
@ -1,8 +1,6 @@
|
|||||||
import { ErrorMessage, Field, Form, Formik } from 'formik';
|
import { ErrorMessage, Field, Form, Formik } from 'formik';
|
||||||
import { Dispatch, useState } from 'react';
|
import { Dispatch, useState } from 'react';
|
||||||
import sample from 'lodash/sample'
|
import sample from 'lodash/sample'
|
||||||
import Row from 'react-bootstrap/Row';
|
|
||||||
import Col from 'react-bootstrap/Col';
|
|
||||||
|
|
||||||
const namePlaceholders = [
|
const namePlaceholders = [
|
||||||
'Alexander the Great',
|
'Alexander the Great',
|
||||||
@ -20,9 +18,9 @@ export default function UserSelector({ users, user, selectUser, removeUser, lock
|
|||||||
users: string[], user?: string, selectUser: Dispatch<string | undefined>, removeUser: () => void, locked: boolean
|
users: string[], user?: string, selectUser: Dispatch<string | undefined>, removeUser: () => void, locked: boolean
|
||||||
}) {
|
}) {
|
||||||
const [namePlaceholder] = useState(() => sample(namePlaceholders))
|
const [namePlaceholder] = useState(() => sample(namePlaceholders))
|
||||||
return <Row>
|
return <div>
|
||||||
{user
|
{user
|
||||||
? <Col>Playing as {user} <button onClick={() => selectUser(undefined)}>Change</button> <button onClick={removeUser} disabled={locked}>Remove</button></Col>
|
? <>Playing as {user} <button onClick={() => selectUser(undefined)}>Change</button> <button onClick={removeUser} disabled={locked}>Remove</button></>
|
||||||
: <Formik
|
: <Formik
|
||||||
initialValues={{ newUser: '' }}
|
initialValues={{ newUser: '' }}
|
||||||
validate={values => {
|
validate={values => {
|
||||||
@ -44,5 +42,5 @@ export default function UserSelector({ users, user, selectUser, removeUser, lock
|
|||||||
</Form>}
|
</Form>}
|
||||||
</Formik>
|
</Formik>
|
||||||
}
|
}
|
||||||
</Row>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user