JSFiddle - React, Tailwind, and code Playground

by Dumine Stefan Daniel

HTML

<div class='header'>
  <h1>WebSockets Demo</h1>
  <p>Open multiple tabs... and talk to yourself! Woo Fun!</p>
</div>

<main id='stream-chat'>
  
  <h1>Chat</h1>
  
  <div class='overflow'>
    <div id='messages'></div>
  </div>
  

  <div id='input-area'>
    <textarea id='input' type='text' disabled></textarea>
    <button id='send'>Choose Name</button>
  </div>

    
</main>

<div id='description'>
  <div class='des-title'>
    WebSockets Demo
  </div>
  <div class='des-info'>
    <div>
      WebSockets server hosted at <a href='https://stream-chat-demo.herokuapp.com' target="_blank">stream-chat-demo.herokuapp.com</a>.
    </div>
    <div>
      See the server code over on <a href="https://github.com/lioneltay/WebSocketDemoServer" target="_blank">GitHub</a>.
    </div>
  </div>
</div>

CSS

* { padding: 0; margin: 0; box-sizing: border-box; }

$background: white;
$header-color: #2B2B2B;
$odd-color: #111111;
$even-color: #171717;
$input-color: #090909;
$text-color: #919090;

$input-area-background: #1D1D1D;

body {
  font-family: 'Lato', sans-serif;
  min-height: 100vh;
  min-width: 100vw;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  background: $background;
}

//
// NAME-INPUT
//

#name-input {
  display: flex;
  justify-content: center;
  align-items: center;
}


//
// STREAM-CHAT
//

$header-text-color: #EEEEEE;
#stream-chat {
  h1 {
    background: $header-color;
    color: $header-text-color;
    text-align: center;
    font-weight: 300;
    padding: 1rem;
  }
  
  margin: 10px;
  min-width: 500px;
  max-width: 600px;
  width: 80%;
  min-height: 500px;
  max-height: 600px;
  height: 80%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}




//
// INPUT-AREA
//

#input-area {
  display: flex;
  min-height: 175px;
  flex-direction: column;
  background: $input-area-background;
  padding: 15px;
}

$button-background: #632F9F;
#send {
  align-self: flex-end;
  padding: 8px 15px;
  margin: 3px;
  background: $button-background;
  border: none;
  color: #F8EBEC;
  font-weight: 900;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 5px;
  box-shadow: 0 0 10px 0px darken($button-background, 10%);
}

$input-border-color: #282828;
#input {
  flex-grow: 1;
  border: 5px solid $input-border-color;
  flex-grow: 1;
  background: $input-color;
  color: $text-color;
  margin-bottom: .7em;
  resize: none;
  
  &:focus {
    outline: none;    
  }
}




//
// MESSAGES
//

$time-stamp-color: #626A6F;
$message-text-color: #BBB7AB;
$messages-padding-left: 12px;
#messages {
  min-height: 500px;
  background: linear-gradient(to bottom, $header-color, $input-area-background);
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  justify-content:...

JavaScript

var connection = new WebSocket('wss://stream-chat-demo.herokuapp.com')

const input = document.querySelector('#input')
const messages = document.querySelector('#messages')
const overflow = document.querySelector('.overflow')
const nameInput = document.querySelector('#name-input')
const sendButton = document.querySelector('#send')

let userName, userColor
let oddMessage = true
let autoScroll = true

// Respond to new connection
connection.addEventListener('open', (e) => {

})

// Respond to WebSocket messages
connection.addEventListener('message', (message) => {
	let resData
	
  try {
    resData = JSON.parse(message.data)
  } catch(error) {
		console.warn(error)
    console.warn('The message does not seem to be valid JSON.')
  }
  
	// Once message is received allow user to send another message
	input.removeAttribute('disabled')
	input.focus()
	
	if (resData.type === 'history') {
		resData.data.forEach(message => addMessage(message))
	}
	
	else if (resData.type === 'color') {
		userColor = resData.data
	}
	
	else if (resData.type === 'message') {
		addMessage(resData.data)
	}
  
  if (autoScroll) {
    overflow.scrollTop = overflow.scrollHeight - overflow.clientHeight;
  }
})

// Respond to user input
function sendMessage(message) {
  if (!message) return
    
  input.setAttribute('disabled', true)
  input.value = ''
  connection.send(message)

  // The first message will be the user's name
  if (!userName) {
    userName = message
    sendButton.innerHTML = 'Chat'
  }	
}

input.addEventListener('keydown', (e) => {
	if (e.keyCode === 13) {
		sendMessage(e.target.value)    	
	}
})

sendButton.addEventListener('click', (e) => {
  sendMessage(input.value)
})

// Add a message to message to DOM
function addMessage(data) {
	const newMsg = document.createElement('div')
  
	const time = timeString(data.timestamp)
	const messageParity = addMessage.odd ? 'odd' : 'even'
  addMessage.odd = !addMessage.odd
  newMsg.setAttribute('class', `${messageParity} message`)
 ...