diff options
Diffstat (limited to 'src/web/js/components')
-rw-r--r-- | src/web/js/components/MainApp.react.js | 21 | ||||
-rw-r--r-- | src/web/js/components/Menu.react.js | 143 | ||||
-rw-r--r-- | src/web/js/components/MiddlePanel.react.js | 111 |
3 files changed, 181 insertions, 94 deletions
diff --git a/src/web/js/components/MainApp.react.js b/src/web/js/components/MainApp.react.js index 743c9510..059d2646 100644 --- a/src/web/js/components/MainApp.react.js +++ b/src/web/js/components/MainApp.react.js @@ -1,16 +1,23 @@ +var React = require('react'); +var Col = require('react-bootstrap/lib/Col'); +var Grid = require('react-bootstrap/lib/Grid'); + 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> + return (<Grid fluid> + <Col xsHidden smHidden md={3} lg={2}> + <Menu.MenuFilter /> + <Menu.Menu /> + </Col> + <Col xs={2} sm={2} md={4} lg={4}> + <MiddlePanel.MiddlePanelFilter /> + <MiddlePanel.MiddlePanel /> + </Col> + </Grid> ); }, }); diff --git a/src/web/js/components/Menu.react.js b/src/web/js/components/Menu.react.js index d44e7bd3..3e5f4156 100644 --- a/src/web/js/components/Menu.react.js +++ b/src/web/js/components/Menu.react.js @@ -1,7 +1,11 @@ var React = require('react'); +var Row = require('react-bootstrap/lib/Row'); +var Badge = require('react-bootstrap/lib/Badge'); var Button = require('react-bootstrap/lib/Button'); var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); -var Badge = require('react-bootstrap/lib/Badge'); +var ListGroup = require('react-bootstrap/lib/ListGroup'); +var ListGroupItem = require('react-bootstrap/lib/ListGroupItem'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); var MenuStore = require('../stores/MenuStore'); var MenuActions = require('../actions/MenuActions'); @@ -13,27 +17,29 @@ var FeedItem = React.createClass({ unread: React.PropTypes.number.isRequired, error_count: React.PropTypes.number.isRequired, icon_url: React.PropTypes.string, + active: React.PropTypes.bool.isRequired, }, render: function() { var icon = null; var badge_unread = null; - var badge_error = null; + var style = null; if(this.props.icon_url){ icon = (<img width="16px" src={this.props.icon_url} />); } else { - icon = (<span className="glyphicon glyphicon-ban-circle" />); + icon = <Glyphicon glyph="ban-circle" />; } if(this.props.unread){ badge_unread = <Badge pullRight>{this.props.unread}</Badge>; } if(this.props.error_count == 6) { - badge_unread = <Badge pullRight error>error</Badge>; + style = "danger"; } else if(this.props.error_count > 3) { - badge_unread = <Badge pullRight warning>warn</Badge>; + style = "warning"; } - return (<li onMouseDown={this.handleClick}> - {icon}{this.props.title}{badge_unread}{badge_error} - </li> + return (<ListGroupItem onMouseDown={this.handleClick} bsStyle={style} + href="#" active={this.props.active}> + {icon}{this.props.title}{badge_unread} + </ListGroupItem> ); }, handleClick: function() { @@ -42,53 +48,76 @@ var FeedItem = React.createClass({ }); var Category = React.createClass({ - propTypes: {category_id: React.PropTypes.number.isRequired, + propTypes: {cat_id: React.PropTypes.number.isRequired, filter: React.PropTypes.string.isRequired, + active_type: React.PropTypes.string, + active_id: React.PropTypes.number, name: React.PropTypes.string.isRequired, feeds: React.PropTypes.array.isRequired, unread: React.PropTypes.number.isRequired, }, + getInitialState: function() { + return {unfolded: true}; + }, render: function() { var filter = this.props.filter; + var a_type = this.props.active_type; + var a_id = this.props.active_id; // filtering according to this.props.filter + if(this.state.unfolded) { var feeds = this.props.feeds.filter(function(feed) { - if (filter == 'unread' && feed.unread <= 0) {return false;} - else if (filter == 'error' && feed.error_count <= 3){return false;} + if (filter == 'unread' && feed.unread <= 0) { + return false; + } else if (filter == 'error' && feed.error_count <= 3) { + return false; + } return true; }).sort(function(feed_a, feed_b){ return feed_b.unread - feed_a.unread; }).map(function(feed) { - return (<FeedItem key={"feed" + feed.id} feed_id={feed.id} + return (<FeedItem key={"f" + feed.id} feed_id={feed.id} title={feed.title} unread={feed.unread} error_count={feed.error_count} - icon_url={feed.icon_url} />); + active={a_type == 'feed_id' && a_id == feed.id} + icon_url={feed.icon_url} /> + ); }); - var unread = undefined; + } else { + var feeds = []; + } + var unread = null; if(this.props.unread){ - unread = (<span className="badge pull-right"> - {this.props.unread} - </span>); + unread = <Badge pullRight>{this.props.unread}</Badge>; } - return (<div> - <h3 onMouseDown={this.handleClick}> - {this.props.name} {unread} - </h3> - <ul className="nav nav-sidebar">{feeds}</ul> - </div> + var active = a_type == 'category_id' && a_id == this.props.cat_id; + var ctrl = (<Glyphicon onMouseDown={this.toggleFolding} pullLeft + glyph={this.state.unfolded?"menu-down":"menu-right"} /> + ); + + return (<ListGroup> + <ListGroupItem href="#" bsStyle="success" + active={active} + onMouseDown={this.handleClick}> + {ctrl} <strong>{this.props.name}</strong> {unread} + </ListGroupItem> + {feeds} + </ListGroup> ); }, handleClick: function() { - MiddlePanelActions.setCategoryFilter(this.props.category_id); + MiddlePanelActions.setCategoryFilter(this.props.cat_id); + }, + toggleFolding: function(evnt) { + this.setState({unfolded: !this.state.unfolded}); + evnt.stopPropagation(); }, }); -var Menu = React.createClass({ +var MenuFilter = React.createClass({ getInitialState: function() { - return {filter: 'all', categories: [], - feed_in_error: false, all_unread_count: 0}; + return {filter: 'all', feed_in_error: false}; }, render: function() { - var filter = this.state.filter; var error_button = null; if (this.state.feed_in_error) { error_button = (<Button active={this.state.filter == "error"} @@ -96,8 +125,7 @@ var Menu = React.createClass({ bsSize="small" bsStyle="warning">Error</Button> ); } - return (<div id="sidebar" data-spy="affix" role="navigation" - className="col-md-2 sidebar sidebar-offcanvas pre-scrollable hidden-sm hidden-xs affix"> + return (<Row className="show-grid"> <ButtonGroup> <Button active={this.state.filter == "all"} onMouseDown={MenuActions.setFilterAll} @@ -106,17 +134,49 @@ var Menu = React.createClass({ onMouseDown={MenuActions.setFilterUnread} bsSize="small">Unread</Button> {error_button} - </ButtonGroup> + </ButtonGroup> + </Row> + ); + }, + componentDidMount: function() { + MenuStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + MenuStore.removeChangeListener(this._onChange); + }, + _onChange: function() { + var datas = MenuStore.getAll(); + this.setState({filter: datas.filter, + feed_in_error: datas.feed_in_error}); + }, +}); + +var Menu = React.createClass({ + getInitialState: function() { + return {filter: 'all', categories: [], all_unread_count: 0, + active_type: null, active_id: null}; + }, + render: function() { + var state = this.state; + var rmPrntFilt = (<ListGroupItem href="#" bsStyle="success" + active={this.state.active_type == null + || this.state.active_id == null} + onMouseDown={MiddlePanelActions.removeParentFilter} + header="All"></ListGroupItem>); + + return (<Row className="show-grid"> + <ListGroup>{rmPrntFilt}</ListGroup> {this.state.categories.map(function(category){ - return (<Category key={"cat" + category.id} - filter={filter} - category_id={category.id} - feeds={category.feeds} - name={category.name} - unread={category.unread} />); + return (<Category key={"c" + category.id} + filter={state.filter} + active_type={state.active_type} + active_id={state.active_id} + cat_id={category.id} + feeds={category.feeds} + name={category.name} + unread={category.unread} />); })} - - </div> + </Row> ); }, componentDidMount: function() { @@ -130,9 +190,10 @@ var Menu = React.createClass({ var datas = MenuStore.getAll(); this.setState({filter: datas.filter, categories: datas.categories, - feed_in_error: datas.feed_in_error, + active_type: datas.active_type, + active_id: datas.active_id, all_unread_count: datas.all_unread_count}); }, }); -module.exports = Menu; +module.exports = {Menu: Menu, MenuFilter: MenuFilter}; diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js index f95554b8..49365a6a 100644 --- a/src/web/js/components/MiddlePanel.react.js +++ b/src/web/js/components/MiddlePanel.react.js @@ -1,6 +1,10 @@ var React = require('react'); +var Row = require('react-bootstrap/lib/Row'); var Button = require('react-bootstrap/lib/Button'); var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); +var ListGroup = require('react-bootstrap/lib/ListGroup'); +var ListGroupItem = require('react-bootstrap/lib/ListGroupItem'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); var MiddlePanelStore = require('../stores/MiddlePanelStore'); var MiddlePanelActions = require('../actions/MiddlePanelActions'); @@ -18,54 +22,78 @@ var TableLine = React.createClass({ return {read: this.props.read, liked: this.props.liked}; }, render: function() { - var read = this.state.read ? 'r' : ''; var liked = this.state.liked ? 'l' : ''; var icon = null; if(this.props.icon_url){ icon = (<img width="16px" src={this.props.icon_url} />); } else { - icon = (<span className="glyphicon glyphicon-ban-circle" />); + icon = <Glyphicon glyph="ban-circle" />; } + var title = (<a href={'/redirect/' + this.props.article_id}> + {icon} {this.props.feed_title} + </a>); + var read = (<Glyphicon glyph={this.state.read?"check":"unchecked"} + onClick={this.toogleRead} />); + var liked = (<Glyphicon glyph={this.state.liked?"star":"star-empty"} + onClick={this.toogleLike} />); return ( - <tr> - <td>{icon}{liked}</td> - <td> - <a href={'/redirect/' + this.props.article_id}> - {this.props.feed_title} - </a> - </td> - <td> - <a href={'/article/' + this.props.article_id}> - {this.props.title} - </a> - </td> - <td>{this.props.date}</td> - </tr> + <ListGroupItem header={title}> + {read} + {liked} + {this.props.title} + </ListGroupItem> ); }, + toogleRead: function() { + this.setState({read: !this.state.read}); + MiddlePanelActions.changeRead(this.props.article_id, !this.state.read); + }, + toogleLike: function() { + this.setState({liked: !this.state.liked}); + MiddlePanelActions.changeLike(this.props.article_id, !this.state.liked); + }, +}); + +var MiddlePanelFilter = React.createClass({ + getInitialState: function() { + return {filter: MiddlePanelStore._datas.filter}; + }, + render: function() { + return (<Row className="show-grid"> + <ButtonGroup> + <Button active={this.state.filter == "all"} + onMouseDown={MiddlePanelActions.setFilterAll} + bsSize="small">All</Button> + <Button active={this.state.filter == "unread"} + onMouseDown={MiddlePanelActions.setFilterUnread} + bsSize="small">Unread</Button> + <Button active={this.state.filter == "liked"} + onMouseDown={MiddlePanelActions.setFilterLiked} + bsSize="small">Liked</Button> + </ButtonGroup> + </Row> + ); + }, + componentDidMount: function() { + MiddlePanelStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + MiddlePanelStore.removeChangeListener(this._onChange); + }, + _onChange: function() { + this.setState({filter: MiddlePanelStore._datas.filter}); + }, }); -var TableBody = React.createClass({ +var MiddlePanel = React.createClass({ getInitialState: function() { - return {filter: 'unread', articles: []}; + return {filter: MiddlePanelStore._datas.filter, articles: []}; }, render: function() { - return (<div className="table-responsive"> - <ButtonGroup> - <Button active={this.state.filter == "all"} - onMouseDown={MiddlePanelActions.setFilterAll} - bsSize="small">All</Button> - <Button active={this.state.filter == "unread"} - onMouseDown={MiddlePanelActions.setFilterUnread} - bsSize="small">Unread</Button> - <Button active={this.state.filter == "liked"} - onMouseDown={MiddlePanelActions.setFilterLiked} - bsSize="small">Liked</Button> - </ButtonGroup> - <table className="table table-striped strict-table"> - <tbody> + return (<Row className="show-grid"> + <ListGroup> {this.state.articles.map(function(article){ - return (<TableLine key={"article" + article.article_id} + return (<TableLine key={"a" + article.article_id} title={article.title} icon_url={article.icon_url} read={article.read} @@ -73,9 +101,8 @@ var TableBody = React.createClass({ date={article.date} article_id={article.article_id} feed_title={article.feed_title} />);})} - </tbody> - </table> - </div> + </ListGroup> + </Row> ); }, componentDidMount: function() { @@ -91,13 +118,5 @@ var TableBody = React.createClass({ }, }); -var MiddlePanel = React.createClass({ - render: function() { - return (<div className="col-md-offset-2 col-md-10 main"> - <TableBody /> - </div> - ); - }, -}); - -module.exports = MiddlePanel; +module.exports = {MiddlePanel: MiddlePanel, + MiddlePanelFilter: MiddlePanelFilter}; |