aboutsummaryrefslogtreecommitdiff
path: root/src/web/js/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/web/js/components')
-rw-r--r--src/web/js/components/MainApp.react.js18
-rw-r--r--src/web/js/components/Menu.react.js119
-rw-r--r--src/web/js/components/MiddlePanel.react.js103
3 files changed, 240 insertions, 0 deletions
diff --git a/src/web/js/components/MainApp.react.js b/src/web/js/components/MainApp.react.js
new file mode 100644
index 00000000..743c9510
--- /dev/null
+++ b/src/web/js/components/MainApp.react.js
@@ -0,0 +1,18 @@
+var Menu = require('./Menu.react');
+var MiddlePanel = require('./MiddlePanel.react');
+var React = require('react');
+
+
+var MainApp = React.createClass({
+ render: function() {
+ return (<div className="container-fluid">
+ <div className="row row-offcanvas row-offcanvas-left">
+ <Menu />
+ <MiddlePanel />
+ </div>
+ </div>
+ );
+ },
+});
+
+module.exports = MainApp;
diff --git a/src/web/js/components/Menu.react.js b/src/web/js/components/Menu.react.js
new file mode 100644
index 00000000..caf8c3a8
--- /dev/null
+++ b/src/web/js/components/Menu.react.js
@@ -0,0 +1,119 @@
+var React = require('react');
+var MenuStore = require('../stores/MenuStore');
+var MenuActions = require('../actions/MenuActions');
+var MiddlePanelActions = require('../actions/MiddlePanelActions');
+
+var FeedItem = React.createClass({
+ propTypes: {feed_id: React.PropTypes.number.isRequired,
+ title: React.PropTypes.string.isRequired,
+ unread: React.PropTypes.number.isRequired,
+ icon_url: React.PropTypes.string,
+ },
+ getInitialState: function() {
+ return {feed_id: this.props.feed_id,
+ title: this.props.title,
+ unread: this.props.unread,
+ icon_url: this.props.icon_url,
+ };
+ },
+ render: function() {
+ var unread = undefined;
+ var icon = undefined;
+ if(this.state.icon_url){
+ icon = (<img width="16px" src={this.state.icon_url} />);
+ } else {
+ icon = (<span className="glyphicon glyphicon-ban-circle" />);
+ }
+ if(this.state.unread){
+ unread = (
+ <span className="badge pull-right">
+ {this.state.unread}
+ </span>
+ );
+ }
+ return (<li onMouseDown={this.handleClick}>
+ {icon} {this.state.title} {unread}
+ </li>
+ );
+ },
+ handleClick: function() {
+ MiddlePanelActions.setFeedFilter(this.state.feed_id);
+ },
+});
+
+var Category = React.createClass({
+ propTypes: {category_id: React.PropTypes.number.isRequired,
+ name: React.PropTypes.string.isRequired,
+ feeds: React.PropTypes.array.isRequired,
+ unread: React.PropTypes.number.isRequired,
+ },
+ getInitialState: function() {
+ return {category_id: this.props.category_id,
+ name: this.props.name,
+ feeds: this.props.feeds,
+ unread: this.props.unread,
+ };
+ },
+ render: function() {
+ unread = undefined;
+ if(this.state.unread){
+ unread = (
+ <span className="badge pull-right">
+ {this.state.unread}
+ </span>
+ );
+ }
+ return (<div>
+ <h3 onMouseDown={this.handleClick}>
+ {this.state.name} {unread}
+ </h3>
+ <ul className="nav nav-sidebar">
+ {this.state.feeds.map(function(feed){
+ return <FeedItem key={"feed" + feed.id}
+ feed_id={feed.id}
+ title={feed.title}
+ unread={feed.unread}
+ icon_url={feed.icon_url} />;})}
+ </ul>
+ </div>
+ );
+ },
+ handleClick: function() {
+ MiddlePanelActions.setCategoryFilter(this.state.category_id);
+ },
+});
+
+var Menu = React.createClass({
+ getInitialState: function() {
+ return {categories: [], all_unread_count: 0};
+ },
+ render: function() {
+ return (<div id="sidebar" data-spy="affix" role="navigation"
+ className="col-md-2 sidebar sidebar-offcanvas pre-scrollable hidden-sm hidden-xs affix">
+ {this.state.categories.map(function(category){
+ return (<Category key={"cat" + category.id}
+ category_id={category.id}
+ feeds={category.feeds}
+ name={category.name}
+ unread={category.unread} />);
+ })}
+
+ </div>
+ );
+ },
+
+ componentDidMount: function() {
+ MenuActions.reload();
+ MenuStore.addChangeListener(this._onChange);
+ },
+ componentWillUnmount: function() {
+ MenuStore.removeChangeListener(this._onChange);
+ },
+ _onChange: function() {
+ var datas = MenuStore.getAll();
+ this.setState({categories: datas.categories,
+ all_unread_count: datas.all_unread_count});
+ },
+});
+
+module.exports = Menu;
diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js
new file mode 100644
index 00000000..51d582c0
--- /dev/null
+++ b/src/web/js/components/MiddlePanel.react.js
@@ -0,0 +1,103 @@
+var React = require('react');
+var MiddlePanelStore = require('../stores/MiddlePanelStore');
+var MiddlePanelActions = require('../actions/MiddlePanelActions');
+
+var TableLine = React.createClass({
+ propTypes: {article_id: React.PropTypes.number.isRequired,
+ feed_title: React.PropTypes.string.isRequired,
+ icon_url: React.PropTypes.string,
+ title: React.PropTypes.string.isRequired,
+ date: React.PropTypes.string.isRequired,
+ read: React.PropTypes.bool.isRequired,
+ liked: React.PropTypes.bool.isRequired,
+ },
+ getInitialState: function() {
+ return {article_id: this.props.article_id,
+ title: this.props.title,
+ icon_url: this.props.icon_url,
+ feed_title: this.props.feed_title,
+ date: this.props.date,
+ read: this.props.read,
+ liked: this.props.liked,
+ };
+ },
+ render: function() {
+ var read = this.state.read ? 'r' : '';
+ var liked = this.state.liked ? 'l' : '';
+ var icon = undefined;
+ if(this.state.icon_url){
+ icon = (<img width="16px" src={this.state.icon_url} />);
+ } else {
+ icon = (<span className="glyphicon glyphicon-ban-circle" />);
+ }
+ return (
+ <tr>
+ <td>{icon}{liked}</td>
+ <td>
+ <a href={'/redirect/' + this.state.article_id}>
+ {this.state.feed_title}
+ </a>
+ </td>
+ <td>
+ <a href={'/article/' + this.state.article_id}>
+ {this.state.title}
+ </a>
+ </td>
+ <td>{this.state.date}</td>
+ </tr>
+ );
+ },
+});
+
+var TableBody = React.createClass({
+ propTypes: {articles: React.PropTypes.array.isRequired,
+ },
+ getInitialState: function() {
+ return {articles: this.props.articles,
+ };
+ },
+ render: function() {
+ return (<div className="table-responsive">
+ <table className="table table-striped strict-table">
+ <tbody>
+ {this.state.articles.map(function(article){
+ return (<TableLine key={"article" + article.article_id}
+ title={article.title}
+ icon_url={article.icon_url}
+ read={article.read}
+ liked={article.liked}
+ date={article.date}
+ article_id={article.article_id}
+ feed_title={article.feed_title} />);})}
+ </tbody>
+ </table>
+ </div>
+ );
+ }
+});
+
+var MiddlePanel = React.createClass({
+ getInitialState: function() {
+ return {articles: []};
+ },
+ render: function() {
+ var body = null;
+ if(this.state.articles.length) {
+ body = (<TableBody articles={this.state.articles} />);
+ }
+ return (<div className="col-md-offset-2 col-md-10 main">{body}</div>);
+ },
+ componentDidMount: function() {
+ MiddlePanelActions.reload();
+ MiddlePanelStore.addChangeListener(this._onChange);
+ },
+ componentWillUnmount: function() {
+ MiddlePanelStore.removeChangeListener(this._onChange);
+ },
+ _onChange: function() {
+ var datas = MiddlePanelStore.getAll();
+ this.setState({articles: datas.articles});
+ },
+});
+
+module.exports = MiddlePanel;
bgstack15