diff --git a/src/components/Chat.jsx b/src/components/Chat.jsx index 6e0bad1..3c6d623 100644 --- a/src/components/Chat.jsx +++ b/src/components/Chat.jsx @@ -13,23 +13,21 @@ import { MAX_CHAT_MESSAGES } from '../core/constants'; import type { State } from '../reducers'; import ChatInput from './ChatInput'; import { saveSelection, restoreSelection } from '../utils/storeSelection'; -import { colorFromText, splitCoordsInString } from '../core/utils'; +import { colorFromText, splitChatMessage } from '../core/utils'; -function ChatMessage({ name, text, country }) { - if (!name || !text) { +function ChatMessage({ name, msgArray, country }) { + if (!name || !msgArray) { return null; } - const msgText = text.trim(); const isInfo = (name === 'info'); let className = 'msg'; if (isInfo) { className += ' info'; - } else if (text.charAt(0) === '>') { + } else if (msgArray[0][1].charAt(0) === '>') { className += ' greentext'; } - const splitMsg = splitCoordsInString(msgText); return (

@@ -60,26 +58,35 @@ function ChatMessage({ name, text, country }) { ) } { - splitMsg.map((txt, i) => { - if (i % 2 === 0) { + msgArray.map((msgPart) => { + const [type, txt] = msgPart; + if (type === 't') { + return ({txt}); + } if (type === 'c') { + return ({txt}); + } if (type === 'p') { + return ({txt}); + } if (type === 'm') { return ( - {txt} - + className="mention" + style={{ + color: colorFromText(txt), + }} + >{txt} ); } - return ({txt}); + return null; }) }

); } -const Chat = ({ chatMessages, chatChannel }) => { +const Chat = ({ chatMessages, chatChannel, ownName }) => { const listRef = useRef(); const [selection, setSelection] = useState(null); + const [nameRegExp, setNameRegExp] = useState(null); const { stayScrolled } = useStayScrolled(listRef, { initialScroll: Infinity, }); @@ -94,7 +101,14 @@ const Chat = ({ chatMessages, chatChannel }) => { if (channelMessages.length === MAX_CHAT_MESSAGES) { restoreSelection(selection); } - }); + }, [channelMessages]); + + useEffect(() => { + const regExp = (ownName) + ? new RegExp(`(^|\\s+)(@${ownName})(\\s+|$)`, 'g') + : null; + setNameRegExp(regExp); + }, [ownName]); return (
@@ -109,7 +123,7 @@ const Chat = ({ chatMessages, chatChannel }) => { channelMessages.map((message) => ( )) @@ -121,9 +135,9 @@ const Chat = ({ chatMessages, chatChannel }) => { }; function mapStateToProps(state: State) { - const { chatMessages } = state.user; + const { chatMessages, name } = state.user; const { chatChannel } = state.gui; - return { chatMessages, chatChannel }; + return { chatMessages, chatChannel, ownName: name }; } export default connect(mapStateToProps)(Chat); diff --git a/src/core/utils.js b/src/core/utils.js index 15df479..ff1edf1 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -227,10 +227,55 @@ export function colorFromText(str: string) { return `#${'00000'.substring(0, 6 - c.length)}${c}`; } +/* + * splits chat message into array of what it represents + * [[type, text],[type, text], ...] + * type: + * 't': text + * 'p': ping + * 'c': coordinates + * 'm': mention of somebody else + * nameRegExp has to be in the form of: + new RegExp(`(^|\\s+)(@${ownName})(\\s+|$)`, 'g'); + */ const linkRegExp = /(#[a-z]*,-?[0-9]*,-?[0-9]*(,-?[0-9]+)?)/gi; -export function splitCoordsInString(text) { - const arr = text - .split(linkRegExp) - .filter((val, ind) => ((ind % 3) !== 2)); +const linkRegExpFilter = (val, ind) => ((ind % 3) !== 2); +const mentionRegExp = /(^|\s+)(@\S+)(\s+|$)/g; +const spaceFilter = (val) => (val !== ' '); + +function splitChatMessageRegexp( + msgArray, + regExp, + ident, + filter = () => true, +) { + return msgArray.map((msgPart) => { + const [type, part] = msgPart; + if (type !== 't') { + return [msgPart]; + } + return part + .split(regExp) + .filter(filter) + .map((stri, i) => { + if (i % 2 === 0) { + return ['t', stri]; + } + return [ident, stri]; + }) + .filter((el) => !!el) + }).flat(1); +} + +export function splitChatMessage(message, nameRegExp = null) { + if (!message) { + return null; + } + let arr = [['t', message.trim()]]; + arr = splitChatMessageRegexp(arr, linkRegExp, 'c', linkRegExpFilter); + if (nameRegExp) { + arr = splitChatMessageRegexp(arr, nameRegExp, 'p', spaceFilter); + } + arr = splitChatMessageRegexp(arr, mentionRegExp, 'm', spaceFilter); return arr; } diff --git a/src/styles/default.css b/src/styles/default.css index 9d860de..3ccdbc1 100644 --- a/src/styles/default.css +++ b/src/styles/default.css @@ -403,6 +403,18 @@ tr:nth-child(even) { .msg.greentext{ color: green; } +.ping { + background-color: #ffff87; + border-style: solid; + border-color: black; + border-width: 1px; + color: #1d1c1c; + border-radius: 6px; +} +.mention, .ping { + margin-left: 5px; + margin-right: 5px; +} #chatlink { position: absolute; font-weight: bold;