wip
This commit is contained in:
parent
93f207cf12
commit
85c508d02d
10 changed files with 218 additions and 193 deletions
179
src/App.tsx
179
src/App.tsx
|
|
@ -1,25 +1,16 @@
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { socket } from "./socket";
|
import { socket } from "./socket";
|
||||||
import { Object3D, Mesh } from "three";
|
|
||||||
import { Canvas } from "@react-three/fiber";
|
import GameCanvas from "./components/GameCanvas";
|
||||||
import { OrbitControls, useGLTF, PerspectiveCamera } from "@react-three/drei";
|
import { Footer } from "./components/Footer";
|
||||||
import { ConnectionState } from "./components/ConnectionState";
|
|
||||||
import { ConnectionManager } from "./components/ConnectionManager";
|
|
||||||
import { JoinSession } from "./components/JoinSession";
|
import { JoinSession } from "./components/JoinSession";
|
||||||
import { Events } from "./components/Events";
|
|
||||||
import { Game } from "./types/gameTypes";
|
import { Game } from "./types/gameTypes";
|
||||||
import Action from "./components/Action";
|
|
||||||
import CardStack from "./components/CardStackOld";
|
|
||||||
import DepositCards from "./components/DepositCardsOld";
|
|
||||||
import CardCache from "./components/CardCacheOld";
|
|
||||||
import { extractCurrentPlayer } from "./helpers";
|
import { extractCurrentPlayer } from "./helpers";
|
||||||
import PlayArea from "./components/PlayArea";
|
import MessageDisplay from "./components/MessageDisplay";
|
||||||
import Text from "./global/Text";
|
|
||||||
import Button from "./global/Button";
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [isConnected, setIsConnected] = useState(socket.connected);
|
const [isConnected, setIsConnected] = useState(socket.connected);
|
||||||
const [messageEvents, setMessageEvents] = useState<string[]>([]);
|
// const [messageEvents, setMessageEvents] = useState<string[]>([]);
|
||||||
const [session, setSession] = useState("");
|
const [session, setSession] = useState("");
|
||||||
const [clientsInRoom, setClientsInRoom] = useState(0);
|
const [clientsInRoom, setClientsInRoom] = useState(0);
|
||||||
const [gameData, setGameData] = useState<Game | null>(null);
|
const [gameData, setGameData] = useState<Game | null>(null);
|
||||||
|
|
@ -28,20 +19,7 @@ export default function App() {
|
||||||
const showStartGameButton = session !== "" && clientsInRoom >= 2;
|
const showStartGameButton = session !== "" && clientsInRoom >= 2;
|
||||||
const showNextGameButton = gameData?.phase === "new round";
|
const showNextGameButton = gameData?.phase === "new round";
|
||||||
|
|
||||||
const playersData = extractCurrentPlayer(gameData);
|
const currentPlayerData = extractCurrentPlayer(gameData);
|
||||||
|
|
||||||
function startGame() {
|
|
||||||
socket.emit("new-game", { sessionId: session });
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextGame() {
|
|
||||||
socket.emit("next-round", { sessionId: session });
|
|
||||||
}
|
|
||||||
|
|
||||||
function clickCard(cardPosition: number) {
|
|
||||||
console.log("Clicked card", cardPosition);
|
|
||||||
socket.emit("click-card", cardPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTempMessage(message: string) {
|
function setTempMessage(message: string) {
|
||||||
setMessageDisplay(message);
|
setMessageDisplay(message);
|
||||||
|
|
@ -65,7 +43,7 @@ export default function App() {
|
||||||
|
|
||||||
function onMessageEvent(message: string) {
|
function onMessageEvent(message: string) {
|
||||||
setTempMessage(message);
|
setTempMessage(message);
|
||||||
setMessageEvents((previous) => [...previous, message]);
|
// setMessageEvents((previous) => [...previous, message]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onGameUpdate(gameData: Game) {
|
function onGameUpdate(gameData: Game) {
|
||||||
|
|
@ -87,130 +65,27 @@ export default function App() {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Three-Fiber
|
|
||||||
const tableModel = useGLTF("/models/table.glb");
|
|
||||||
const heightProportion = 1.25;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-700">
|
<div className="bg-gray-900 w-screen h-screen">
|
||||||
<div
|
{!gameData && (
|
||||||
style={{
|
<JoinSession
|
||||||
width: window.innerWidth,
|
clientsInRoom={clientsInRoom}
|
||||||
height: window.innerHeight / heightProportion,
|
session={session}
|
||||||
}}
|
setSession={setSession}
|
||||||
>
|
showStartGameButton={showStartGameButton}
|
||||||
<Canvas>
|
/>
|
||||||
<PerspectiveCamera
|
)}
|
||||||
makeDefault
|
<GameCanvas session={session} gameData={gameData} />
|
||||||
manual
|
<MessageDisplay message={messageDispaly} />
|
||||||
fov={75}
|
{session !== "" && (
|
||||||
aspect={window.innerWidth / (window.innerHeight / heightProportion)}
|
<Footer
|
||||||
near={0.1}
|
isConnected={isConnected}
|
||||||
far={1000}
|
session={session}
|
||||||
position={[0, 45, 10]}
|
clientsInRoom={clientsInRoom}
|
||||||
// lookAt={() => new Vector3(0, 0, 0)}
|
currentPlayerData={currentPlayerData}
|
||||||
/>
|
showNextGameButton={showNextGameButton}
|
||||||
<ambientLight color={0xa3a3a3} intensity={0.1} />
|
/>
|
||||||
<directionalLight
|
)}
|
||||||
color={0xffffff}
|
|
||||||
position={[0, 50, 20]}
|
|
||||||
castShadow
|
|
||||||
shadow-mapSize={[1024, 1024]}
|
|
||||||
/>
|
|
||||||
<mesh>
|
|
||||||
<boxGeometry args={[2, 2, 2]} />
|
|
||||||
<meshStandardMaterial color={0x00ff00} />
|
|
||||||
</mesh>
|
|
||||||
<primitive
|
|
||||||
object={tableModel.scene}
|
|
||||||
position={[0, 1.8, 0]}
|
|
||||||
scale={[2, 2, 2]}
|
|
||||||
traverse={(node: Object3D) => {
|
|
||||||
if (node instanceof Mesh) {
|
|
||||||
// node.castShadow = true;
|
|
||||||
node.receiveShadow = true;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<gridHelper args={[100, 100]} />
|
|
||||||
<axesHelper args={[5]} />
|
|
||||||
<OrbitControls />
|
|
||||||
<PlayArea gameData={gameData} />
|
|
||||||
</Canvas>
|
|
||||||
</div>
|
|
||||||
{messageDispaly && messageDispaly !== "" && <p>{messageDispaly}</p>}
|
|
||||||
<JoinSession session={session} setSession={setSession} />
|
|
||||||
<Text>Player ID: {playersData?.id}</Text>
|
|
||||||
<Text>Player Name: {playersData?.name}</Text>
|
|
||||||
<Text>Player Round Points: {playersData?.roundPoints}</Text>
|
|
||||||
<Text>Player Total Points: {playersData?.totalPoints}</Text>
|
|
||||||
<ConnectionState
|
|
||||||
isConnected={isConnected}
|
|
||||||
session={session}
|
|
||||||
clientsInRoom={clientsInRoom}
|
|
||||||
/>
|
|
||||||
<ConnectionManager />
|
|
||||||
{showStartGameButton && <Button onClick={startGame}>Start Game</Button>}
|
|
||||||
{showNextGameButton && <Button onClick={nextGame}>Next Game</Button>}
|
|
||||||
<div className="bg-white">
|
|
||||||
<p> ############### OLD INTERFACE ############### </p>
|
|
||||||
|
|
||||||
{gameData &&
|
|
||||||
gameData.players.map((playerData, index) => (
|
|
||||||
<div key={index}>
|
|
||||||
<p>Player ID: {playerData.id}</p>
|
|
||||||
<p>Player Name: {playerData.name}</p>
|
|
||||||
<p>Player Round Points: {playerData.roundPoints}</p>
|
|
||||||
<p>Player Total Points: {playerData.totalPoints}</p>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Column 1</th>
|
|
||||||
<th>Column 2</th>
|
|
||||||
<th>Column 3</th>
|
|
||||||
<th>Column 4</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{Array(Math.ceil(playerData.cards.length / 4))
|
|
||||||
.fill(null)
|
|
||||||
.map((_, rowIndex) => (
|
|
||||||
<tr key={rowIndex}>
|
|
||||||
{Array(4)
|
|
||||||
.fill(null)
|
|
||||||
.map((_, colIndex) => {
|
|
||||||
const card =
|
|
||||||
playerData.cards[rowIndex * 4 + colIndex];
|
|
||||||
return (
|
|
||||||
<td key={colIndex}>
|
|
||||||
{card && (
|
|
||||||
<Action
|
|
||||||
data={playerData}
|
|
||||||
action={() =>
|
|
||||||
clickCard(rowIndex * 4 + colIndex)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{card.value}
|
|
||||||
</Action>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<CardStack gameData={gameData} playerData={playerData} />
|
|
||||||
<DepositCards gameData={gameData} playerData={playerData} />
|
|
||||||
<CardCache playersData={playersData} />
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Events events={messageEvents} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import { FC } from "react";
|
|
||||||
import { socket } from "../socket";
|
|
||||||
|
|
||||||
import Text from "../global/Text";
|
|
||||||
|
|
||||||
type ConnectionStateProps = {
|
|
||||||
isConnected: boolean;
|
|
||||||
session: string;
|
|
||||||
clientsInRoom: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ConnectionState: FC<ConnectionStateProps> = ({
|
|
||||||
isConnected,
|
|
||||||
session,
|
|
||||||
clientsInRoom,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Text>
|
|
||||||
State: {"" + isConnected} <br />
|
|
||||||
Session: {session} <br />
|
|
||||||
Players: {clientsInRoom} <br />
|
|
||||||
SocketId: {socket.id}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
40
src/components/Footer.tsx
Normal file
40
src/components/Footer.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
|
||||||
|
import Text from "../global/Text";
|
||||||
|
import Button from "../global/Button";
|
||||||
|
import { Player } from "../types/gameTypes";
|
||||||
|
|
||||||
|
type Footer = {
|
||||||
|
isConnected: boolean;
|
||||||
|
session: string;
|
||||||
|
clientsInRoom: number;
|
||||||
|
currentPlayerData: Player | undefined;
|
||||||
|
showNextGameButton: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Footer: FC<Footer> = ({
|
||||||
|
isConnected,
|
||||||
|
session,
|
||||||
|
clientsInRoom,
|
||||||
|
currentPlayerData,
|
||||||
|
showNextGameButton,
|
||||||
|
}) => {
|
||||||
|
function nextGame() {
|
||||||
|
socket.emit("next-round", { sessionId: session });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>Player Name: {currentPlayerData?.name}</Text>
|
||||||
|
<Text>Round Points: {currentPlayerData?.roundPoints}</Text>
|
||||||
|
<Text>Total Points: {currentPlayerData?.totalPoints}</Text>
|
||||||
|
<br />
|
||||||
|
<Text>State: {"" + isConnected}</Text>
|
||||||
|
<Text>SocketId: {socket.id}</Text>
|
||||||
|
<Text>Session: {session}</Text>
|
||||||
|
<Text>Players: {clientsInRoom}</Text>
|
||||||
|
{showNextGameButton && <Button onClick={nextGame}>Next Game</Button>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
69
src/components/GameCanvas.tsx
Normal file
69
src/components/GameCanvas.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Object3D, Mesh } from "three";
|
||||||
|
import { Canvas } from "@react-three/fiber";
|
||||||
|
import { OrbitControls, useGLTF, PerspectiveCamera } from "@react-three/drei";
|
||||||
|
|
||||||
|
import PlayArea from "../components/PlayArea";
|
||||||
|
import { Game } from "../types/gameTypes";
|
||||||
|
|
||||||
|
type GameCanvasProps = {
|
||||||
|
session: string;
|
||||||
|
gameData: Game | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GameCanvas: FC<GameCanvasProps> = ({ gameData }) => {
|
||||||
|
const tableModel = useGLTF("/models/table.glb");
|
||||||
|
const heightProportion = 1.4;
|
||||||
|
|
||||||
|
if (!gameData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight / heightProportion,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Canvas>
|
||||||
|
<PerspectiveCamera
|
||||||
|
makeDefault
|
||||||
|
manual
|
||||||
|
fov={75}
|
||||||
|
aspect={window.innerWidth / (window.innerHeight / heightProportion)}
|
||||||
|
near={0.1}
|
||||||
|
far={1000}
|
||||||
|
position={[0, 43, 10]}
|
||||||
|
// lookAt={() => new Vector3(0, 20, 0)}
|
||||||
|
/>
|
||||||
|
<ambientLight color={0xa3a3a3} intensity={0.1} />
|
||||||
|
<directionalLight
|
||||||
|
color={0xffffff}
|
||||||
|
position={[0, 50, 20]}
|
||||||
|
castShadow
|
||||||
|
shadow-mapSize={[1024, 1024]}
|
||||||
|
/>
|
||||||
|
<mesh>
|
||||||
|
<boxGeometry args={[2, 2, 2]} />
|
||||||
|
<meshStandardMaterial color={0x00ff00} />
|
||||||
|
</mesh>
|
||||||
|
<primitive
|
||||||
|
object={tableModel.scene}
|
||||||
|
position={[0, 1.8, 2]}
|
||||||
|
scale={[2, 2, 2]}
|
||||||
|
traverse={(node: Object3D) => {
|
||||||
|
if (node instanceof Mesh) {
|
||||||
|
// node.castShadow = true;
|
||||||
|
node.receiveShadow = true;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<gridHelper args={[100, 100]} />
|
||||||
|
<axesHelper args={[5]} />
|
||||||
|
<OrbitControls />
|
||||||
|
<PlayArea gameData={gameData} />
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GameCanvas;
|
||||||
|
|
@ -4,11 +4,18 @@ import { socket } from "../socket";
|
||||||
import Button from "../global/Button";
|
import Button from "../global/Button";
|
||||||
|
|
||||||
type JoinSessionProps = {
|
type JoinSessionProps = {
|
||||||
|
clientsInRoom: number;
|
||||||
session: string;
|
session: string;
|
||||||
setSession: Dispatch<SetStateAction<string>>;
|
setSession: Dispatch<SetStateAction<string>>;
|
||||||
|
showStartGameButton: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JoinSession: FC<JoinSessionProps> = ({ session, setSession }) => {
|
export const JoinSession: FC<JoinSessionProps> = ({
|
||||||
|
clientsInRoom,
|
||||||
|
session,
|
||||||
|
setSession,
|
||||||
|
showStartGameButton,
|
||||||
|
}) => {
|
||||||
const [sessionField, setSessionField] = useState("");
|
const [sessionField, setSessionField] = useState("");
|
||||||
|
|
||||||
function joinSession(event: React.FormEvent<HTMLFormElement>) {
|
function joinSession(event: React.FormEvent<HTMLFormElement>) {
|
||||||
|
|
@ -18,15 +25,59 @@ export const JoinSession: FC<JoinSessionProps> = ({ session, setSession }) => {
|
||||||
setSessionField("");
|
setSessionField("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session !== "") {
|
function startGame() {
|
||||||
return null;
|
socket.emit("new-game", { sessionId: session });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const isActiveSession = session !== "";
|
||||||
<form onSubmit={joinSession}>
|
|
||||||
<input onChange={(e) => setSessionField(e.target.value)} />
|
|
||||||
|
|
||||||
<Button>Join</Button>
|
return (
|
||||||
</form>
|
<section>
|
||||||
|
<div
|
||||||
|
className="w-full h-full absolute top-0 left-0 z-0"
|
||||||
|
style={{
|
||||||
|
backgroundImage: "linear-gradient(to bottom, #233876, #111827)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="py-8 px-4 mx-auto max-w-screen-xl text-center lg:py-16 z-10 relative">
|
||||||
|
<h1 className="mb-4 text-4xl font-extrabold tracking-tight leading-none md:text-5xl lg:text-6xl text-white">
|
||||||
|
Skyjo
|
||||||
|
</h1>
|
||||||
|
<p className="mb-8 text-lg font-normal lg:text-xl sm:px-16 lg:px-48 text-gray-200">
|
||||||
|
Play Skyjo online with your friends!
|
||||||
|
</p>
|
||||||
|
<div className="p-4">
|
||||||
|
{!isActiveSession && (
|
||||||
|
<form onSubmit={joinSession}>
|
||||||
|
<label
|
||||||
|
htmlFor="first_name"
|
||||||
|
className="block mb-2 text-sm font-medium text-white"
|
||||||
|
>
|
||||||
|
Join Skyjo Session
|
||||||
|
</label>
|
||||||
|
<div className="flex space-x-1 items-center">
|
||||||
|
<input
|
||||||
|
className="border text-sm rounded-lg block w-full p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"
|
||||||
|
placeholder="Session name"
|
||||||
|
required
|
||||||
|
onChange={(e) => setSessionField(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Button>Join</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-200 text-3xl my-2">Session: {session}</p>
|
||||||
|
<p className="text-gray-200 text-3xl my-4">
|
||||||
|
Players: {clientsInRoom}
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
{showStartGameButton && (
|
||||||
|
<Button onClick={startGame}>Start Game</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
19
src/components/MessageDisplay.tsx
Normal file
19
src/components/MessageDisplay.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
type MessageDisplayProps = {
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MessageDisplay: FC<MessageDisplayProps> = ({ message }) => {
|
||||||
|
if (!message || message == "") return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full flex justify-center items-center">
|
||||||
|
<div className="bg-gray-800 p-4 rounded-lg">
|
||||||
|
<p className="text-white text-xl opacity-100">{message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessageDisplay;
|
||||||
|
|
@ -4,7 +4,6 @@ import PlayerCards from "../components/PlayerCards";
|
||||||
import { Game } from "../types/gameTypes";
|
import { Game } from "../types/gameTypes";
|
||||||
import CardStackStaple from "./CardStackStaple";
|
import CardStackStaple from "./CardStackStaple";
|
||||||
import DiscardPile from "./DiscardPile";
|
import DiscardPile from "./DiscardPile";
|
||||||
import CardCache from "./CardCache";
|
|
||||||
|
|
||||||
type PlayAreaProps = {
|
type PlayAreaProps = {
|
||||||
gameData: Game | null;
|
gameData: Game | null;
|
||||||
|
|
@ -18,7 +17,6 @@ const PlayArea: FC<PlayAreaProps> = ({ gameData }) => {
|
||||||
<PlayerCards playersData={gameData.players} />
|
<PlayerCards playersData={gameData.players} />
|
||||||
<CardStackStaple cardStackData={gameData.cardStack} />
|
<CardStackStaple cardStackData={gameData.cardStack} />
|
||||||
<DiscardPile discardPileData={gameData.discardPile} />
|
<DiscardPile discardPileData={gameData.discardPile} />
|
||||||
<CardCache playersData={gameData.players} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const PlayerCards: FC<PlayerCardsProps> = ({ playersData }) => {
|
||||||
const currentPlayerWithCards: PlayerWithVisualCards[] = [];
|
const currentPlayerWithCards: PlayerWithVisualCards[] = [];
|
||||||
let nonCurrentPlayerIndex = 1;
|
let nonCurrentPlayerIndex = 1;
|
||||||
playersData.forEach((player) => {
|
playersData.forEach((player) => {
|
||||||
const positionOffset = 12;
|
const positionOffset = 14;
|
||||||
const playerWithCards: PlayerWithVisualCards = {
|
const playerWithCards: PlayerWithVisualCards = {
|
||||||
player,
|
player,
|
||||||
cards: [],
|
cards: [],
|
||||||
|
|
@ -68,7 +68,7 @@ const PlayerCards: FC<PlayerCardsProps> = ({ playersData }) => {
|
||||||
<CardCache
|
<CardCache
|
||||||
playerData={playerWithCards.player}
|
playerData={playerWithCards.player}
|
||||||
// current player is always at index 0
|
// current player is always at index 0
|
||||||
position={new Vector3(9, 20, 4 - playerIndex * 12)}
|
position={new Vector3(9, 20, 6 - playerIndex * 12)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||||
const Button: FC<ButtonProps> = ({ children, ...rest }) => {
|
const Button: FC<ButtonProps> = ({ children, ...rest }) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className="text-white focus:ring-4 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-blue-800"
|
className="text-white focus:ring-4 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-blue-800"
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ type TextNormalProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Text: FC<TextNormalProps> = ({ children }) => {
|
const Text: FC<TextNormalProps> = ({ children }) => {
|
||||||
return <p className="text-white">{children}</p>;
|
return <p className="mb-2 text-sm font-medium text-white">{children}</p>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Text;
|
export default Text;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue