-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Chris Sevilleja
committed
Oct 19, 2014
1 parent
cf9cc4b
commit 65e4200
Showing
18 changed files
with
697 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,3 +26,5 @@ node_modules | |
|
||
# Users Environment Variables | ||
.lock-wscript | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
var TweetsApp = require('./components/TweetsApp.react'); | ||
|
||
// Snag the initial state that was passed from the server side | ||
var initialState = JSON.parse(document.getElementById('initial-state').innerHTML) | ||
|
||
// Render the components, picking up where react left off on the server | ||
React.renderComponent( | ||
<TweetsApp tweets={initialState}/>, | ||
document.getElementById('react-app') | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
|
||
module.exports = Loader = React.createClass({ | ||
render: function(){ | ||
return ( | ||
<div className={"loader " + (this.props.paging ? "active" : "")}> | ||
<img src="svg/loader.svg" /> | ||
</div> | ||
) | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
|
||
module.exports = NotificationBar = React.createClass({ | ||
render: function(){ | ||
var count = this.props.count; | ||
return ( | ||
<div className={"notification-bar" + (count > 0 ? ' active' : '')}> | ||
<p>There are {count} new tweets! <a href="#top" onClick={this.props.onShowNewTweets}>Click here to see them.</a></p> | ||
</div> | ||
) | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
|
||
module.exports = Tweet = React.createClass({ | ||
render: function(){ | ||
var tweet = this.props.tweet; | ||
return ( | ||
<li className={"tweet" + (tweet.active ? ' active' : '')}> | ||
<img src={tweet.avatar} className="avatar"/> | ||
<blockquote> | ||
<cite> | ||
<a href={"http://www.twitter.com/" + tweet.screenname}>{tweet.author}</a> | ||
<span className="screen-name">@{tweet.screenname}</span> | ||
</cite> | ||
<span className="content">{tweet.body}</span> | ||
</blockquote> | ||
</li> | ||
) | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
var Tweet = require('./Tweet.react.js'); | ||
|
||
module.exports = Tweets = React.createClass({ | ||
|
||
// Render our tweets | ||
render: function(){ | ||
|
||
// Build list items of single tweet components using map | ||
var content = this.props.tweets.map(function(tweet){ | ||
return ( | ||
<Tweet key={tweet.twid} tweet={tweet} /> | ||
) | ||
}); | ||
|
||
// Return ul filled with our mapped tweets | ||
return ( | ||
<ul className="tweets">{content}</ul> | ||
) | ||
|
||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
/** @jsx React.DOM */ | ||
|
||
var React = require('react'); | ||
var Tweets = require('./Tweets.react.js'); | ||
var Loader = require('./Loader.react.js'); | ||
var NotificationBar = require('./NotificationBar.react.js'); | ||
|
||
// Export the TweetsApp component | ||
module.exports = TweetsApp = React.createClass({ | ||
|
||
// Method to add a tweet to our timeline | ||
addTweet: function(tweet){ | ||
|
||
// Get current application state | ||
var updated = this.state.tweets; | ||
|
||
// Increment the unread count | ||
var count = this.state.count + 1; | ||
|
||
// Increment the skip count | ||
var skip = this.state.skip + 1; | ||
|
||
// Add tweet to the beginning of the tweets array | ||
updated.unshift(tweet); | ||
|
||
// Set application state | ||
this.setState({tweets: updated, count: count, skip: skip}); | ||
|
||
}, | ||
|
||
// Method to get JSON from server by page | ||
getPage: function(page){ | ||
|
||
// Setup our ajax request | ||
var request = new XMLHttpRequest(), self = this; | ||
request.open('GET', 'page/' + page + "/" + this.state.skip, true); | ||
request.onload = function() { | ||
|
||
// If everything is cool... | ||
if (request.status >= 200 && request.status < 400){ | ||
|
||
// Load our next page | ||
self.loadPagedTweets(JSON.parse(request.responseText)); | ||
|
||
} else { | ||
|
||
// Set application state (Not paging, paging complete) | ||
self.setState({paging: false, done: true}); | ||
|
||
} | ||
}; | ||
|
||
// Fire! | ||
request.send(); | ||
|
||
}, | ||
|
||
// Method to show the unread tweets | ||
showNewTweets: function(){ | ||
|
||
// Get current application state | ||
var updated = this.state.tweets; | ||
|
||
// Mark our tweets active | ||
updated.forEach(function(tweet){ | ||
tweet.active = true; | ||
}); | ||
|
||
// Set application state (active tweets + reset unread count) | ||
this.setState({tweets: updated, count: 0}); | ||
|
||
}, | ||
|
||
// Method to load tweets fetched from the server | ||
loadPagedTweets: function(tweets){ | ||
|
||
// So meta lol | ||
var self = this; | ||
|
||
// If we still have tweets... | ||
if(tweets.length > 0) { | ||
|
||
// Get current application state | ||
var updated = this.state.tweets; | ||
|
||
// Push them onto the end of the current tweets array | ||
tweets.forEach(function(tweet){ | ||
updated.push(tweet); | ||
}); | ||
|
||
// This app is so fast, I actually use a timeout for dramatic effect | ||
// Otherwise you'd never see our super sexy loader svg | ||
setTimeout(function(){ | ||
|
||
// Set application state (Not paging, add tweets) | ||
self.setState({tweets: updated, paging: false}); | ||
|
||
}, 1000); | ||
|
||
} else { | ||
|
||
// Set application state (Not paging, paging complete) | ||
this.setState({done: true, paging: false}); | ||
|
||
} | ||
}, | ||
|
||
// Method to check if more tweets should be loaded, by scroll position | ||
checkWindowScroll: function(){ | ||
|
||
// Get scroll pos & window data | ||
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); | ||
var s = document.body.scrollTop; | ||
var scrolled = (h + s) > document.body.offsetHeight; | ||
|
||
// If scrolled enough, not currently paging and not complete... | ||
if(scrolled && !this.state.paging && !this.state.done) { | ||
|
||
// Set application state (Paging, Increment page) | ||
this.setState({paging: true, page: this.state.page + 1}); | ||
|
||
// Get the next page of tweets from the server | ||
this.getPage(this.state.page); | ||
|
||
} | ||
}, | ||
|
||
// Set the initial component state | ||
getInitialState: function(props){ | ||
|
||
props = props || this.props; | ||
|
||
// Set initial application state using props | ||
return { | ||
tweets: props.tweets, | ||
count: 0, | ||
page: 0, | ||
paging: false, | ||
skip: 0, | ||
done: false | ||
}; | ||
|
||
}, | ||
|
||
componentWillReceiveProps: function(newProps, oldProps){ | ||
this.setState(this.getInitialState(newProps)); | ||
}, | ||
|
||
// Called directly after component rendering, only on client | ||
componentDidMount: function(){ | ||
|
||
// Preserve self reference | ||
var self = this; | ||
|
||
// Initialize socket.io | ||
var socket = io.connect(); | ||
|
||
// On tweet event emission... | ||
socket.on('tweet', function (data) { | ||
|
||
// Add a tweet to our queue | ||
self.addTweet(data); | ||
|
||
}); | ||
|
||
// Attach scroll event to the window for infinity paging | ||
window.addEventListener('scroll', this.checkWindowScroll); | ||
|
||
}, | ||
|
||
// Render the component | ||
render: function(){ | ||
|
||
return ( | ||
<div className="tweets-app"> | ||
<Tweets tweets={this.state.tweets} /> | ||
<Loader paging={this.state.paging}/> | ||
<NotificationBar count={this.state.count} onShowNewTweets={this.showNewTweets}/> | ||
</div> | ||
) | ||
|
||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module.exports = { | ||
twitter: { | ||
consumer_key: 'put-yours-here', | ||
consumer_secret: 'put-yours-here', | ||
access_token_key: 'put-yours-here', | ||
access_token_secret: 'put-yours-here' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
var mongoose = require('mongoose'); | ||
|
||
// Create a new schema for our tweet data | ||
var schema = new mongoose.Schema({ | ||
twid : String | ||
, active : Boolean | ||
, author : String | ||
, avatar : String | ||
, body : String | ||
, date : Date | ||
, screenname : String | ||
}); | ||
|
||
// Create a static getTweets method to return tweet data from the db | ||
schema.statics.getTweets = function(page, skip, callback) { | ||
|
||
var tweets = [], | ||
start = (page * 10) + (skip * 1); | ||
|
||
// Query the db, using skip and limit to achieve page chunks | ||
Tweet.find({},'twid active author avatar body date screenname',{skip: start, limit: 10}).sort({date: 'desc'}).exec(function(err,docs){ | ||
|
||
// If everything is cool... | ||
if(!err) { | ||
tweets = docs; // We got tweets | ||
tweets.forEach(function(tweet){ | ||
tweet.active = true; // Set them to active | ||
}); | ||
} | ||
|
||
// Pass them back to the specified callback | ||
callback(tweets); | ||
|
||
}); | ||
|
||
}; | ||
|
||
// Return a Tweet model based upon the defined schema | ||
module.exports = Tweet = mongoose.model('Tweet', schema); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "react-isomorph", | ||
"version": "0.0.0", | ||
"description": "Isomorphic React Example", | ||
"main": "app.js", | ||
"scripts": { | ||
"watch": "watchify app.js -o public/js/bundle.js -v", | ||
"browserify": "browserify app.js | uglifyjs > public/js/bundle.js", | ||
"build": "npm run browserify ", | ||
"start": "npm run watch & nodemon server.js" | ||
}, | ||
"author": "Ken Wheeler", | ||
"license": "MIT", | ||
"dependencies": { | ||
"express": "~4.9.7", | ||
"express-handlebars": "~1.1.0", | ||
"mongoose": "^3.8.17", | ||
"node-jsx": "~0.11.0", | ||
"ntwitter": "^0.5.0", | ||
"react": "~0.11.2", | ||
"socket.io": "^1.1.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "~6.0.3", | ||
"nodemon": "^1.2.1", | ||
"reactify": "~0.14.0", | ||
"uglify-js": "~2.4.15", | ||
"watchify": "~2.0.0" | ||
}, | ||
"browserify": { | ||
"transform": [ | ||
"reactify" | ||
] | ||
} | ||
} |
Oops, something went wrong.