1
0

Add Resource replacement in Chat

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-28 21:12:10 -08:00
parent 7439eaf21f
commit 44cd877c4e
5 changed files with 228 additions and 183 deletions

81
client/src/Chat.css Normal file
View File

@ -0,0 +1,81 @@
.Chat {
display: flex;
flex-direction: column;
flex-grow: 1;
padding: 0.5em;
}
.ChatList {
/* for Firefox */
min-height: 0;
flex-grow: 1;
flex-shrink: 1;
overflow: auto;
scroll-behavior: smooth;
align-items: flex-start;
overflow-x: hidden;
}
.ChatList .System {
background-color: #f0f0f0;
transform: scale(0.8);
border-radius: 0.25em;
}
.ChatInput {
flex-grow: 0;
flex-shrink: 0;
}
.ChatList .MuiListItem-gutters {
padding: 2px 0 2px 0;
}
.ChatList .MuiTypography-body1 {
font-size: 0.8rem;
display: flex;
}
.ChatList .System .MuiTypography-body1 {
margin-left: 1em;
}
.ChatList .MuiTypography-body2 {
font-size: 0.7rem;
}
.ChatList .MuiListItemText-multiline {
margin-top: 0;
margin-bottom: 0;
padding: 4px 0px 4px 4px;
}
.ChatList .PlayerColor {
width: 1em;
height: 1em;
padding: 0;
margin-top: 6px;
align-self: flex-start;
}
.ChatList .Resource {
display: inline-flex;
width: 3em;
height: 4.3em;
pointer-events: none;
}
.ChatList .Stack {
margin-left: 0;
transition: none;
}
.ChatList .Stack > *:not(:first-child) {
margin-left: 0;
transition: none;
}
.ChatList .Dice {
margin-left: 0.25em;
}

143
client/src/Chat.js Normal file
View File

@ -0,0 +1,143 @@
import React, { useState, useEffect } from "react";
import "./Chat.css";
import PlayerColor from './PlayerColor.js';
import Paper from '@material-ui/core/Paper';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Moment from 'react-moment';
import TextField from '@material-ui/core/TextField';
import Resource from './Resource.js';
import Dice from './Dice.js';
const Chat = ({ table }) => {
const [lastTop, setLastTop] = useState(0),
[autoScroll, setAutoscroll] = useState(true),
[latest, setLatest] = useState(''),
[scrollTime, setScrollTime] = useState(0);
const chatInput = (event) => {
};
const chatKeyPress = (event) => {
if (event.key === "Enter") {
if (!autoScroll) {
setAutoscroll(true);
}
table.sendChat(event.target.value);
event.target.value = "";
}
};
const chatScroll = (event) => {
const chatList = event.target,
fromBottom = Math.round(Math.abs((chatList.scrollHeight - chatList.offsetHeight) - chatList.scrollTop));
/* If scroll is within 20 pixels of the bottom, turn on auto-scroll */
const shouldAutoscroll = (fromBottom < 20);
if (shouldAutoscroll !== autoScroll) {
setAutoscroll(shouldAutoscroll);
}
/* If the list should not auto scroll, then cache the current
* top of the list and record when we did this so we honor
* the auto-scroll for at least 500ms */
if (!shouldAutoscroll) {
const target = Math.round(chatList.scrollTop);
if (target !== lastTop) {
setLastTop(target);
setScrollTime(Date.now());
}
}
};
useEffect(() => {
const chatList = document.getElementById("ChatList"),
currentTop = Math.round(chatList.scrollTop);
if (autoScroll) {
/* Auto-scroll to the bottom of the chat window */
const target = Math.round(chatList.scrollHeight - chatList.offsetHeight);
if (currentTop !== target) {
chatList.scrollTop = target;
}
return;
}
/* Maintain current position in scrolled view if the user hasn't
* been scrolling in the past 0.5s */
if ((Date.now() - scrollTime) > 500 && currentTop !== lastTop) {
chatList.scrollTop = lastTop;
}
});
//const timeDelta = game.timestamp - Date.now();
if (!table.game) {
console.log("Why no game?");
}
const messages = table.game && table.game.chat.map((item, index) => {
let message;
/* If the date is in the future, set it to now */
const dice = item.message.match(/^(.*rolled )([1-6])(, ([1-6]))?(.*)$/);
if (dice) {
if (dice[4]) {
message = <>{dice[1]}<Dice pips={dice[2]}/>, <Dice pips={dice[4]}/>{dice[5]}</>;
} else {
message = <>{dice[1]}<Dice pips={dice[2]}/>{dice[5]}</>;
}
} else {
let start = item.message;
while (start) {
const resource = start.match(/^(.*)(([0-9]+) (wood|sheep|wheat|stone|brick),?)(.*)$/);
if (resource) {
const count = resource[3] ? parseInt(resource[3]) : 1;
message = <><Resource count={count} type={resource[4]}/>{resource[5]}{message}</>;
start = resource[1];
} else {
message = <>{start}{message}</>;
start = '';
}
}
}
return (
<ListItem key={`msg-${item.date}`} className={item.color ? '' : 'System'}>
{ item.color &&
<PlayerColor color={item.color}/>
}
<ListItemText primary={message}
secondary={item.color && <Moment fromNow date={item.date > Date.now() ?
Date.now() : item.date} interval={1000}/>} />
</ListItem>
);
});
if (table.game && table.game.chat &&
table.game.chat.length &&
table.game.chat[table.game.chat.length - 1].date !== latest) {
setLatest(table.game.chat[table.game.chat.length - 1].date);
setAutoscroll(true);
}
const name = table.game ? table.game.name : "Why no game?";
const elapsed = table.game ? (table.game.timestamp - table.game.startTime) : undefined;
return (
<Paper className="Chat">
<List className="ChatList" id="ChatList" onScroll={chatScroll}>
{ messages }
</List>
<TextField className="ChatInput"
disabled={!name}
onChange={chatInput}
onKeyPress={chatKeyPress}
label={elapsed && <Moment tz={"Etc/GMT"} format="h:mm:ss" durationFromNow interval={1000} date={table.game.startTime}></Moment>} variant="outlined"/>
</Paper>
);
}
export default Chat;

View File

@ -264,66 +264,6 @@
* Chat
* Action
*/
.Chat {
display: flex;
flex-direction: column;
flex-grow: 1;
padding: 0.5em;
}
.ChatList {
/* for Firefox */
min-height: 0;
flex-grow: 1;
flex-shrink: 1;
overflow: auto;
scroll-behavior: smooth;
align-items: flex-start;
overflow-x: hidden;
}
.ChatList .System {
background-color: #f0f0f0;
transform: scale(0.8);
border-radius: 0.25em;
}
.ChatInput {
flex-grow: 0;
flex-shrink: 0;
}
.ChatList .MuiListItem-gutters {
padding: 2px 0 2px 0;
}
.ChatList .MuiTypography-body1 {
font-size: 0.8rem;
}
.ChatList .System .MuiTypography-body1 {
margin-left: 1em;
}
.ChatList .MuiTypography-body2 {
font-size: 0.7rem;
}
.ChatList .MuiListItemText-multiline {
margin-top: 0;
margin-bottom: 0;
padding: 4px 0px 4px 4px;
}
.ChatList .PlayerColor {
width: 1em;
height: 1em;
padding: 0;
margin-top: 6px;
align-self: flex-start;
}
.Players {
flex: 1 0;
overflow: hidden;

View File

@ -1,11 +1,10 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import "./Table.css";
import history from "./history.js";
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Moment from 'react-moment';
import Board from './Board.js';
@ -17,6 +16,7 @@ import Resource from './Resource.js';
import ViewCard from './ViewCard.js';
import Winner from './Winner.js';
import ChooseCard from './ChooseCard.js';
import Chat from './Chat.js';
import { CircularProgress } from "@material-ui/core";
import 'moment-timezone';
@ -119,123 +119,6 @@ const Development = ({table, type, card, onClick}) => {
);
};
const Chat = ({ table }) => {
const [lastTop, setLastTop] = useState(0),
[autoScroll, setAutoscroll] = useState(true),
[latest, setLatest] = useState(''),
[scrollTime, setScrollTime] = useState(0);
const chatInput = (event) => {
};
const chatKeyPress = (event) => {
if (event.key === "Enter") {
if (!autoScroll) {
setAutoscroll(true);
}
table.sendChat(event.target.value);
event.target.value = "";
}
};
const chatScroll = (event) => {
const chatList = event.target,
fromBottom = Math.round(Math.abs((chatList.scrollHeight - chatList.offsetHeight) - chatList.scrollTop));
/* If scroll is within 20 pixels of the bottom, turn on auto-scroll */
const shouldAutoscroll = (fromBottom < 20);
if (shouldAutoscroll !== autoScroll) {
setAutoscroll(shouldAutoscroll);
}
/* If the list should not auto scroll, then cache the current
* top of the list and record when we did this so we honor
* the auto-scroll for at least 500ms */
if (!shouldAutoscroll) {
const target = Math.round(chatList.scrollTop);
if (target !== lastTop) {
setLastTop(target);
setScrollTime(Date.now());
}
}
};
useEffect(() => {
const chatList = document.getElementById("ChatList"),
currentTop = Math.round(chatList.scrollTop);
if (autoScroll) {
/* Auto-scroll to the bottom of the chat window */
const target = Math.round(chatList.scrollHeight - chatList.offsetHeight);
if (currentTop !== target) {
chatList.scrollTop = target;
}
return;
}
/* Maintain current position in scrolled view if the user hasn't
* been scrolling in the past 0.5s */
if ((Date.now() - scrollTime) > 500 && currentTop !== lastTop) {
chatList.scrollTop = lastTop;
}
});
//const timeDelta = game.timestamp - Date.now();
if (!table.game) {
console.log("Why no game?");
}
const messages = table.game && table.game.chat.map((item, index) => {
let message;
/* If the date is in the future, set it to now */
const dice = item.message.match(/^(.*rolled )([1-6])(, ([1-6]))?(.*)$/);
if (dice) {
if (dice[4]) {
message = <>{dice[1]}<Dice pips={dice[2]}/>, <Dice pips={dice[4]}/>{dice[5]}</>;
} else {
message = <>{dice[1]}<Dice pips={dice[2]}/>{dice[5]}</>;
}
} else {
message = item.message;
}
return (
<ListItem key={`msg-${item.date}`} className={item.color ? '' : 'System'}>
{ item.color &&
<PlayerColor color={item.color}/>
}
<ListItemText primary={message}
secondary={item.color && <Moment fromNow date={item.date > Date.now() ?
Date.now() : item.date} interval={1000}/>} />
</ListItem>
);
});
if (table.game && table.game.chat &&
table.game.chat.length &&
table.game.chat[table.game.chat.length - 1].date !== latest) {
setLatest(table.game.chat[table.game.chat.length - 1].date);
setAutoscroll(true);
}
const name = table.game ? table.game.name : "Why no game?";
const elapsed = table.game ? (table.game.timestamp - table.game.startTime) : undefined;
return (
<Paper className="Chat">
<List className="ChatList" id="ChatList" onScroll={chatScroll}>
{ messages }
</List>
<TextField className="ChatInput"
disabled={!name}
onChange={chatInput}
onKeyPress={chatKeyPress}
label={elapsed && <Moment tz={"Etc/GMT"} format="h:mm:ss" durationFromNow interval={1000} date={table.game.startTime}></Moment>} variant="outlined"/>
</Paper>
);
}
const StartButton = ({ table }) => {
const startClick = (event) => {
table.setGameState("game-order").then((state) => {

View File

@ -1785,7 +1785,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
game.turn.actions = [];
game.turn.limits = {};
addChatMessage(game, session,
`${session.name} randomly stole ${type} from ${playerNameFromColor(game, value)}.`);
`${session.name} randomly stole 1 ${type} from ${playerNameFromColor(game, value)}.`);
}
debugChat(game, 'After steal');
@ -2891,9 +2891,7 @@ const createGame = (id) => {
setBeginnerGame(game);
resetGame(game);
console.log(`New game created with Beginner's Layout: ${game.id}`);
addChatMessage(game, null,
`New game created with Beginner's Layout: ${game.id}`);
addChatMessage(game, null, `New game created with Beginner's Layout: ${game.id}`);
games[game.id] = game;