Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Choice Page #1

Merged
merged 5 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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