11import React , { useState , useEffect , useRef } from 'react' ;
2- import styled from 'styled-components' ;
2+ import styled , { css as c } from 'styled-components' ;
33import { sortBy , takeRight } from 'lodash-es' ;
44
5- import AutosizeTextArea from '@codesandbox/common/lib/components/AutosizeTextArea' ;
65import { ENTER } from '@codesandbox/common/lib/utils/keycodes' ;
76import { useOvermind } from 'app/overmind' ;
7+ import css from '@styled-system/css' ;
8+ import {
9+ Collapsible ,
10+ Text ,
11+ Stack ,
12+ Textarea ,
13+ Element ,
14+ } from '@codesandbox/components' ;
815
9- const Container = styled . div `
16+ const Container = styled ( Stack ) `
1017 min-height: 200px;
1118 max-height: 300px;
12- padding: 0 1rem;
13- color: white;
14- font-size: 0.875rem;
15- display: flex;
16- flex-direction: column;
19+ padding: 0 ${ props => props . theme . sizes [ 2 ] } px;
1720 overflow-y: auto;
1821` ;
1922
@@ -22,9 +25,17 @@ const Messages = styled.div`
2225 flex: 1;
2326` ;
2427
28+ const Avatar = styled . img `
29+ ${ ( { theme, color } ) => c `
30+ border-radius: ${ theme . radii . medium } px;
31+ border: 1px solid ${ color } ;
32+ width: ${ theme . sizes [ 8 ] } px;
33+ height: ${ theme . sizes [ 8 ] } px;
34+ ` }
35+ ` ;
36+
2537export const Chat : React . FC = ( ) => {
2638 const [ value , setValue ] = useState ( '' ) ;
27- const [ height , setHeight ] = useState < number > ( null ) ;
2839 const { state, actions } = useOvermind ( ) ;
2940 const messagesRef = useRef ( null ) ;
3041 const scrollDown = ( ) => {
@@ -35,7 +46,7 @@ export const Chat: React.FC = () => {
3546 useEffect ( scrollDown ) ;
3647
3748 const handleKeyDown = ( e : React . KeyboardEvent ) => {
38- if ( e . keyCode === ENTER && ! e . shiftKey ) {
49+ if ( e . keyCode === ENTER && ! e . shiftKey && value . trim ( ) !== '' ) {
3950 e . preventDefault ( ) ;
4051 e . stopPropagation ( ) ;
4152 // Enter
@@ -54,76 +65,96 @@ export const Chat: React.FC = () => {
5465 } ;
5566
5667 const { messages, users } = state . live . roomInfo . chat ;
57- const currentUserId = state . live . liveUserId ;
5868 const roomInfoUsers = state . live . roomInfo . users ;
5969
70+ const orderedMessages : ( m : any ) => any [ ] = m =>
71+ sortBy ( takeRight ( m , 100 ) , 'date' ) ;
72+
73+ const messageData = message => {
74+ const metadata = roomInfoUsers . find ( u => u . id === message . userId ) ;
75+ return {
76+ metadata,
77+ color : metadata
78+ ? `rgb(${ metadata . color [ 0 ] } , ${ metadata . color [ 1 ] } , ${ metadata . color [ 2 ] } )`
79+ : '#636363' ,
80+ name : users [ message . userId ] ,
81+ } ;
82+ } ;
83+
84+ const isNotSameUser = ( message , i ) =>
85+ i === 0 || messages [ i - 1 ] . userId !== message . userId ;
86+
87+ const isLight = theme => theme . vscodeTheme . type === 'light' ;
88+
6089 return (
61- < Container ref = { messagesRef } >
62- < Messages >
63- { messages . length > 0 ? (
64- sortBy ( takeRight ( messages , 100 ) , 'date' ) . map ( ( message , i ) => {
65- const metadata = roomInfoUsers . find ( u => u . id === message . userId ) ;
66- const color = metadata
67- ? `rgb(${ metadata . color [ 0 ] } , ${ metadata . color [ 1 ] } , ${ metadata . color [ 2 ] } )`
68- : '#636363' ;
69- const name = users [ message . userId ] ;
70- return (
71- < div key = { message . date } >
72- { ( i === 0 || messages [ i - 1 ] . userId !== message . userId ) && (
73- < div
90+ < Collapsible
91+ css = { css ( theme => ( {
92+ borderTop : '1px solid' ,
93+ borderColor : 'sideBar.border' ,
94+ boxShadow : isLight ( theme )
95+ ? '0px -8px 8px rgba(255,255,255,0.24), 0px -4px 8px rgba(255,255,255,0.4)'
96+ : '0px -8px 8px rgba(0,0,0,0.24), 0px -4px 8px rgba(0,0,0,0.4)' ,
97+ } ) ) }
98+ defaultOpen
99+ title = "Chat"
100+ >
101+ < Container direction = "vertical" ref = { messagesRef } >
102+ < Messages >
103+ { messages . length > 0 ? (
104+ orderedMessages ( messages ) . map ( ( message , i ) => {
105+ const { color, name, metadata } = messageData ( message ) ;
106+ return (
107+ < Element key = { message . date } >
108+ { isNotSameUser ( message , i ) && (
109+ < Stack
110+ paddingTop = { 2 }
111+ marginBottom = { 2 }
112+ align = "center"
113+ gap = { 2 }
114+ >
115+ < Avatar
116+ color = { color }
117+ alt = { metadata . username }
118+ src = { metadata . avatarUrl }
119+ />
120+ < Text block weight = "bold" >
121+ { name }
122+ </ Text >
123+ </ Stack >
124+ ) }
125+ < Text
126+ block
74127 style = { {
75- color,
76- fontWeight : 600 ,
77- marginBottom : '0.25rem' ,
78- marginTop : '0.5rem' ,
128+ wordBreak : 'break-word' ,
79129 } }
130+ marginBottom = { 2 }
80131 >
81- { name }
82- { currentUserId === message . userId && ' (you)' }
83- { ! metadata && ' (left)' }
84- </ div >
85- ) }
86- < div
87- style = { {
88- color : 'rgba(255, 255, 255, 0.7)' ,
89- fontWeight : 400 ,
90- marginBottom : '.25rem' ,
91- } }
92- >
93- { message . message . split ( '\n' ) . map ( m => (
94- < span key = { m } >
95- { m }
96- < br />
97- </ span >
98- ) ) }
99- </ div >
100- </ div >
101- ) ;
102- } )
103- ) : (
104- < div
105- style = { {
106- fontStyle : 'italic' ,
107- color : 'rgba(255, 255, 255, 0.5)' ,
108- } }
109- >
110- No messages, start sending some!
111- </ div >
112- ) }
113- </ Messages >
114- < AutosizeTextArea
115- useCacheForDOMMeasurements
116- value = { value }
117- onChange = { handleChange }
118- placeholder = "Send a message..."
119- style = { {
120- width : '100%' ,
121- minHeight : height ,
122- marginTop : '0.5rem' ,
123- } }
124- onKeyDown = { handleKeyDown }
125- onHeightChange = { setHeight }
126- />
127- </ Container >
132+ { message . message . split ( '\n' ) . map ( m => (
133+ < span key = { m } >
134+ { m }
135+ < br />
136+ </ span >
137+ ) ) }
138+ </ Text >
139+ </ Element >
140+ ) ;
141+ } )
142+ ) : (
143+ < Text variant = "muted" > No messages, start sending some!</ Text >
144+ ) }
145+ </ Messages >
146+ < Element marginTop = { 4 } >
147+ < Textarea
148+ autosize
149+ style = { { height : 'auto' , minHeight : 'auto' } }
150+ rows = { 1 }
151+ value = { value }
152+ onChange = { handleChange }
153+ placeholder = "Send a message..."
154+ onKeyDown = { handleKeyDown }
155+ />
156+ </ Element >
157+ </ Container >
158+ </ Collapsible >
128159 ) ;
129160} ;
0 commit comments