Skip to content

Commit

Permalink
Merge pull request #17 from tylercrosse/styles
Browse files Browse the repository at this point in the history
Styles
  • Loading branch information
tylercrosse authored Mar 14, 2017
2 parents bb92b06 + 7bdc9f3 commit b5afe5a
Show file tree
Hide file tree
Showing 14 changed files with 302 additions and 121 deletions.
63 changes: 48 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,61 @@
[![Build Status](https://semaphoreci.com/api/v1/tcrosse/gitter-clone/branches/master/badge.svg)](https://semaphoreci.com/tcrosse/gitter-clone)
[![codecov](https://codecov.io/gh/tylercrosse/gitter-clone/branch/master/graph/badge.svg)](https://codecov.io/gh/tylercrosse/gitter-clone)

<div align="center">
</div>

This is app was built as portfolio piece representing a subset of the features of Troupe Technology's wonderful chat app, [Gitter](https://gitter.im/). I'm currently looking for a new position - Hire me!

---
### Demo

You can test a fully working live demo at http://138.68.24.248:3333/

---
### Major features

- Create Channels
- Send Messages to all subscribed clients on channel
- Load previous messages in channel
- MD / syntax highlighting support for messages
- Messages grouped into bursts
- Create Channels
- Load previous messages in channel
- Send Messages to all subscribed clients on channel

---
### Built with

<div align="center">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/react.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/redux.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/webpack.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/express.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/mongodb.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/jest.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/semaphor.svg">
<img height="80" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/digitalocean.svg">
</div>
##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/react.svg"> [React](https://facebook.github.io/react/)

React makes it really easy to focus on the view in a declarative way. I like that it makes it easy to write composable, testable UI. Routing is handled by [react router](https://reacttraining.com/react-router/).

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/redux.svg"> [Redux](http://redux.js.org/)

Redux is where the fun is at. Maintain a flat minimal state, with dictionary of normalized objects. I use [reselect](https://github.com/reactjs/reselect) to compute derived data. [Redux devtools](https://github.com/zalmoxisus/redux-devtools-extension) are also great, I kept it enabled on production for anyone wanting to easily take a look at the app's state.

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/webpack.svg"> [Webpack 2](https://webpack.js.org/)

Fantastic code bundler once you get past the learning curve. I use it for a number of things including: transpile ES2015+ javascript to ES5 with [Babel](https://babeljs.io/), compile [Sass](http://sass-lang.com/) into css, optimize assets, hot reload code, build minimized split production code, + more.

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/express.svg"> [Express](https://expressjs.com/)

It's nice to have JS everywhere. Express is fast and minimal. The backend is pretty simple with a router, a few controllers, and basic db interactions. Logging handled by [winston](https://github.com/winstonjs/winston).

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/mongodb.svg"> [MongoDB](https://www.mongodb.com/)

This project doesn't currently require a ton of data persistence. MongoDB + [Mongoose](http://mongoosejs.com/) make it easy to quickly update the Schema. If the project continues to grow I will probably switch to a relational DB. Also Mongo is still trendy.

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/jest.svg"> [Jest](http://facebook.github.io/jest/)

Unit tests run by Jest. If you haven't seen Jest recently, you should take another look. [Enzyme](https://github.com/airbnb/enzyme) is used for React support and [SuperTest](https://github.com/visionmedia/supertest) is used for HTTP assertions. [Enzyme-to-JSON](https://github.com/adriantoine/enzyme-to-json) is also great and worth checking out in conjunction with the other test utilities.

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/semaphor.svg"> [SemaphoreCI](https://semaphoreci.com/)

Continuous integration handled by the super fast SemaphoreCI. Passing merges to master are auto deployed with help from [pm2](http://pm2.keymetrics.io/).

##### <img height="20" src="https://cdn.rawgit.com/tylercrosse/gitter-clone/assets/src/client/assets/img/digitalocean.svg"> [Digital Ocean](https://www.digitalocean.com/)

Application hosted on Ubuntu Digital Ocean droplet. SSH is fun!

---
### Setup

If you don't have [yarn](https://yarnpkg.com/en/) commands can be run with `npm`. First, clone and cd into the repo and install the dependencies.
Expand All @@ -41,16 +69,21 @@ $ yarn install

Additional commands:
##### `yarn dev`
- Start development server on 127.0.0.1:3333
- Start development server on `127.0.0.1:3333`

##### `yarn build`
- Build a production version of the app.

##### `yarn start`
- Start production server on 127.0.0.1:3333 to serve built app. Requires the build command to have already been run.
- Start production server on `127.0.0.1:3333` to serve built app. Requires the build command to have already been run.

##### `yarn test`
- Run all of the projects tests using jest.

##### `yarn lint`
- Lint all of the projects javascript files using eslint.

---
### Contributing

Thank you for your interest! Unfortunately, I'm not currently taking contributions.
17 changes: 13 additions & 4 deletions config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,24 @@ module.exports = merge(config, {
},
include: [path.resolve(__dirname, '../src')]
}, {
test: /\.css?$/,
loaders: ['style-loader', 'raw-loader']
}, {
// test: /\.css?$/,
// loaders: ['style-loader', 'raw-loader']
// }, {
test: /\.scss$/,
use : [
loaders : [
{
loader: 'style-loader'
}, {
loader: 'css-loader',
}, {
loader: 'postcss-loader',
options: {
plugins() {
return [
require('autoprefixer')
]
}
}
}, {
loader: 'resolve-url-loader'
}, {
Expand Down
9 changes: 9 additions & 0 deletions config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ module.exports = merge(config, {
use: [
{
loader: 'css-loader',
}, {
loader: 'postcss-loader',
options: {
plugins() {
return [
require('autoprefixer')
]
}
}
}, {
loader: 'resolve-url-loader'
}, {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"winston": "^2.3.1"
},
"devDependencies": {
"autoprefixer": "^6.7.6",
"autoprefixer": "^6.7.7",
"babel-cli": "^6.22.2",
"babel-core": "^6.21.0",
"babel-eslint": "^7.1.1",
Expand Down
41 changes: 21 additions & 20 deletions src/client/components/chatmain/chatmain.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import '../../mixins/_variables.scss';

.loading-container {
background-color: rgba(0, 0, 0, 0.5);
background-color: $trans-black5;
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -14,8 +14,8 @@
width: 80px;
height: 80px;
border-radius: 100%;
border: 10px solid rgba(255, 255, 255, 0.2);
border-top-color: #FFF;
border: 10px solid $trans-white2;
border-top-color: $white;
animation: spin 1s infinite linear;
}

Expand Down Expand Up @@ -66,7 +66,7 @@
flex-shrink: 0;
display: flex;
width: 70px;
border-left: 1px solid #f1f1f1;
border-left: 1px solid $seashell;

.roster {
list-style: none;
Expand All @@ -87,8 +87,8 @@
}

.status {
background-color: #fff;
box-shadow: inset 0 0 0 2px #fcb316;
background-color: $white;
box-shadow: inset 0 0 0 2px $supernova;
position: absolute;
top: 5px;
left: -6px;
Expand All @@ -98,7 +98,7 @@
justify-content: center;
width: 7px;
height: 7px;
border: 2px solid white;
border: 2px solid $white;
border-radius: 80px;
box-sizing: content-box;
}
Expand All @@ -121,7 +121,7 @@
padding-right: 18px;

img {
border: 3px solid white;
border: 3px solid $white;
border-radius: 4px;
}
}
Expand All @@ -132,15 +132,15 @@
overflow: hidden;
display: inline-block;
max-width: 100%;
color: white;
color: $white;
font-size: 24px;
line-height: 40px;
font-weight: 300;
text-overflow: ellipsis;
}

.chat-user-avatar {
border-left: 1px solid rgba(0, 0, 0, 0.1);
border-left: 1px solid $trans-black1;
padding: 8px 0 8px 19px;
margin-right: 19px;
}
Expand All @@ -164,7 +164,7 @@
overflow-y: auto;
flex-grow: 1;
flex-shrink: 1;
background-color: #fdfdfd;
background-color: $romance;

.chat-item {
transition: background-color 0.2s linear;
Expand Down Expand Up @@ -387,7 +387,7 @@

.chat-input {
align-self: flex-end;
background-color: #fdfdfd;
background-color: $romance;
flex-shrink: 0;
width: 100%;
border-top: 1px solid rgba(0, 0, 0, 0.05);
Expand All @@ -414,11 +414,11 @@
min-height: 44px;
margin: 0;
padding: 0;
background-color: #fff;
background-color: $white;
box-shadow: none;
border: 0;
outline: none;
color: black;
color: $black;
font-size: 1em;
line-height: 1.38em;
resize: none;
Expand All @@ -428,10 +428,11 @@
position: absolute;
right: 0;
top: 0;
height: 50px;
height: 42px;
background-color: $maroon;
color: white;
color: $white;
border-radius: 4px;
margin-right: 4px;
border: 0;
}
}
Expand All @@ -447,8 +448,8 @@
text-decoration: none;
border: none;
border-radius: 6px;
background: #ea9448;
color: #fff;
background: $sea-buckthorn;
color: $white;
-webkit-flex-shrink: 0;
-ms-flex-negative: 0;
flex-shrink: 0;
Expand All @@ -462,11 +463,11 @@
box-sizing: border-box;
display: inline-block;
padding: 9.6px 42px;
background-color: #46bc99;
background-color: $puerto-rico;
border: none;
border-radius: 6px;
outline: none;
color: #ffffff;
color: $white;
text-transform: uppercase;
letter-spacing: 0.1em;
text-align: center;
Expand Down
10 changes: 8 additions & 2 deletions src/client/components/chatmenu/ChatMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import {
openCreateRoomModal,
closeModal,
Expand Down Expand Up @@ -40,9 +41,14 @@ export class ChatMenu extends React.Component {
<nav className="minibar">
<div className="minibar-inner">
<ul>
<li className="minibar-convos">G</li>
<li className="minibar-convos">
<Link
to={'/'}
className="minibar-button"
>G</Link>
</li>
<li className="minibar-search">
<button className="minibar-button" onClick={this.handleMinibarButtonClick}>
<button className="minibar-button minibar-button-search" onClick={this.handleMinibarButtonClick}>
Q
</button>
</li>
Expand Down
8 changes: 4 additions & 4 deletions src/client/components/chatmenu/ChatMenu.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ describe('<ChatMenu />', () => {
const { component } = setup();
const wrapper = mount(component);
expect(wrapper.state().active).toBeFalsy();
wrapper.find('.minibar-button').simulate('click');
wrapper.find('.minibar-button-search').simulate('click');
expect(wrapper.state().active).toBeTruthy();
wrapper.find('.minibar-button').simulate('click');
wrapper.find('.minibar-button-search').simulate('click');
expect(wrapper.state().active).toBeFalsy();
});

it('should toggle active state onMouseLeave', () => {
const { component } = setup();
const wrapper = mount(component);
expect(wrapper.state().active).toBeFalsy();
wrapper.find('.minibar-button').simulate('click');
wrapper.find('.minibar-button-search').simulate('click');
expect(wrapper.state().active).toBeTruthy();
// trouble simulating clientX on synthetic mouseLeave event
wrapper.instance().handleMouseLeave({clientX: 400});
Expand All @@ -67,7 +67,7 @@ describe('<ChatMenu />', () => {
expect(wrapper.state().active).toBeFalsy();
expect(wrapper.find('.chat-menu-panel').hasClass('active'))
.toBeFalsy();
wrapper.find('.minibar-button').simulate('click');
wrapper.find('.minibar-button-search').simulate('click');
expect(wrapper.state().active).toBeTruthy();
expect(wrapper.find('.chat-menu-panel').hasClass('active'))
.toBeTruthy();
Expand Down
Loading

0 comments on commit b5afe5a

Please sign in to comment.