Merge pull request #1 from MauMauStudios/meow_to_mau
Basic (and First!) Mau Front-End
BIN
src/assets/cards/back.png
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
src/assets/cards/clubs_ace.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/assets/cards/clubs_eight.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/cards/clubs_five.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/clubs_four.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/clubs_jack.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
src/assets/cards/clubs_king.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
src/assets/cards/clubs_nine.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/cards/clubs_queen.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
src/assets/cards/clubs_seven.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/cards/clubs_six.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/clubs_ten.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/cards/clubs_three.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/clubs_two.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/cards/diamonds_ace.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/cards/diamonds_eight.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/diamonds_five.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/diamonds_four.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/assets/cards/diamonds_jack.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
src/assets/cards/diamonds_king.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
src/assets/cards/diamonds_nine.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/diamonds_queen.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/assets/cards/diamonds_seven.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/cards/diamonds_six.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/cards/diamonds_ten.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/cards/diamonds_three.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/diamonds_two.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
src/assets/cards/hearts_ace.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
src/assets/cards/hearts_eight.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/cards/hearts_five.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/hearts_four.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
src/assets/cards/hearts_jack.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
src/assets/cards/hearts_king.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
src/assets/cards/hearts_nine.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/cards/hearts_queen.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
src/assets/cards/hearts_seven.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/cards/hearts_six.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/cards/hearts_ten.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/cards/hearts_three.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/hearts_two.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/assets/cards/joker_black.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
src/assets/cards/joker_red.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
src/assets/cards/spades_ace.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/assets/cards/spades_eight.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/cards/spades_five.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/spades_four.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/cards/spades_jack.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/assets/cards/spades_king.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
src/assets/cards/spades_nine.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/cards/spades_queen.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
src/assets/cards/spades_seven.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/cards/spades_six.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/cards/spades_ten.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/cards/spades_three.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/cards/spades_two.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
32
src/layout/components/Card.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import React, {FunctionComponent} from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
cardString: string;
|
||||||
|
handleClick?: (cardString: string) => void;
|
||||||
|
isHidden?: boolean;
|
||||||
|
isClickable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Card: FunctionComponent<Props> = ({cardString, handleClick, isHidden, isClickable}) => {
|
||||||
|
const cardType = cardString.split(' ')[0].toLowerCase();
|
||||||
|
const cardValue = cardString.split(' ')[1].toLowerCase();
|
||||||
|
|
||||||
|
const cardSource = isHidden ?
|
||||||
|
require(`../../assets/cards/back.png`) :
|
||||||
|
require(`../../assets/cards/${cardType}_${cardValue}.png`);
|
||||||
|
const cardName = isHidden ? 'back' : `${cardType} ${cardValue}`;
|
||||||
|
|
||||||
|
const handleCardClick = () => {
|
||||||
|
if (handleClick) {
|
||||||
|
handleClick(cardString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`card ${isClickable && 'card-clickable'}`}>
|
||||||
|
<img className="card__texture" src={cardSource} alt={cardName} onClick={handleCardClick}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Card;
|
||||||
28
src/layout/components/Hand.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import React, {FunctionComponent} from 'react';
|
||||||
|
import Card from "./Card";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
hand: string[];
|
||||||
|
actionOnClick: (cardString: string) => void;
|
||||||
|
isHidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Hand: FunctionComponent<Props> = ({hand, actionOnClick, isHidden}) => {
|
||||||
|
|
||||||
|
const isMyHand = !isHidden;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="hand">
|
||||||
|
{
|
||||||
|
hand.map((card, index) => {
|
||||||
|
return (
|
||||||
|
<Card key={index} cardString={card} handleClick={actionOnClick} isHidden={!isMyHand}
|
||||||
|
isClickable={isMyHand}/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Hand;
|
||||||
@@ -3,6 +3,16 @@ import React from "react";
|
|||||||
import {useParams} from "react-router";
|
import {useParams} from "react-router";
|
||||||
import {GHButton} from "../components/Button";
|
import {GHButton} from "../components/Button";
|
||||||
import useTitle from "../../utils/TitleHook";
|
import useTitle from "../../utils/TitleHook";
|
||||||
|
import Card from "../components/Card";
|
||||||
|
import Hand from "../components/Hand";
|
||||||
|
|
||||||
|
interface GameState {
|
||||||
|
PlayerName: string;
|
||||||
|
Hand: string[];
|
||||||
|
CurrentCard: string;
|
||||||
|
CurrentPlayer: string;
|
||||||
|
Players: string[];
|
||||||
|
}
|
||||||
|
|
||||||
const Room = () => {
|
const Room = () => {
|
||||||
|
|
||||||
@@ -12,47 +22,40 @@ const Room = () => {
|
|||||||
|
|
||||||
const WS_URL = `ws://${process.env.REACT_APP_API_URL}/room/${roomId}`;
|
const WS_URL = `ws://${process.env.REACT_APP_API_URL}/room/${roomId}`;
|
||||||
|
|
||||||
const [message, setMessage] = React.useState<string>('');
|
const [gameState, setGameState] = React.useState<GameState>({PlayerName: '', Hand: [], CurrentCard: '', CurrentPlayer: '', Players: []});
|
||||||
const [messages, setMessages] = React.useState<string[]>([]);
|
|
||||||
|
|
||||||
const websocket = useWebSocket(WS_URL, {
|
const websocket = useWebSocket(WS_URL, {
|
||||||
onOpen: () => {
|
onOpen: () => {
|
||||||
console.log('WebSocket connection established.');
|
console.log('WebSocket connection established.');
|
||||||
},
|
},
|
||||||
onMessage: (event) => {
|
onMessage: (event) => {
|
||||||
setMessages([...messages, event.data]);
|
const data = JSON.parse(event.data);
|
||||||
|
setGameState(data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSend = () => {
|
|
||||||
websocket.sendMessage(message);
|
|
||||||
setMessage('');
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMessageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setMessage(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleLeaveRoom = () => {
|
const handleLeaveRoom = () => {
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleCardSend = (card: string) => {
|
||||||
|
const formattedCard = JSON.stringify({CardType: card.split(' ')[0], CardValue: card.split(' ')[1]});
|
||||||
|
websocket.sendMessage(formattedCard);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Room {roomId}</h1>
|
<h1>Room {roomId}</h1>
|
||||||
<GHButton onClick={handleLeaveRoom}>Leave Room</GHButton>
|
<GHButton onClick={handleLeaveRoom}>Leave Room</GHButton>
|
||||||
<form onSubmit={(event) => {
|
{
|
||||||
event.preventDefault();
|
gameState.CurrentCard &&
|
||||||
handleSend();
|
<Card cardString={gameState.CurrentCard}/>
|
||||||
}}>
|
}
|
||||||
<input type="text" name="message" placeholder="Send a message" value={message}
|
<Hand hand={gameState.Hand} actionOnClick={handleCardSend}/>
|
||||||
onChange={handleMessageChange}/>
|
|
||||||
<span onClick={handleSend}>Send</span>
|
|
||||||
</form>
|
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
messages.map((message, index) => {
|
gameState.Players.map((player, index) => {
|
||||||
return <li key={index}>{message}</li>
|
return <li key={index} style={{fontWeight: player === gameState.CurrentPlayer ? 'bold' : 'normal'}}>{player} {player === gameState.PlayerName && '(You)'}</li>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
@import "button";
|
@import "button";
|
||||||
|
@import "card";
|
||||||
|
@import "hand";
|
||||||
14
src/styles/layout/components/card.scss
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.card {
|
||||||
|
width: 100px;
|
||||||
|
min-width: 100px;
|
||||||
|
|
||||||
|
&-clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__texture {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/styles/layout/components/hand.scss
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.hand {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
//justify-content: center;
|
||||||
|
flex-flow: nowrap !important;
|
||||||
|
overflow-x: scroll;
|
||||||
|
padding: 0.5rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||