diff --git a/src/App.css b/src/App.css
index da1168b..027e0b2 100644
--- a/src/App.css
+++ b/src/App.css
@@ -2,6 +2,6 @@
display: grid;
place-content: center;
height: 100vh;
- background-color: black;
+ background-color: var(--app-background-color);
}
diff --git a/src/App.tsx b/src/App.tsx
index 6a35175..323fca3 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,5 @@
import './App.css'
+import './mediaQueries.css'
import Arbiter from './components/Arbiter/Arbiter'
// The app component
diff --git a/src/Constants.ts b/src/Constants.ts
index bc64ee0..1c002be 100644
--- a/src/Constants.ts
+++ b/src/Constants.ts
@@ -5,9 +5,6 @@ import { PieceType, TeamType } from './Types'
export const VERTICAL_AXIS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
export const HORIZONTAL_AXIS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
-// Grid Size
-export const GRID_SIZE = 50
-
// InitialBoardState
export const initialBoard: Board = new Board(
[
@@ -87,7 +84,7 @@ export const initialBoard: Board = new Board(
new Piece(new Position(12, 9), PieceType.PAWN, TeamType.GREEN, false),
new Piece(new Position(12, 10), PieceType.PAWN, TeamType.GREEN, false),
],
- 0
+ 1
)
initialBoard.calculateAllMoves()
diff --git a/src/components/Arbiter/Arbiter.tsx b/src/components/Arbiter/Arbiter.tsx
index 394f237..f1659d8 100644
--- a/src/components/Arbiter/Arbiter.tsx
+++ b/src/components/Arbiter/Arbiter.tsx
@@ -4,6 +4,8 @@ import { initialBoard } from '../../Constants'
import { PieceType, TeamType } from '../../Types'
import { Piece, Position } from '../../models'
import { useRef, useState } from 'react'
+import { ChessProvider } from '../context/ChessContext'
+import ChessWrapper from '../ChessWrapper/ChessWrapper'
export default function Arbiter() {
// Declaring the constants
@@ -91,16 +93,19 @@ export default function Arbiter() {
}
// Deciding the type of color of the pieces when opening the modal
- function promotionTeamType() {
- if (promotionPawn?.team === TeamType.RED) {
- return 'r'
- } else if (promotionPawn?.team === TeamType.BLUE) {
- return 'b'
- } else if (promotionPawn?.team === TeamType.YELLOW) {
- return 'y'
- } else if (promotionPawn?.team === TeamType.GREEN) {
- return 'g'
+ function promotionTeamType(): 'r' | 'b' | 'y' | 'g' {
+ if (promotionPawn && promotionPawn.team) {
+ if (promotionPawn.team === TeamType.RED) {
+ return 'r'
+ } else if (promotionPawn.team === TeamType.BLUE) {
+ return 'b'
+ } else if (promotionPawn.team === TeamType.YELLOW) {
+ return 'y'
+ } else if (promotionPawn.team === TeamType.GREEN) {
+ return 'g'
+ }
}
+ return 'r'; // defaulting to red team at initial state
}
// Writing the full name of the winning team
@@ -126,29 +131,29 @@ export default function Arbiter() {
setBoard(initialBoard.clone())
}
-
+
return (
<>
promotePawn(PieceType.ROOK)}
- src={`${basePath}/assets/images/${promotionTeamType()}R.png`}
+ src={`${basePath}assets/images/${promotionTeamType()}R.png`}
alt='Rook'
/>
promotePawn(PieceType.KNIGHT)}
- src={`${basePath}/assets/images/${promotionTeamType()}N.png`}
+ src={`${basePath}assets/images/${promotionTeamType()}N.png`}
alt='Knight'
/>
promotePawn(PieceType.BISHOP)}
- src={`${basePath}/assets/images/${promotionTeamType()}B.png`}
+ src={`${basePath}assets/images/${promotionTeamType()}B.png`}
alt='Bishop'
/>
promotePawn(PieceType.QUEEN)}
- src={`${basePath}/assets/images/${promotionTeamType()}Q.png`}
+ src={`${basePath}assets/images/${promotionTeamType()}Q.png`}
alt='Queen'
/>
@@ -166,7 +171,7 @@ export default function Arbiter() {
{teamNames[team]} |
|
@@ -179,13 +184,16 @@ export default function Arbiter() {
-
+
+
+
+
+
>
)
}
diff --git a/src/components/ChessWrapper/ChessWrapper.css b/src/components/ChessWrapper/ChessWrapper.css
new file mode 100644
index 0000000..f8fcfd1
--- /dev/null
+++ b/src/components/ChessWrapper/ChessWrapper.css
@@ -0,0 +1,81 @@
+.game-layout {
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+ gap: 10px;
+}
+
+.game-layout > .middle-panel {
+ display: flex;
+ gap: 10px;
+}
+
+.game-layout > .panel-area,
+.game-layout > .middle-panel > .panel-area {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.middle-panels > .player-panel {
+ writing-mode: vertical-rl;
+ height: calc(var(--tile-size) * 8);
+ width: 0.5vw;
+ padding: 0 12px;
+}
+
+.game-layout > .panel-area > .player-panel {
+ height: 0.5vw;
+ width: calc(var(--tile-size) * 8);
+ padding: 12px 0;
+}
+
+div#left-panel {
+ transform: rotate(-180deg);
+}
+
+.player-panel {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: calc(var(--tile-size) * 0.1);
+}
+
+.game-display {
+ display: none;
+}
+
+@media all and (max-width: 700px) {
+ /* phone styles here */
+ .game-layout {
+ padding: 4vh 4vw;
+ }
+
+ .player-panel > .player-name {
+ display: none;
+ }
+
+ .middle-panels > .player-panel {
+ padding: 0;
+ width: 5px;
+ border-radius: 1px;
+ }
+
+ .game-layout > .panel-area > .player-panel {
+ padding: 0;
+ height: 5px;
+ border-radius: 1px;
+ }
+
+ .game-display {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .game-display > .currentPlayerDisplay {
+ color: var(--secondary-text-color);
+ padding: 2px 10px;
+ border-radius: calc(1rem + 2px);
+ }
+}
diff --git a/src/components/ChessWrapper/ChessWrapper.tsx b/src/components/ChessWrapper/ChessWrapper.tsx
new file mode 100644
index 0000000..b8272b3
--- /dev/null
+++ b/src/components/ChessWrapper/ChessWrapper.tsx
@@ -0,0 +1,102 @@
+import './ChessWrapper.css'
+import { useChessContext } from '../context/ChessContext'
+import { TeamType } from '../../Types'
+
+type PlayerState = 'active' | 'inactive' | 'lost';
+
+/** Wrapper component for the chess board, holds player panels surrounding the board */
+export default function ChessWrapper({
+ children,
+ loseOrder: lostTeams,
+}: {
+ children: React.ReactNode;
+ loseOrder: TeamType[];
+}) {
+ const { currentPlayer } = useChessContext();
+ const players = [
+ { name: "Red Player", color: "red", id: "r" },
+ { name: "Blue Player", color: "blue", id: "b" },
+ { name: "Yellow Player", color: "yellow", id: "y" },
+ { name: "Green Player", color: "green", id: "g" },
+ ];
+
+ const getPlayerState = (playerId: TeamType): PlayerState => {
+ if (lostTeams.includes(playerId)) return 'lost'
+ return currentPlayer === playerId ? 'active' : 'inactive'
+ }
+
+ const displayBgColor = players.find((p) => p.id === currentPlayer)?.color || 'grey';
+
+ return (
+
+
+
+ {players.find((p) => p.id === currentPlayer)?.name}
+
+
+
+
+ );
+}
+
+interface PlayerPanelProps {
+ name: string
+ color: string
+ playerState: PlayerState
+}
+
+/** Player panel component, holds player name and indicates active player */
+function PlayerPanel({ name, color, playerState }: PlayerPanelProps) {
+ const stateToColorMap = {
+ active: color,
+ inactive: 'grey',
+ lost: '#444',
+ }
+
+ return (
+
+
{`${name} ${playerState === 'lost' ? 'lost' : ''}`}
+
+ )
+}
diff --git a/src/components/Chessboard/Chessboard.css b/src/components/Chessboard/Chessboard.css
index 776b6e4..8e0f55a 100644
--- a/src/components/Chessboard/Chessboard.css
+++ b/src/components/Chessboard/Chessboard.css
@@ -1,19 +1,23 @@
#chessboard {
display: grid;
- grid-template-columns: repeat(14, 50px);
- grid-template-rows: repeat(14, 50px);
- width: 700px;
- height: 700px;
- background-color: black;
+ grid-template-columns: repeat(14, var(--tile-size));
+ grid-template-rows: repeat(14, var(--tile-size));
+ width: calc(var(--tile-size) * 14);
+ height: calc(var(--tile-size) * 14);
+ background-color: var(--app-background-color);
}
.modal {
- position: absolute;
- top: 0px;
- right: 0px;
- bottom: 0px;
- left: 0px;
- z-index: 1000;
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100dvw;
+ height: 100dvh;
+ background-color: rgba(0, 0, 0, 0.75);
+ z-index: 20;
}
.modal.hidden {
@@ -21,21 +25,18 @@
}
.modal > .modal-body {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- left: calc(50% - 350px);
display: flex;
align-items: center;
justify-content: space-around;
- width: 700px;
+ gap: 10px;
+ height: fit-content;
+ width: calc(var(--tile-size) * 14);
background-color: rgba(0, 0, 0, 0.75);
- padding: 20px 0;
}
.modal > .modal-body > img {
- height: 90px;
- padding: 20px;
+ width: 100%;
+ padding: 10px;
border-radius: 50%;
}
@@ -47,19 +48,19 @@
.modal > .modal-body > .checkmate-body {
display: flex;
flex-direction: column;
+ padding: 10px;
gap: 24px;
width: 45%;
}
.modal > .modal-body > .checkmate-body > span {
- font-size: 28px;
- color: white;
+ font-size: 1.5rem;
text-align: center;
}
.modal > .modal-body > .checkmate-body .team {
font-size: 20px;
- color: white;
+ color: var(--secondary-text-color);
}
.modal > .modal-body > .checkmate-body td:nth-child(2) {
@@ -67,12 +68,12 @@
}
.modal > .modal-body > .checkmate-body > button {
- background-color: #779556;
+ background-color: var(--button-background-color);
border: none;
border-radius: 8px;
padding: 16px;
font-size: 28px;
- color: white;
+ color: var(--secondary-text-color);
}
.modal > .modal-body > .checkmate-body > button:hover {
diff --git a/src/components/Chessboard/Chessboard.tsx b/src/components/Chessboard/Chessboard.tsx
index 6164fb6..cd3bf3d 100644
--- a/src/components/Chessboard/Chessboard.tsx
+++ b/src/components/Chessboard/Chessboard.tsx
@@ -1,225 +1,212 @@
-import './Chessboard.css'
-import PlayerName from '../PlayerName/PlayerName'
-import { Piece, Position } from '../../models'
-import Tile from '../Tile/Tile'
-import { useRef, useState } from 'react'
-import { VERTICAL_AXIS, HORIZONTAL_AXIS, GRID_SIZE } from '../../Constants'
+import "./Chessboard.css";
+import { Piece, Position } from "../../models";
+import Tile from "../Tile/Tile";
+import { useEffect, useRef, useState } from "react";
+import { VERTICAL_AXIS, HORIZONTAL_AXIS } from "../../Constants";
import { PieceType, TeamType } from '../../Types'
+import { useChessContext } from "../context/ChessContext";
-// Interface deciding the types
interface Props {
- playMove: (piece: Piece, position: Position) => boolean
- pieces: Piece[]
- whoseTurn: TeamType
- loseOrder: TeamType[]
- isChecked: boolean
+ playMove: (piece: Piece, position: Position) => boolean;
+ pieces: Piece[];
+ loseOrder: TeamType[];
+ isChecked: boolean;
}
-export default function Chessboard({
- playMove,
- pieces,
- whoseTurn,
- loseOrder,
- isChecked,
-}: Props) {
- // Declaring Constants
- const [activePiece, setActivePiece] = useState(null)
- const [grabPosition, setGrabPosition] = useState(
- new Position(-1, -1)
- )
- const [isClicked, setIsClicked] = useState(false)
- const chessboardRef = useRef(null)
- // Function when player grabs a piece
- function grabPiece(e: React.MouseEvent) {
- // Grabbing the pieces off the chessboard
- const chessboard = chessboardRef.current
- const element = e.target as HTMLElement
-
- if (element.classList.contains('chess-piece') && chessboard) {
- const grabX = Math.floor((e.clientX - chessboard.offsetLeft) / GRID_SIZE)
- const grabY = Math.abs(
- Math.abs(
- Math.ceil((e.clientY - chessboard.offsetTop - 700) / GRID_SIZE)
- )
- )
-
- setGrabPosition(new Position(grabX, grabY))
-
- const x = e.clientX - GRID_SIZE / 2
- const y = e.clientY - GRID_SIZE / 2
-
- element.style.position = 'absolute'
- element.style.left = `${x}px`
- element.style.top = `${y}px`
- element.style.zIndex = '10'
-
- setActivePiece(element)
- setIsClicked(false)
- document.body.style.userSelect = 'none'
+export default function Chessboard({ playMove, pieces, loseOrder, isChecked }: Props) {
+
+ // Dynamic grid size calculation
+ const getGridSize = () => {
+ const vw = window.innerWidth * 0.8;
+ const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
+ return window.innerWidth > 768 ? 2.5 * rem : vw / 14;
+ };
+ const GRID_SIZE = getGridSize();
+ const { currentPlayer: whoseTurn } = useChessContext();
+
+ // Piece tracking states
+ const [currentPiece, setCurrentPiece] = useState(null);
+ const [activePieceElement, setActivePieceElement] = useState(null);
+ const [selectedPieceElement, setSelectedPieceElement] = useState(null);
+ const [showPossibleMoves, setShowPossibleMoves] = useState(false);
+
+ // board related states and constants
+ const chessboardRef = useRef(null);
+ const [boardMetrics, setBoardMetrics] = useState({
+ top: 0, left: 0, width: 0, height: 0
+ });
+
+ /** Calculates boundaries of the chessboard */
+ const calculateBoundaries = () => {
+ if (!chessboardRef.current) return null;
+
+ const { left, top, width, height } = boardMetrics;
+ const sidePortionWidth = 3 * GRID_SIZE;
+
+ return {
+ centralRegionLeft: left,
+ centralRegionRight: left + width,
+ centralRegionTop: top + sidePortionWidth,
+ centralRegionBottom: top + height - sidePortionWidth,
+ topBottomRegionLeft: left + sidePortionWidth,
+ topBottomRegionRight: left + width - sidePortionWidth,
+ topRegionBottom: top + sidePortionWidth,
+ bottomRegionTop: top + height - sidePortionWidth,
+ bottom: top + height
+ };
+ };
+
+ // Updates board metrics on resize
+ useEffect(() => {
+ const updateOffset = () => {
+ if (chessboardRef.current) {
+ const rect = chessboardRef.current.getBoundingClientRect();
+ setBoardMetrics({
+ top: rect.top,
+ left: rect.left,
+ width: rect.width,
+ height: rect.height
+ });
+ }
+ };
+
+ updateOffset();
+ window.addEventListener("resize", updateOffset);
+ return () => window.removeEventListener("resize", updateOffset);
+ }, []);
+
+ /** Transforms client position to chessboard grid position coordinates */
+ const calculateGridPosition = (clientX: number, clientY: number) => ({
+ x: Math.floor((clientX - boardMetrics.left) / GRID_SIZE),
+ y: Math.floor((boardMetrics.height - (clientY - boardMetrics.top)) / GRID_SIZE)
+ });
+
+ /* Piece Interaction Event Handling */
+ /** Handles piece grabbing event, loads piece htmlElement, piece object */
+ const grabPiece = (e: React.MouseEvent) => {
+ const element = e.target as HTMLElement;
+ const chessboard = chessboardRef.current;
+
+ if (element.classList.contains("chess-piece") && chessboard) {
+ const { x: grabX, y: grabY } = calculateGridPosition(e.clientX, e.clientY);
+ const x = e.clientX - GRID_SIZE / 2;
+ const y = e.clientY - GRID_SIZE / 2;
+
+ element.style.position = "fixed";
+ element.style.left = `${x}px`;
+ element.style.top = `${y}px`;
+ element.style.zIndex = "100";
+
+ setCurrentPiece(pieces.find(p => p.samePosition(new Position(grabX, grabY))) || null);
+ setActivePieceElement(element);
+ setShowPossibleMoves(true);
+ document.body.style.userSelect = 'none';
}
- }
-
- // Function when player clicks a piece
- function clickPiece(e: React.MouseEvent) {
- const chessboard = chessboardRef.current
- const element = e.target as HTMLElement
-
- if (element.classList.contains('chess-piece') && chessboard) {
- const grabX = Math.floor((e.clientX - chessboard.offsetLeft) / GRID_SIZE)
- const grabY = Math.abs(
- Math.abs(
- Math.ceil((e.clientY - chessboard.offsetTop - 700) / GRID_SIZE)
- )
- )
-
- setGrabPosition(new Position(grabX, grabY))
- setActivePiece(element)
- setIsClicked(true)
+ };
+
+ /** Handles Piece move event, restricts piece movement to insides of chessboard */
+ const movePiece = (e: React.MouseEvent) => {
+ if (activePieceElement && chessboardRef.current) {
+ const boundaries = calculateBoundaries();
+ if (!boundaries) return;
+
+ const x = e.clientX - GRID_SIZE / 2;
+ const y = e.clientY - GRID_SIZE / 2;
+
+ const isInsideValidRegion = (
+ (x > boundaries.centralRegionLeft &&
+ x < boundaries.centralRegionRight &&
+ y > boundaries.centralRegionTop &&
+ y < boundaries.centralRegionBottom) ||
+ (x > boundaries.topBottomRegionLeft &&
+ x < boundaries.topBottomRegionRight &&
+ ((y > boardMetrics.top && y < boundaries.topRegionBottom) ||
+ (y > boundaries.bottomRegionTop && y < boundaries.bottom)))
+ );
+
+ activePieceElement.style.position = "fixed";
+ activePieceElement.style.left = `${x}px`;
+ activePieceElement.style.top = `${y}px`;
+ activePieceElement.style.visibility = isInsideValidRegion ? "visible" : "hidden";
}
- }
-
- // Function when player tries to move a piece
- function movePiece(e: React.MouseEvent) {
- const chessboard = chessboardRef.current
-
- if (activePiece && chessboard) {
- // Declaring constants for restricting the pieces
- const leftX = chessboard.offsetLeft - 4
- const midleftX =
- chessboard.offsetLeft + (chessboard.clientWidth / 14) * 3 - 4
- const topY = chessboard.offsetTop - 4
- const midtopY =
- chessboard.offsetTop + (chessboard.clientHeight / 14) * 3 - 4
- const rightX = chessboard.offsetLeft + chessboard.clientWidth - 46
- const midrightX =
- chessboard.offsetLeft -
- (chessboard.clientWidth / 14) * 3 +
- chessboard.clientWidth -
- 46
- const bottomY = chessboard.offsetTop + chessboard.clientHeight - 46
- const midbottomY =
- chessboard.offsetTop -
- (chessboard.clientHeight / 14) * 3 +
- chessboard.clientHeight -
- 46
- const x = e.clientX - GRID_SIZE / 2
- const y = e.clientY - GRID_SIZE / 2
- activePiece.style.position = 'absolute'
-
- // Restricting the x position
- if (x < leftX) {
- activePiece.style.left = `${leftX}px`
- } else if (x > rightX) {
- activePiece.style.left = `${rightX}px`
- } else {
- activePiece.style.left = `${x}px`
+ };
+
+ /** Handles piece placement event, plays the move, checks for success, reflects the result on chessboard */
+ const dropPiece = (e: React.MouseEvent) => {
+ if (chessboardRef.current && currentPiece) {
+ const targetElement = activePieceElement || selectedPieceElement;
+ if (!targetElement) return;
+
+ const oldPosition = currentPiece.position;
+ const { x: placeX, y: placeY } = calculateGridPosition(e.clientX, e.clientY);
+
+ // Reset piece if dropped in the same position
+ if (oldPosition?.x === placeX && oldPosition?.y === placeY) {
+ resetPiecePosition(targetElement);
+ setSelectedPieceElement(activePieceElement);
+ setActivePieceElement(null);
+ document.body.style.userSelect = 'auto';
+ return;
}
- // Restricting the y position
- if (y < topY) {
- activePiece.style.top = `${topY}px`
- } else if (y > bottomY) {
- activePiece.style.top = `${bottomY}px`
- } else {
- activePiece.style.top = `${y}px`
- }
+ const success = playMove(currentPiece.clone(), new Position(placeX, placeY));
- // Restricting the cutout portions
- if ((x < midleftX && y > midbottomY) || (x < midleftX && y < midtopY)) {
- activePiece.style.left = `${midleftX}px`
- } else if (
- (x > midrightX && y > midbottomY) ||
- (x > midrightX && y < midtopY)
- ) {
- activePiece.style.left = `${midrightX}px`
- }
- }
- }
-
- // Function when player drops a piece
- function dropPiece(e: React.MouseEvent) {
- const chessboard = chessboardRef.current
- // Dropping the pieces on the right grid
- if (activePiece && chessboard) {
- const x = Math.floor((e.clientX - chessboard.offsetLeft) / GRID_SIZE)
- const y = Math.abs(
- Math.ceil((e.clientY - chessboard.offsetTop - 700) / GRID_SIZE)
- )
-
- const currentPiece = pieces.find((p) => p.samePosition(grabPosition))
-
- if (currentPiece) {
- var success = playMove(currentPiece.clone(), new Position(x, y))
-
- if (!success) {
- // Resets the piece position
- activePiece.style.position = 'static'
- activePiece.style.removeProperty('top')
- activePiece.style.removeProperty('left')
- activePiece.style.removeProperty('z-index')
- }
+ if (!success) {
+ resetPiecePosition(targetElement);
}
- setActivePiece(null)
- document.body.style.userSelect = 'auto'
+ setActivePieceElement(null);
+ setShowPossibleMoves(false);
+ document.body.style.userSelect = 'auto';
}
- }
- // Setting the four player chessboard
- let board = []
-
- for (let j = VERTICAL_AXIS.length - 1; j >= 0; j--) {
- for (let i = 0; i < HORIZONTAL_AXIS.length; i++) {
- const num_i = i
- const num_j = j
- const piece = pieces.find((p) => p.samePosition(new Position(i, j)))
- let image = piece ? piece.image : undefined
-
- let currentPiece =
- activePiece != null
- ? pieces.find((p) => p.samePosition(grabPosition))
- : undefined
-
- // For highlighting the attacked pieces
- let highlight = currentPiece?.possibleMoves
- ? currentPiece.possibleMoves.some((p) =>
- p.samePosition(new Position(i, j))
- )
- : false
-
- board.push(
-
- )
+ };
+
+ /** Helper function for resetting piece position back to original place */
+ const resetPiecePosition = (element: HTMLElement) => {
+ element.style.position = "relative";
+ element.style.removeProperty("top");
+ element.style.removeProperty("left");
+ element.style.removeProperty("z-index");
+ };
+
+ /** chessboard constructor */
+ const renderBoard = () => {
+ const board = [];
+ for (let j = VERTICAL_AXIS.length - 1; j >= 0; j--) {
+ for (let i = 0; i < HORIZONTAL_AXIS.length; i++) {
+ const piece = pieces.find(p => p.samePosition(new Position(i, j)));
+ const highlight = showPossibleMoves &&
+ currentPiece?.possibleMoves?.some(p => p.samePosition(new Position(i, j)));
+
+ board.push(
+
+ );
+ }
}
- }
+ return board;
+ };
+
return (
- <>
- {
- if (!isClicked) {
- movePiece(e)
- }
- }}
- onMouseDown={(e) => grabPiece(e)}
- onClick={(e) => clickPiece(e)}
- onMouseUp={(e) => dropPiece(e)}
- id='chessboard'
- ref={chessboardRef}
- >
- {board}
-
-
- >
- )
+
+ {renderBoard()}
+
+ );
}
diff --git a/src/components/PlayerName/PlayerName.css b/src/components/PlayerName/PlayerName.css
deleted file mode 100644
index 670357b..0000000
--- a/src/components/PlayerName/PlayerName.css
+++ /dev/null
@@ -1,39 +0,0 @@
-.playerName {
- padding: 15px;
- border-radius: 20px;
- font-weight: bold;
- position: absolute;
- opacity: 0.4;
-}
-
-.team-blue {
- margin-top: 100px;
- margin-left: 0;
- background-color: rgb(96, 96, 253);
-}
-
-.team-yellow {
- margin-top: 0;
- margin-left: 550px;
- background-color: rgb(255, 255, 88);
-}
-
-.team-red {
- margin-top: 652px;
- margin-left: 36px;
- background-color: rgb(254, 81, 81);
-}
-
-.team-green {
- margin-top: 550px;
- margin-left: 565px;
- background-color: rgb(85, 249, 85);
-}
-
-.player-active {
- opacity: 1;
-}
-
-.player-lost {
- background-color: #eeeeee;
-}
diff --git a/src/components/PlayerName/PlayerName.tsx b/src/components/PlayerName/PlayerName.tsx
deleted file mode 100644
index 1a3a38f..0000000
--- a/src/components/PlayerName/PlayerName.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { TeamType } from '../../Types'
-import './PlayerName.css'
-
-interface Props {
- whoseTurn: TeamType
- lostTeams: TeamType[]
-}
-// Color names for the different players
-export default function PlayerName({ whoseTurn, lostTeams }: Props) {
- return (
- <>
- x)
- .join(' ')}
- >
- Player RED
-
- x)
- .join(' ')}
- >
- Player BLUE
-
- x)
- .join(' ')}
- >
- Player YELLOW
-
- x)
- .join(' ')}
- >
- Player GREEN
-
- >
- )
-}
diff --git a/src/components/Tile/Tile.css b/src/components/Tile/Tile.css
index b67e655..edd9f9b 100644
--- a/src/components/Tile/Tile.css
+++ b/src/components/Tile/Tile.css
@@ -1,21 +1,20 @@
.tile {
display: grid;
place-content: center;
- width: 50px;
- height: 50px;
+ width: var(--tile-size);
+ height: var(--tile-size);
}
.tile img {
- width: 50px;
+ width: var(--tile-size);
}
.tile .chess-piece {
- width: 43px;
- height: 43px;
+ width: var(--chess-piece-size);
+ height: var(--chess-piece-size);
background-repeat: no-repeat;
background-position: center;
- background-size: 43px;
- z-index: 1;
+ background-size: var(--chess-piece-size);
}
.tile .chess-piece:hover {
@@ -40,17 +39,17 @@
.tile-highlight:not(.chess-piece-tile)::before {
content: ' ';
- width: 12px;
- height: 12px;
+ width: var(--tile-highlight-size);
+ height: var(--tile-highlight-size);
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.4);
}
.tile-highlight.chess-piece-tile::before {
- position: absolute;
+ position: fixed;
content: ' ';
- width: 45px;
- height: 45px;
+ width: var(--tile-highlight-chess-piece-size);
+ height: var(--tile-highlight-chess-piece-size);
border: 2.5px solid rgba(0, 0, 0);
border-radius: 50%;
z-index: 2;
diff --git a/src/components/context/ChessContext.tsx b/src/components/context/ChessContext.tsx
new file mode 100644
index 0000000..d6dbe98
--- /dev/null
+++ b/src/components/context/ChessContext.tsx
@@ -0,0 +1,43 @@
+import { createContext, useCallback, useContext, useEffect, useState } from "react";
+import { TeamType } from "../../Types";
+
+interface ChessContextProps {
+ currentPlayer: TeamType;
+ setCurrentPlayerByWhoseTurn: (whoseTurn: TeamType) => void;
+}
+
+export const ChessContext = createContext({
+ currentPlayer: TeamType.RED,
+ setCurrentPlayerByWhoseTurn: (whoseTurn) => {},
+});
+
+/** Provider component for the chess context, provides currentPlayer, interactionMode */
+export function ChessProvider({ whoseTurn, children }: { whoseTurn: TeamType, children: React.ReactNode }) {
+ const [currentPlayer, setCurrentPlayer] = useState(whoseTurn);
+
+ /** memoized function to set the current player by whose turn as input */
+ // fixes the function behavior, function doesnt change on re-render, only changes when input differs
+ const setCurrentPlayerByWhoseTurn = useCallback((whoseTurn: TeamType) => {
+ setCurrentPlayer(whoseTurn);
+ }, []);
+
+ useEffect(() => {
+ setCurrentPlayerByWhoseTurn(whoseTurn)
+ }, [whoseTurn, setCurrentPlayerByWhoseTurn]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+/** custom chess context hook, provides easy access to the chess context */
+export function useChessContext() {
+ return useContext(ChessContext);
+}
diff --git a/src/index.css b/src/index.css
index ec2585e..522997b 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,3 +1,23 @@
+:root {
+ /* strictly global css variables only */
+ --tile-size: 3rem;
+
+ /* size */
+ --chess-piece-size: calc(var(--tile-size) * 0.85);
+ --tile-highlight-size: calc(var(--tile-size) * 0.25);
+ --tile-highlight-chess-piece-size: calc(var(--tile-size) * 0.9);
+
+ /* color palette */
+ --dark-tile-color: #ababab;
+ --light-tile-color: #dcdcdc;
+ --useless-tile-color: black;
+ --checked-tile-gradient: radial-gradient(circle, red 20%, white 80%);
+ --primary-text-color: black;
+ --secondary-text-color: white;
+ --app-background-color: black;
+ --button-background-color: #779556;
+}
+
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
diff --git a/src/mediaQueries.css b/src/mediaQueries.css
new file mode 100644
index 0000000..bad1fcd
--- /dev/null
+++ b/src/mediaQueries.css
@@ -0,0 +1,13 @@
+@media all and (min-width: 700px) {
+ /* tablet landscape and desktop styles here */
+ :root {
+ --tile-size: 2.5rem;
+ }
+}
+
+@media all and (max-width: 700px) {
+ /* phone styles here */
+ :root {
+ --tile-size: calc(80vw / 14);
+ }
+}