Skip to content

Instantly share code, notes, and snippets.

@julianocomg
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save julianocomg/1998a61070e732f4ddec to your computer and use it in GitHub Desktop.
Save julianocomg/1998a61070e732f4ddec to your computer and use it in GitHub Desktop.
A simple realtime application using the CotaPreco/Horus
/**
* @return {ReactComponent}
*/
var TagInput = React.createClass({
/**
* @return {Object}
*/
getDefaultProps() {
return {
onAddTag: function() {}
};
},
/**
* @param {KeyboardEvent} e
*/
handleSubmit(e) {
var input = e.target;
if (e.keyCode === 13) {
this.props.onAddTag(input.value);
return input.value = '';
}
},
render() {
return (
<div className="input">
<input type="text" placeholder="Type a tag" onKeyDown={this.handleSubmit}/>
</div>
);
}
});
/**
* @return {ReactComponent}
*/
var Tags = React.createClass({
/**
* @return {Object}
*/
getDefaultProps() {
return {
tags: [],
onRemoveTag: function() {}
};
},
/**
* @param {String} tag
*/
onRemoveTag(tag) {
return this.props.onRemoveTag(tag);
},
render() {
var tags = this.props.tags.map(function(tag) {
return (
<span className="tag" onClick={this.onRemoveTag.bind(this, tag)}>{tag}</span>
);
}.bind(this));
return (
<div className="tags">
{this.props.tags.length ? tags : 'Hey, add some tags here!'}
</div>
);
}
});
/**
* @return {ReactComponent}
*/
var Posts = React.createClass({
/**
* @return {Object}
*/
getDefaultProps() {
return {
posts: [],
tags: []
};
},
render() {
var self = this;
var posts = this.props.posts.map(function(post) {
return (
<li className="post">
<p>{post.content}</p>
<span>{new Date(post.time).toString().replace('GMT-0400 (AMT)', '')}</span>
{post.tags.map(function(tag) {
var match = self.props.tags.indexOf(tag) > -1 ? ' match' : '';
return (
<span className={'tag' + match}>{tag}</span>
);
})}
</li>
);
});
return (
<ul className="posts">
{posts}
</ul>
);
}
});
/**
* @return {ReactComponent}
*/
var Feed = React.createClass({
/**
* @return {Object}
*/
getInitialState() {
return {
connected: false,
tags: [],
posts: []
};
},
/**
* @param {String} tag
*/
onAddTag(tag) {
this.horus.send('ATAG ' + tag);
this.setState({
tags: this.state.tags.concat(tag)
});
},
/**
* @param {String} tag
*/
onRemoveTag(tag) {
this.horus.send('RTAG ' + tag);
var tags = this.state.tags;
tags.splice(tags.indexOf(tag), 1)
this.setState({
tags: tags
});
},
/**
* @param {Object} post
*/
onReceivePost(post) {
var posts = this.state.posts.filter(function(p) {
return p.content !== post.content;
});
posts.unshift(post);
this.setState({
posts: posts
});
},
/**
* @return {void}
*/
connect() {
var server = React.findDOMNode(this.refs.server).value;
this.horus = new WebSocket(server);
this.horus.onopen = function() {
this.setState({
connected: true
});
}.bind(this);
this.horus.onmessage = function(post) {
var post = JSON.parse(post.data);
this.onReceivePost(post);
}.bind(this);
this.horus.onclose = function() {
this.setState({
connected: false
});
}.bind(this);
},
/**
* @return {void}
*/
disconnect() {
this.horus.close();
},
render() {
return (
<div>
<div className="header">
<h1>Horus Feed</h1>
<p>Choose the <strong>tags</strong> that you want to get posts!</p>
<div className="connection">
<input
type="text"
ref="server"
defaultValue="ws://0.0.0.0:8000"
placeholder="ws://0.0.0.0:8000"
disabled={this.state.connected} />
{!this.state.connected ?
<button onClick={this.connect}>Connect</button> :
<button onClick={this.disconnect}>Disconnect</button>}
</div>
</div>
<div className="app">
{this.state.connected ?
<div>
<TagInput onAddTag={this.onAddTag} />
<Tags tags={this.state.tags} onRemoveTag={this.onRemoveTag} />
<Posts posts={this.state.posts} tags={this.state.tags} />
</div> :
<h3>Configure and connect to the Horus server!</h3>}
</div>
</div>
);
}
});
React.render(<Feed />, document.getElementById('feed'));
var Horus = require('horusjs');
var client = new Horus('udp://0.0.0.0', 7600);
var tags = [
'ipad',
'mobile',
'technology',
'apple'
];
var post = JSON.stringify({
content: "Prepare yourself for the new iPad with retina!",
time: Date.now(),
tags: tags
});
client.send({
tags: tags,
message: post
});
<html>
<head>
<meta charset="UTF-8">
<title>Horus Feed</title>
<link rel="stylesheet" href="styles.css"/>
<script src="https://fb.me/react-0.13.2.min.js"></script>
<script src="https://fb.me/JSXTransformer-0.13.2.js"></script>
</head>
<body>
<div id="feed"></div>
<script src="feed.js" type="text/jsx"></script>
</body>
</html>
#feed {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
color: #333;
font-size: 14px;
width: 525px;
margin: 0 auto;
}
.header h1 {
font-weight: 300;
font-size: 40px;
margin-top: 50px;
margin-bottom: 0;
}
.header p {
color: #888;
font-weight: 300;
font-size: 15px;
margin-bottom: 0;
margin-top: 10px;
}
.connection {
float: right;
margin-top: -18px;
}
.connection input {
border-radius: 2px;
border: 1px solid #cdcdcd;
padding: 1px 5px;
}
.connection input[disabled] {
border-color: green;
color: green;
}
.connection button {
height: 20px;
margin-left: 3px;
}
.app {
margin-top: 60px;
}
.input, .tags {
display: inline-block;
}
.input input {
font-size: 14px;
width: 130px;
height: 30px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 3px;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
margin-right: 10px;
}
.tags .tag, .posts .post .tag {
display: inline;
padding: .2em .6em .3em;
font-size: 100%;
font-weight: 400;
line-height: 1;
color: #fff;
background: #337ab7;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: .25em;
margin: 0 5px;
}
.tags .tag:hover {
cursor: pointer;
background: #266193;
}
.posts {
margin-top: 10px;
list-style: none;
padding: 0;
border-top: 1px solid #E4E4E4;
padding-top: 25px;
}
.posts li:not(:first-child) {
border-top: 1px solid #dcdcdc;
}
.posts .post {
padding: 20px 0;
}
.posts .post p {
margin-top: 0;
}
.posts .post span {
color: #999;
}
.posts .post .tag {
padding: 2px 7px;
font-weight: 300;
padding-top: 1px;
font-size: 12px;
background: #cdcdcd;
}
.posts .post .tag.match {
background: #337ab7;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment