Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
brandly committed Mar 16, 2015
0 parents commit 1c0b4c6
Show file tree
Hide file tree
Showing 22 changed files with 803 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .editorconfig
@@ -0,0 +1,11 @@
# http://editorconfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
node_modules
*.log
.DS_Store

dist
4 changes: 4 additions & 0 deletions README.md
@@ -0,0 +1,4 @@
```shell
$ npm install
$ npm start
```
25 changes: 25 additions & 0 deletions package.json
@@ -0,0 +1,25 @@
{
"name": "irc",
"version": "0.0.0",
"description": "",
"private": true,
"scripts": {
"start": "nw"
},
"main": "src/index.html",
"author": "",
"license": "MIT",
"dependencies": {
"classnames": "^1.1.4",
"flux": "^2.0.1",
"immutable": "^3.6.4",
"keymirror": "^0.1.1",
"nw": "^0.12.0",
"object-assign": "^2.0.0",
"react": "^0.13.0",
"slate-irc": "^0.8.1"
},
"devDependencies": {
"babel": "^4.7.12"
}
}
26 changes: 26 additions & 0 deletions src/index.html
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>IRC</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" href="static/reset.css">
<link rel="stylesheet" href="static/style.css">
</head>
<body>
<div id="main"></div>
<script>
// Prevents "document is not defined" error in React
// http://stackoverflow.com/questions/25402492/nw-reactjs-requring-in-multiple-files-does-not-work
global.document = window.document;
global.navigator = window.navigator;

require('babel/register');
require('./js/main');
</script>
</body>
</html>
25 changes: 25 additions & 0 deletions src/js/actions/channel-actions.js
@@ -0,0 +1,25 @@
import ircDispatcher from '../dispatchers/irc-dispatcher';
import ActionTypes from '../constants/action-types';

module.exports = {
requestJoinChannel({channelName}) {
ircDispatcher.dispatch({
type: ActionTypes.REQUEST_JOIN_CHANNEL,
channelName
})
},

selectChannel({channelName}) {
ircDispatcher.dispatch({
type: ActionTypes.SELECT_CHANNEL,
channelName
});
},

receiveMessage({channel, from, message, when}) {
ircDispatcher.dispatch({
type: ActionTypes.RECEIVE_MESSAGE,
channel, from, message, when
});
}
};
11 changes: 11 additions & 0 deletions src/js/actions/connection-actions.js
@@ -0,0 +1,11 @@
import ircDispatcher from '../dispatchers/irc-dispatcher';
import ActionTypes from '../constants/action-types';

module.exports = {
requestConnection({realName, nickname, password, server, port}) {
ircDispatcher.dispatch({
type: ActionTypes.REQUEST_CONNECTION,
realName, nickname, password, server, port
})
}
};
55 changes: 55 additions & 0 deletions src/js/components/channel-list.js
@@ -0,0 +1,55 @@
import React from 'react';
import { addons } from 'react/addons';
import Immutable from 'immutable';
import classNames from 'classnames';
import ChannelStore from '../stores/channel-store';
import ChannelActions from '../actions/channel-actions';

const component = React.createClass({
mixins: [addons.PureRenderMixin],

componentWillMount() {
ChannelStore.addChangeListener(this._onChange);
},

getInitialState() {
return {
channels: Immutable.List(),
selectedChannel: {}
};
},

_onChange() {
this.setState({
channels: ChannelStore.getChannels(),
selectedChannel: ChannelStore.getSelectedChannel()
});
},

selectChannel(channelName) {
ChannelActions.selectChannel({ channelName });
},

render() {
const channelElements = this.state.channels.sort().map((channel, i) => {
const classes = classNames({
'channel-list-item': true,
'is-selected': channel.name === this.state.selectedChannel.name
});

return (
<li className={classes}
key={i}
onClick={this.selectChannel.bind(this, channel.name)}>{channel.name}</li>
);
});

return (
<ul className="scrolling-panel channel-list">
{channelElements.toArray()}
</ul>
);
}
});

module.exports = component;
27 changes: 27 additions & 0 deletions src/js/components/compose-message.js
@@ -0,0 +1,27 @@
import React from 'react';
import { addons } from 'react/addons';

const component = React.createClass({
mixins: [addons.PureRenderMixin],

getInitialState() {
return {};
},

handleFormSubmission(event) {
event.preventDefault();
// TODO: fire action
},

render() {
return (
<form className="form-panel" onSubmit={this.handleFormSubmission}>
<input type="text"
placeholder="new message"
required />
</form>
);
}
});

module.exports = component;
79 changes: 79 additions & 0 deletions src/js/components/connection-creator.js
@@ -0,0 +1,79 @@
import React from 'react';
import { addons } from 'react/addons';
import ConnectionActions from '../actions/connection-actions';

const component = React.createClass({
mixins: [addons.PureRenderMixin],

getInitialState() {
return {isConnecting: false};
},

handleChange(key, event) {
this.setState({
[key]: event.target.value
});
},

handleFormSubmission(event) {
event.preventDefault();
this.setState({isConnecting: true});

const { realName, nickname, password, server, port } = this.state;
ConnectionActions.requestConnection({
realName, nickname, password, server, port: parseInt(port, 10)
});
},

render() {
const inputGroupClass = 'input-group';
const serverOptions = ['chat.freenode.net'];

return (
<form className="connection-creator" onSubmit={this.handleFormSubmission}>
<div className={inputGroupClass}>
<label>Real Name</label>
<input type="text"
autoFocus
required
onChange={this.handleChange.bind(this, 'realName')} />
</div>

<div className={inputGroupClass}>
<label>Nickname</label>
<input type="text"
required
onChange={this.handleChange.bind(this, 'nickname')} />
</div>

<div className={inputGroupClass}>
<label>Password</label>
<input type="password"
onChange={this.handleChange.bind(this, 'password')} />
</div>

<div className={inputGroupClass}>
<label>Server</label>
<select required
onChange={this.handleChange.bind(this, 'server')}>
<option value=""></option>
{serverOptions.map((n, i) => {
return <option value={n} key={i}>{n}</option>
})}
</select>
</div>

<div className={inputGroupClass}>
<label>Port</label>
<input type="number"
required
onChange={this.handleChange.bind(this, 'port')} />
</div>

<input type="submit" disabled={this.state.isConnecting} />
</form>
);
}
});

module.exports = component;
38 changes: 38 additions & 0 deletions src/js/components/irc.js
@@ -0,0 +1,38 @@
import React from 'react';
import { addons } from 'react/addons';
import MessageCenter from './message-center';
import ConnectionCreator from './connection-creator';
import ConnectionStore from '../stores/connection-store';

const app = React.createClass({
mixins: [addons.PureRenderMixin],

componentWillMount() {
ConnectionStore.addChangeListener(this._onChange);
},

getInitialState() {
return {
hasConnection: false
};
},

_onChange() {
this.setState({
hasConnection: !!ConnectionStore.getConnection()
});
},

render() {
return (
<div className="irc">
{this.state.hasConnection ?
<MessageCenter /> :
<ConnectionCreator />
}
</div>
);
}
});

module.exports = app;
43 changes: 43 additions & 0 deletions src/js/components/join-channel.js
@@ -0,0 +1,43 @@
import React from 'react';
import { addons } from 'react/addons';
import ChannelActions from '../actions/channel-actions';

const component = React.createClass({
mixins: [addons.PureRenderMixin],

getInitialState() {
return {
channelName: null
};
},

setChannelName(channelName) {
this.setState({ channelName });
},

handleChange(event) {
this.setChannelName(event.target.value);
},

handleFormSubmission(event) {
event.preventDefault();
ChannelActions.requestJoinChannel({
channelName: this.state.channelName
});
this.setChannelName(null);
},

render() {
return (
<form className="form-panel" onSubmit={this.handleFormSubmission}>
<input type="text"
placeholder="join channel"
required
onChange={this.handleChange} />
<input type="submit" value="+" />
</form>
);
}
});

module.exports = component;

0 comments on commit 1c0b4c6

Please sign in to comment.