feat: initial messages
This commit is contained in:
parent
b9b439290e
commit
7982eb054a
|
@ -2,9 +2,13 @@ import './chat--center.scss';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import ChatMessages from './chat--messages';
|
||||||
|
|
||||||
export default function ChatCenter() {
|
export default function ChatCenter() {
|
||||||
return (
|
return (
|
||||||
<div className="chat__center flexed" />
|
<div className="center flexed">
|
||||||
|
<ChatMessages />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.chat__center {
|
.center {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
56
src/client/chat--message.jsx
Normal file
56
src/client/chat--message.jsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import './chat--message.scss';
|
||||||
|
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
|
export default function PlayersChatMessageSpace(props) {
|
||||||
|
const {message: {owner, text, timestamp}, isShort} = props;
|
||||||
|
const ownerMap = {
|
||||||
|
1: 'cha0s',
|
||||||
|
2: 'BabeHasHiccups',
|
||||||
|
};
|
||||||
|
const dtf = new Intl.DateTimeFormat(undefined, {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
});
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
const $messageTime = (
|
||||||
|
<div
|
||||||
|
className="chat--messageTime"
|
||||||
|
title={date.toISOString()}
|
||||||
|
>
|
||||||
|
{dtf.format(date)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames('chat--message', {short: isShort})}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
!isShort && (
|
||||||
|
<header>
|
||||||
|
<div className="chat--messageOwner">{ownerMap[owner]}</div>
|
||||||
|
{$messageTime}
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<div className="chat--messageText">
|
||||||
|
<div className="chat--messageMarkdown">
|
||||||
|
<ReactMarkdown source={text} />
|
||||||
|
</div>
|
||||||
|
{isShort && $messageTime}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayersChatMessageSpace.propTypes = {
|
||||||
|
isShort: PropTypes.bool.isRequired,
|
||||||
|
message: PropTypes.shape({
|
||||||
|
text: PropTypes.string,
|
||||||
|
timestamp: PropTypes.number,
|
||||||
|
owner: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
};
|
82
src/client/chat--message.scss
Normal file
82
src/client/chat--message.scss
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
.chat--message {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message, .chat--message * {
|
||||||
|
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message.short {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message.short .chat--messageTime {
|
||||||
|
display: inline;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message.short:hover .chat--messageTime {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message.short .chat--messageOwner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message:hover {
|
||||||
|
background-color: #1c1c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageOwner {
|
||||||
|
color: #d68030aa;
|
||||||
|
font-family: Caladea, 'Times New Roman', Times, serif;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageTime {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--message:not(.short) .chat--messageTime {
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageText {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageMarkdown * {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageMarkdown {
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageMarkdown {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageMarkdown :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messageMarkdown :last-child {
|
||||||
|
display: inline;
|
||||||
|
}
|
103
src/client/chat--messages.jsx
Normal file
103
src/client/chat--messages.jsx
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import './chat--messages.scss';
|
||||||
|
|
||||||
|
import React, {useLayoutEffect, useRef, useState} from 'react';
|
||||||
|
|
||||||
|
import ChatMessage from './chat--message';
|
||||||
|
|
||||||
|
export default function PlayersChatSpace() {
|
||||||
|
const [$form, $messages] = [useRef(null), useRef(null)];
|
||||||
|
const [text, setText] = useState('');
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
owner: 1,
|
||||||
|
text: 'Hi!',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
owner: 2,
|
||||||
|
text: 'Yo.',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 3,
|
||||||
|
owner: 2,
|
||||||
|
text: 'How have you been?',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 4,
|
||||||
|
owner: 1,
|
||||||
|
text: 'Not too bad.',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const {current} = $messages;
|
||||||
|
const isAtTheBottom = !current
|
||||||
|
? true
|
||||||
|
: 0 === current.scrollTop || (
|
||||||
|
current.scrollHeight
|
||||||
|
=== current.scrollTop
|
||||||
|
+ ['margin-top', 'margin-bottom'].reduce((r, property) => (
|
||||||
|
r + parseInt(window.getComputedStyle(current).getPropertyValue(property), 10)
|
||||||
|
), current.offsetHeight)
|
||||||
|
);
|
||||||
|
const heightWatch = current && current.scrollHeight;
|
||||||
|
const messageCount = messages && messages.length;
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (isAtTheBottom) {
|
||||||
|
current?.scrollTo(0, !current ? 0 : current.scrollHeight);
|
||||||
|
}
|
||||||
|
}, [current, heightWatch, messageCount, isAtTheBottom]);
|
||||||
|
let messageOwner = false;
|
||||||
|
return (
|
||||||
|
<div className="chat--messages">
|
||||||
|
<div className="chat--messagesSmoosh" />
|
||||||
|
<div
|
||||||
|
className="chat--messagesList"
|
||||||
|
ref={$messages}
|
||||||
|
>
|
||||||
|
{messages && messages.map((message) => {
|
||||||
|
const $message = (
|
||||||
|
<ChatMessage
|
||||||
|
key={message.key}
|
||||||
|
isShort={messageOwner === message.owner}
|
||||||
|
message={message}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
messageOwner = message.owner;
|
||||||
|
return $message;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
onSubmit={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const trimmed = text.slice(0, 1000).trim();
|
||||||
|
if (trimmed) {
|
||||||
|
// socket.send(new ActionPacket(chat({owner: playerId, text: trimmed}, {game: id})));
|
||||||
|
}
|
||||||
|
setText('');
|
||||||
|
}}
|
||||||
|
ref={$form}
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
className="chat--messagesTextarea"
|
||||||
|
name="message"
|
||||||
|
type="textarea"
|
||||||
|
maxLength="1000"
|
||||||
|
onChange={(event) => {
|
||||||
|
setText(event.target.value);
|
||||||
|
}}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if ('Enter' === event.key && !event.shiftKey) {
|
||||||
|
$form.current?.dispatchEvent(new Event('submit', {cancelable: true}));
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={text}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
28
src/client/chat--messages.scss
Normal file
28
src/client/chat--messages.scss
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.chat--messages {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messagesSmoosh {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messagesList {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat--messagesTextarea {
|
||||||
|
background-color: #333;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: #aaa;
|
||||||
|
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
height: 4rem;
|
||||||
|
margin: 0.5rem 1rem 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
resize: none;
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user