From 44cd877c4e390c623d4bf02fa29acd336e48adec Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Mon, 28 Feb 2022 21:12:10 -0800 Subject: [PATCH] Add Resource replacement in Chat Signed-off-by: James Ketrenos --- client/src/Chat.css | 81 +++++++++++++++++++++++ client/src/Chat.js | 143 +++++++++++++++++++++++++++++++++++++++++ client/src/Table.css | 60 ----------------- client/src/Table.js | 121 +--------------------------------- server/routes/games.js | 6 +- 5 files changed, 228 insertions(+), 183 deletions(-) create mode 100644 client/src/Chat.css create mode 100644 client/src/Chat.js diff --git a/client/src/Chat.css b/client/src/Chat.css new file mode 100644 index 0000000..f33c6fb --- /dev/null +++ b/client/src/Chat.css @@ -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; +} \ No newline at end of file diff --git a/client/src/Chat.js b/client/src/Chat.js new file mode 100644 index 0000000..6cbc775 --- /dev/null +++ b/client/src/Chat.js @@ -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[5]}; + } else { + message = <>{dice[1]}{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[5]}{message}; + start = resource[1]; + } else { + message = <>{start}{message}; + start = ''; + } + } + } + + return ( + + { item.color && + + } + Date.now() ? + Date.now() : item.date} interval={1000}/>} /> + + ); + }); + + 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 ( + + + { messages } + + } variant="outlined"/> + + ); +} + +export default Chat; \ No newline at end of file diff --git a/client/src/Table.css b/client/src/Table.css index bd119e8..083b06a 100755 --- a/client/src/Table.css +++ b/client/src/Table.css @@ -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; diff --git a/client/src/Table.js b/client/src/Table.js index 359d625..c058f76 100755 --- a/client/src/Table.js +++ b/client/src/Table.js @@ -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[5]}; - } else { - message = <>{dice[1]}{dice[5]}; - } - } else { - message = item.message; - } - return ( - - { item.color && - - } - Date.now() ? - Date.now() : item.date} interval={1000}/>} /> - - ); - }); - - 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 ( - - - { messages } - - } variant="outlined"/> - - ); -} - const StartButton = ({ table }) => { const startClick = (event) => { table.setGameState("game-order").then((state) => { diff --git a/server/routes/games.js b/server/routes/games.js index 5d6609a..0316865 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -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;