feat(frontend): let the board render at any width
Board components size themselves from a --board-unit CSS variable instead of vw. By default it is 1vw, so the game page looks the same; with the new width prop the same board renders small, e.g. in previews.
This commit is contained in:
parent
85e3fb60f6
commit
9278ed7447
@ -14,12 +14,19 @@ const BoardView: FunctionComponent<{
|
||||
boardViewModel: BoardViewModel;
|
||||
revert: boolean;
|
||||
onPitSelect: (index: number, pit: Pit) => void;
|
||||
}> = ({ game, context, boardId, boardViewModel, revert, onPitSelect }) => {
|
||||
// Width in px, e.g. for previews; by default the board is as wide as the viewport.
|
||||
width?: number;
|
||||
}> = ({ game, context, boardId, boardViewModel, revert, onPitSelect, width }) => {
|
||||
const mancalaGame = game?.mancalaGame;
|
||||
const theme = context.themeManager.theme;
|
||||
|
||||
// Compute pit width based on viewport (each column is 11vw)
|
||||
const pitWidth = typeof window !== "undefined" ? window.innerWidth * 0.11 : 100;
|
||||
// The board is 92 units wide (8 columns of 11 plus padding); all board parts are sized in units.
|
||||
const unit = width !== undefined ? width / 92 : (typeof window !== "undefined" ? window.innerWidth / 100 : 10);
|
||||
const pitWidth = unit * 11;
|
||||
const sizeVariables = {
|
||||
"--board-unit": width !== undefined ? `${unit}px` : "1vw",
|
||||
"--board-spacing": width !== undefined ? `${unit * 0.3}px` : "5px",
|
||||
} as React.CSSProperties;
|
||||
|
||||
const createPitView = (key: any, pit: Pit, pitViewModel: PitViewModel) => (
|
||||
<PitView
|
||||
@ -42,7 +49,7 @@ const BoardView: FunctionComponent<{
|
||||
const player2BankViewModel = boardViewModel.pits[player2BankIndex];
|
||||
|
||||
return (
|
||||
<div className="board" style={{ background: theme.boardColor }}>
|
||||
<div className="board" style={{ background: theme.boardColor, ...sizeVariables }}>
|
||||
<StoreView
|
||||
context={context}
|
||||
pitViewModel={revert ? player2BankViewModel : player1BankViewModel}
|
||||
@ -61,11 +68,11 @@ const BoardView: FunctionComponent<{
|
||||
{revert ? player2Pits : player1Pits}
|
||||
<style jsx>{`
|
||||
.board {
|
||||
padding: 2vw;
|
||||
padding: calc(2 * var(--board-unit));
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 11vw);
|
||||
grid-template-rows: repeat(2, 11vw);
|
||||
border-radius: 3vw;
|
||||
grid-template-columns: repeat(8, calc(11 * var(--board-unit)));
|
||||
grid-template-rows: repeat(2, calc(11 * var(--board-unit)));
|
||||
border-radius: calc(3 * var(--board-unit));
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@ -53,9 +53,9 @@ const PitView: FunctionComponent<PitViewProps> = ({ pitViewModel, context, onCli
|
||||
)}
|
||||
<style jsx>{`
|
||||
.pit {
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border-radius: 10vw;
|
||||
margin: var(--board-spacing);
|
||||
padding: var(--board-spacing);
|
||||
border-radius: calc(10 * var(--board-unit));
|
||||
transition: background-color 0.5s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -67,11 +67,11 @@ const PitView: FunctionComponent<PitViewProps> = ({ pitViewModel, context, onCli
|
||||
}
|
||||
.stone-count {
|
||||
position: absolute;
|
||||
bottom: 1.0vw;
|
||||
bottom: calc(1.0 * var(--board-unit));
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-family: monospace;
|
||||
font-size: 1.5vw;
|
||||
font-size: calc(1.5 * var(--board-unit));
|
||||
font-weight: bold;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@ -7,9 +7,9 @@ const StoneView: FunctionComponent<{ color: string }> = ({ color }) => {
|
||||
<style jsx>{`
|
||||
.stone {
|
||||
margin: 1px;
|
||||
width: 1vw;
|
||||
height: 1vw;
|
||||
border-radius: 10vw;
|
||||
width: calc(1 * var(--board-unit));
|
||||
height: calc(1 * var(--board-unit));
|
||||
border-radius: calc(10 * var(--board-unit));
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@ -34,8 +34,8 @@ const StoreView: FunctionComponent<{
|
||||
</span>
|
||||
<style jsx>{`
|
||||
.store {
|
||||
margin: 5px;
|
||||
border-radius: 10vw;
|
||||
margin: var(--board-spacing);
|
||||
border-radius: calc(10 * var(--board-unit));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -46,10 +46,10 @@ const StoreView: FunctionComponent<{
|
||||
}
|
||||
.store-stone-count-text {
|
||||
position: absolute;
|
||||
bottom: 2vw;
|
||||
bottom: calc(2 * var(--board-unit));
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 2vw;
|
||||
font-size: calc(2 * var(--board-unit));
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
|
||||
@ -166,7 +166,7 @@ not spectators (R4.5).
|
||||
|
||||
### Board size
|
||||
`BoardView` gets an optional `width` (px). All board components size themselves from a CSS variable
|
||||
`--board-unit` (default `1vw`, else `width / 100` px) instead of `vw`, so the same board renders at full width in a
|
||||
`--board-unit` (default `1vw`, else `width / 92` px, the board being 92 units wide) instead of `vw`, so the same board renders at full width in a
|
||||
game and small in previews.
|
||||
|
||||
### Home page (`routes/Home.tsx`)
|
||||
|
||||
@ -17,7 +17,7 @@ Work through the tasks in order; each ends with its tests passing and a commit.
|
||||
unit tests.
|
||||
- [x] 7. **API**: public ids, Bearer auth middleware, `/games/me/active`, `/games/me`, `/games/popular`,
|
||||
`/game/:id` for finished games, live games channel with throttled push; tests.
|
||||
- [ ] 8. **Board size**: `--board-unit` in `BoardView`, `PitView`, `StoreView`, `StoneView`; `width` prop.
|
||||
- [x] 8. **Board size**: `--board-unit` in `BoardView`, `PitView`, `StoreView`, `StoneView`; `width` prop.
|
||||
- [ ] 9. **Home page**: `ActiveGameBanner`, `LiveGamesSection` with live updates, `RecentGamesSection`; lobby
|
||||
rejection message.
|
||||
- [ ] 10. **Live game history**: `MoveList`, review mode with `ReviewBanner` and keyboard, timeout countdown.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user