LOADING...

Preview

Pen ID
Unlock Campus Themeforest adv

 

Code
CSS
* {
  box-sizing: border-box;
}

html, body, #app {
  height: 100%;
  overflow: hidden;
}

body {
  font-family: "Open Sans";
}

div.wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-flow: column;
      flex-flow: column;
  height: 100%;
}

div.main-window {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
}

div.user-list-container {
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-flow: column;
      flex-flow: column;
  border-left: 1px solid #ddd;
}
div.user-list-container h2 {
  padding: 8px;
  font-size: 12px;
  text-align: center;
  color: gray;
  border-bottom: 1px solid whitesmoke;
}
div.user-list-container .user-list {
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
  overflow-y: auto;
}
div.user-list-container .user-list-item {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  font-size: 12px;
}
div.user-list-container .user-list-item img {
  margin: 5px;
  border-radius: 50%;
}

div.message-list-container {
  background: whitesmoke;
  font-size: 13px;
  -webkit-box-flex: 2;
      -ms-flex: 2;
          flex: 2;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-flow: column;
      flex-flow: column;
}
div.message-list-container .message-list {
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
  overflow-y: auto;
}
div.message-list-container .message {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  padding: 0 10px;
}
div.message-list-container .message img {
  border-radius: 50%;
}
div.message-list-container .message .message-text {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-flow: column;
      flex-flow: column;
  -webkit-box-flex: 3;
      -ms-flex: 3;
          flex: 3;
  line-height: 1.3em;
  padding: 10px;
}
div.message-list-container .message .message-text strong {
  font-weight: bold;
}
div.message-list-container .message .message-text em {
  font-style: italic;
}
div.message-list-container .message .message-text a {
  color: #336633;
}
div.message-list-container .message .message-text .message-username {
  font-weight: bold;
  font-size: 14px;
  margin-bottom: 4px;
}
div.message-list-container .message .message-text .message-username a {
  text-decoration: none;
  color: black;
}
div.message-list-container .message .message-text .message-username span.message-time {
  font-weight: normal;
  font-size: 12px;
  color: #999;
}
div.message-list-container .message-event {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  text-align: center;
  color: #aaa;
  width: 100%;
  font-size: 12px;
  padding: 10px;
}

.register-error {
  background: red;
  padding: 10px 10px 10px 15px;
  font-size: 12px;
  color: white;
}

form {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
}
form input {
  -webkit-box-flex: 4;
      -ms-flex: 4;
          flex: 4;
  border: 0;
  padding: 10px;
  border-top: 1px solid #ddd;
}
form input:focus {
  outline: 0;
}
form button {
  border: 0;
  background: #55acee;
  color: white;
  font-size: 12px;
  padding: 10px 10px 10px 34px;
  font-family: "Helvetica Neue";
  border-radius: 5px;
  cursor: pointer;
  font-weight: bold;
  background-image: url(//g.twimg.com/Twitter_logo_white.png);
  background-position: 10px 50%;
  background-size: auto 14px;
  background-repeat: no-repeat;
}

.wrapper > h1 {
  padding: 20px;
  background: #222;
  color: #eee;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  font-weight: bold;
}
.wrapper > h1 .header-info {
  font-size: 11px;
  color: #ddd;
  font-weight: normal;
}
JS
/**
 * Build up Firebase references
 */
const _fbBase = new Firebase('https://amber-heat-810.firebaseio.com');
const _fbMessages = _fbBase.child('messages');
const _fbUsers = _fbBase.child('users');

/**
 * Local cache of users in a Map
 * Used to track who is here.
 */
const _users = new Map();

/**
 * mardown-it instance to parse chat messages
 */
const _md = window.markdownit({
  linkify: true,
});

/**
 * Message Component
 * Renders an individual message or event in the list
 */
class Message extends React.Component {
  render() {
    /*
     * Run message through markdown-it.
     * dangerouslySetInnerHTML is necessary b/c React escapes HTML by defaukt
     */
    const messageText = 
; /** * Event messages * User has joined/left room */ if (this.props.message.type === 'event') { // Buggy, removing for now. return null; // return
// {messageText} //
; } return
{'@' + this.props.message.username} {' '} {moment(this.props.message.timestamp).format('h:mma')}
{messageText}
; } } /** * MessageList Component * Renders the list of chat messages */ class MessageList extends React.Component { /** * Anytime new data comes in, scroll to bottom * TODO: Could be more intelligent here and only * scroll when user is not browsing back up the list. */ componentDidUpdate() { let list = this.refs.messageList.getDOMNode(); list.scrollTop = list.scrollHeight; } render() { return
{this.props.messages.map((message, index) => )}
; } } class UserList extends React.Component { render() { return

{this.props.users.length ? this.props.users.length : 'No'} user{this.props.users.length !== 1 ? 's' : ''} chatting

{this.props.users.map((user) => )}
; } } class UserListItem extends React.Component { render() { return
{this.props.user._isCurrentUser ? 'You' : '@' + this.props.user.twitter.username}
; } } /** * MessageForm Component * Form input for adding new messages */ class MessageForm extends React.Component { componentDidMount() { this.refs.messageText.getDOMNode().focus(); } /** * Submit the new Message * @param {object} event - onsubmit event */ _onSubmit(event) { event.preventDefault(); const user = _users.get(this.props.userId); const message = this.refs.messageText.getDOMNode().value.trim(); if (!message.length) { return; } _fbMessages.push({ type: "userMessage", user_avatar: user.twitter.cachedUserProfile.profile_image_url_https, username: user.twitter.username, text: this.refs.messageText.getDOMNode().value, timestamp: +new Date, }); event.target.reset(); } render() { return
; } } /** * RegisterForm Component * Renders the registration form when a user enters the chat window */ class RegisterForm extends React.Component { render() { return
; } } /** * Application Component * Main component */ class Application extends React.Component { constructor() { super(); this._messages = []; this._username = null; this.state = { messages: [], user: null, users: [], userId: null, joinError: null, }; if (location.href.indexOf('fullpage') !== -1) { this.state.joinError = 'View this pen in the Editor in order to join the chat. Codepen\'s fullpage view blocks popups, so Twitter authentication does not work.'; } this._join = this._join.bind(this); this._createUsersArray = this._createUsersArray.bind(this); } componentWillMount() { /** * onAuth fires anytime the auth status of this user changes */ _fbBase.onAuth((authData) => { if (!authData) { return; } this._username = authData.twitter.username; _fbUsers.push(authData); this.setState({ user: this._username, joinError: null, }); }); /** * Faster to call once.value, then listen to * new children after that */ _fbMessages.orderByKey().once('value', (dataSnapshot) => { dataSnapshot.forEach((snapshot) => { this._messages.push(snapshot.val()); }); this.setState({messages: this._messages}); const last = this._messages[this._messages.length - 1]; _fbMessages .orderByChild('timestamp') .startAt(last.timestamp + 1) .on('child_added', (snapshot) => { this._messages.push(snapshot.val()); this.setState({messages: this._messages}); }); }); _fbUsers.on('child_added', (snapshot) => { const key = snapshot.key(); const userObj = snapshot.val(); _users.set(key, snapshot.val()); this._createUsersArray(); if (userObj.twitter.username === this._username) { this.setState({userId: key}); const disconnectListener = _fbUsers.child(key); disconnectListener.onDisconnect().remove(); } }); _fbUsers.on('child_removed', (snapshot) => { _users.delete(snapshot.key()); this._createUsersArray(); }); } _createUsersArray() { let users = []; _users.forEach((user, key) => { user._isCurrentUser = user.twitter.username === this._username; users.push(user) }); this.setState({users}); } /** * Add the user to the chat * @param {object} event - the onsubmit event */ _join(event) { event.preventDefault(); _fbBase.authWithOAuthPopup("twitter", (error, authData) => { if (error) { this.setState({joinError: `Error authenticating with Twitter: ${error.message}`}); } else { _fbMessages.push({ type: "event", text: `@${authData.twitter.username} has joined the room`, }); } }, { remember: "sessionOnly" }); } render() { return

CHATPEN
{this.state.user ? `Chatting as @${this.state.user}` : }

{this.state.userId ? : null}
{this.state.joinError ?

{this.state.joinError}

: null}
; } } /** * Get this party started! */ React.render(, document.getElementById('app'));

Description

Multiuser chat built with React and Firebase. Note that this is on the Firebase free plan, so if more than 50 users are on it things may go south.
Term
Mon, 11/27/2017 - 21:23

Related Codes

Pen ID
Pen ID
Pen ID
Square Adv