Skip to content

Commit

Permalink
Merge pull request #1 from max-programming/feat/choice-page
Browse files Browse the repository at this point in the history
Choice Page
  • Loading branch information
max-programming authored Jun 20, 2024
2 parents 9afd94e + 9c6f7be commit 289d9dd
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 40 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"react": "^18.2.0",
"react-dice-roll": "^1.2.2",
"react-dom": "^18.2.0",
"react-router-dom": "^6.23.1",
"react-use": "^17.5.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 3 additions & 10 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { Provider } from "jotai";
import { Board } from "./components/Board";
import { ludoStore } from "./utils/atoms";
import { DevTools } from "jotai-devtools";
import "jotai-devtools/styles.css";

function App() {
return (
<Provider store={ludoStore}>
<DevTools store={ludoStore} />
<main className="flex items-center justify-center h-screen">
<Board />
</main>
</Provider>
<main className="flex items-center justify-center h-screen">
<Board />
</main>
);
}

Expand Down
8 changes: 5 additions & 3 deletions src/components/DiceView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PlayerColor } from "@/types";
import {
bluePlayerAtom,
colorToAtomMap,
colors,
colorsAtom,
diceValueAtom,
disabledDiceAtom,
greenPlayerAtom,
Expand Down Expand Up @@ -59,6 +59,7 @@ export function DiceView() {
const player = useAtomValue(colorToAtomMap[playerTurn]);
const [, setMoveLogs] = useAtom(moveLogsAtom);
const { pawns } = useAtomValue(colorAtom[playerTurn]);
const colors = useAtomValue(colorsAtom);

function handleRoll(value: number) {
setDiceValue(value);
Expand Down Expand Up @@ -125,7 +126,8 @@ export function DiceView() {

function setNextPlayer() {
setTimeout(() => {
const nextPlayer = colors[(colors.indexOf(playerTurn) + 1) % 4];
const nextPlayer =
colors[(colors.indexOf(playerTurn) + 1) % colors.length];
setPlayerTurn(nextPlayer);
}, 200);
}
Expand Down Expand Up @@ -189,7 +191,7 @@ export function DiceView() {
size={100}
disabled={disabledDice}
onRoll={handleRoll}
cheatValue={cheatNumber}
cheatValue={isCheatMode ? cheatNumber : undefined}
/>
</div>
</motion.div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/InitialHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { cn } from "@/lib/utils";
import { type PlayerColor } from "@/types";
import { PawnPlace } from "./PawnPlace";
import { useAtomValue } from "jotai";
import { playerTurnAtom } from "@/utils/atoms";
import { colorsAtom, playerTurnAtom } from "@/utils/atoms";

interface InitialHomeProps {
playerColor: PlayerColor;
}

export function InitialHome({ playerColor }: InitialHomeProps) {
const playerTurn = useAtomValue(playerTurnAtom);
const playerColors = useAtomValue(colorsAtom);

const colors = {
bg: {
red: "bg-red-500",
Expand All @@ -28,6 +30,7 @@ export function InitialHome({ playerColor }: InitialHomeProps) {
return (
<div
className={cn(
!playerColors.includes(playerColor) && "opacity-50",
"relative size-72 border-none initial_home",
colors.bg[playerColor],
playerTurn === playerColor &&
Expand Down
14 changes: 14 additions & 0 deletions src/components/PageRoutes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Choice } from "@/pages/Choice";
import { GameView } from "@/pages/GameView";
import { BrowserRouter, Route, Routes } from "react-router-dom";

export function PageRoutes() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Choice />} />
<Route path="/game" element={<GameView />} />
</Routes>
</BrowserRouter>
);
}
14 changes: 9 additions & 5 deletions src/components/Pawns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { type PlayerColor } from "@/types";
import {
diceValueAtom,
playerTurnAtom,
colors as playerColors,
disabledDiceAtom,
moveLogsAtom,
colorToAtomMap,
ludoStore,
colorsAtom,
} from "@/utils/atoms";
import { Pawn } from "@/utils/pawn-controller";
import { motion, useMotionValue, useAnimation } from "framer-motion";
import { useAtom, useSetAtom } from "jotai";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { useEffect, useRef } from "react";

interface PawnProps {
Expand Down Expand Up @@ -47,8 +47,9 @@ export function PawnButton({ playerColor, index }: PawnProps) {
const [player, setPlayer] = useAtom(colorToAtomMap[playerColor]);
const [diceNumber, setDiceNumber] = useAtom(diceValueAtom);
const [, setMoveLogs] = useAtom(moveLogsAtom);
const pawnRef = useRef<HTMLButtonElement>(null);
const setDisabledDice = useSetAtom(disabledDiceAtom);
const playerColors = useAtomValue(colorsAtom);
const pawnRef = useRef<HTMLButtonElement>(null);

const controls = useAnimation();
const x = useMotionValue(index % 2 === 0 ? Pawn.STEP : Pawn.STEP * 4);
Expand All @@ -73,7 +74,7 @@ export function PawnButton({ playerColor, index }: PawnProps) {
});
setPlayer((p) => ({ ...p, pawns: [...p.pawns, newPawn] }));

// NEVER FORGET THE CLEANUP OR ELSE STRICT MODE WILL FU
// NEVER FORGET THE CLEANUP
return () => {
setPlayer((p) => ({
...p,
Expand All @@ -86,7 +87,9 @@ export function PawnButton({ playerColor, index }: PawnProps) {
function setNextPlayer() {
setTimeout(() => {
const nextPlayer =
playerColors[(playerColors.indexOf(playerTurn) + 1) % 4];
playerColors[
(playerColors.indexOf(playerTurn) + 1) % playerColors.length
];
setPlayerTurn(nextPlayer);
}, 200);
}
Expand Down Expand Up @@ -186,6 +189,7 @@ export function PawnButton({ playerColor, index }: PawnProps) {
return (
<motion.button
className={cn(
!playerColors.includes(playerColor) && "hidden",
"absolute focus:outline-none pawn",
playerColor === playerTurn ? "z-50" : "z-40",
)}
Expand Down
12 changes: 10 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import { PostHogProvider } from "posthog-js/react";
import { PageRoutes } from "./components/PageRoutes.tsx";
import { Provider } from "jotai";
import { DevTools } from "jotai-devtools";
import { ludoStore } from "./utils/atoms.ts";

import "./index.css";
import "jotai-devtools/styles.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
Expand All @@ -13,7 +18,10 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
person_profiles: "always",
}}
>
<App />
<Provider store={ludoStore}>
<DevTools store={ludoStore} />
<PageRoutes />
</Provider>
</PostHogProvider>
</React.StrictMode>,
);
146 changes: 146 additions & 0 deletions src/pages/Choice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { cn } from "@/lib/utils";
import { PlayerColor } from "@/types";
import { colorsAtom, playerTurnAtom } from "@/utils/atoms";
import { useSetAtom } from "jotai";
import { useState } from "react";
import { useNavigate } from "react-router-dom";

export function Choice() {
const [selectedColor, setSelectedColor] = useState<PlayerColor>("red");
const [numberOfPlayers, setNumberOfPlayers] = useState(4);
const setColors = useSetAtom(colorsAtom);
const setPlayerTurn = useSetAtom(playerTurnAtom);
const navigate = useNavigate();

function chooseColor(color: PlayerColor) {
setSelectedColor(color);
}
function chooseNumberOfPlayers(number: number) {
setNumberOfPlayers(number);
}

function startGame() {
let colors: PlayerColor[] = [];

if (numberOfPlayers === 2) {
if (selectedColor === "red" || selectedColor === "yellow") {
colors = ["red", "yellow"];
}
else {
colors = ["green", "blue"];
}
}
else if (numberOfPlayers === 3) {
if (selectedColor === "red") {
colors = ["red", "green", "yellow"];
}
else if (selectedColor === "green") {
colors = ["green", "yellow", "blue"];
}
else if (selectedColor === "yellow") {
colors = ["yellow", "blue", "red"];
}
else {
colors = ["blue", "red", "green"];
}
}
else {
colors = ["red", "green", "yellow", "blue"];
}
setColors(colors);
setPlayerTurn(pickRandomColor(colors));
}

function pickRandomColor(colors: PlayerColor[]) {
return colors[Math.floor(Math.random() * colors.length)];
}

return (
<main className="flex flex-col items-center justify-center h-screen gap-5">
<div className="flex justify-between gap-12 text-center">
<div>
<h2 className="mb-5 text-3xl font-bold">Choose number of players</h2>
<div className="grid grid-cols-2 gap-4 place-items-center *:transition-colors">
<button
onClick={() => chooseNumberOfPlayers(2)}
className={cn(
"text-xl border rounded-lg size-40 border-gray-950 hover:bg-gray-200",
numberOfPlayers === 2 && "bg-gray-200",
)}
>
2 Players
</button>
<button
onClick={() => chooseNumberOfPlayers(3)}
className={cn(
"text-xl border rounded-lg size-40 border-gray-950 hover:bg-gray-200",
numberOfPlayers === 3 && "bg-gray-200",
)}
>
3 Players
</button>
<button
onClick={() => chooseNumberOfPlayers(4)}
className={cn(
"col-span-2 text-xl border rounded-lg size-40 border-gray-950 hover:bg-gray-200",
numberOfPlayers === 4 && "bg-gray-200",
)}
>
4 Players
</button>
</div>
</div>
<div>
<h2 className="mb-5 text-3xl font-bold">Choose color</h2>
<div className="grid grid-cols-2 gap-4 place-items-center *:transition-colors">
<button
onClick={() => chooseColor("red")}
className={cn(
"text-xl border border-red-700 rounded-lg size-40 hover:bg-red-200",
selectedColor === "red" && "bg-red-200",
)}
>
Red
</button>
<button
onClick={() => chooseColor("green")}
className={cn(
"text-xl border border-green-700 rounded-lg size-40 hover:bg-green-200",
selectedColor === "green" && "bg-green-200",
)}
>
Green
</button>
<button
onClick={() => chooseColor("blue")}
className={cn(
"text-xl border border-blue-700 rounded-lg size-40 hover:bg-blue-200",
selectedColor === "blue" && "bg-blue-200",
)}
>
Blue
</button>
<button
onClick={() => chooseColor("yellow")}
className={cn(
"text-xl border border-yellow-700 rounded-lg size-40 hover:bg-yellow-200",
selectedColor === "yellow" && "bg-yellow-200",
)}
>
Yellow
</button>
</div>
</div>
</div>
<button
onClick={() => {
startGame();
navigate("/game");
}}
className="px-4 py-2 text-xl font-bold text-white bg-blue-500 rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
Start Game
</button>
</main>
);
}
9 changes: 9 additions & 0 deletions src/pages/GameView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Board } from "@/components/Board";

export function GameView() {
return (
<main className="flex items-center justify-center h-screen">
<Board />
</main>
);
}
Loading

0 comments on commit 289d9dd

Please sign in to comment.