From 1f650d327d35bc48b897da99914c43750d8e5fd3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 7 Oct 2016 16:00:11 +0200 Subject: Adding public timeline --- .../components/features/account/index.jsx | 21 +++-- .../components/features/getting_started/index.jsx | 18 ++-- .../components/features/public_timeline/index.jsx | 103 +++++++++++++++++++++ .../components/features/status/index.jsx | 21 +++-- .../components/features/ui/components/column.jsx | 9 +- .../features/ui/components/columns_area.jsx | 2 +- .../features/ui/components/navigation_bar.jsx | 2 +- .../javascripts/components/features/ui/index.jsx | 4 +- 8 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 app/assets/javascripts/components/features/public_timeline/index.jsx (limited to 'app/assets/javascripts/components/features') diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx index c9de1a848..9c77214d1 100644 --- a/app/assets/javascripts/components/features/account/index.jsx +++ b/app/assets/javascripts/components/features/account/index.jsx @@ -27,9 +27,10 @@ import StatusList from '../../components/status_list'; import LoadingIndicator from '../../components/loading_indicator'; import Immutable from 'immutable'; import ActionBar from './components/action_bar'; +import Column from '../ui/components/column'; function selectStatuses(state, accountId) { - return state.getIn(['timelines', 'accounts_timelines', accountId], Immutable.List()).map(id => selectStatus(state, id)).filterNot(status => status === null); + return state.getIn(['timelines', 'accounts_timelines', accountId], Immutable.List([])).map(id => selectStatus(state, id)).filterNot(status => status === null); }; const mapStateToProps = (state, props) => ({ @@ -109,15 +110,21 @@ const Account = React.createClass({ const { account, statuses, me } = this.props; if (account === null) { - return ; + return ( + + + + ); } return ( -
-
- - -
+ +
+
+ + +
+
); } diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx index d507cb46f..a4f1ac487 100644 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ b/app/assets/javascripts/components/features/getting_started/index.jsx @@ -1,12 +1,16 @@ +import Column from '../ui/components/column'; + const GettingStarted = () => { return ( -
-

Getting started

-

Mastodon is still in development and one of the lacking areas at the moment is user discovery.

-

You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the form in the bottom of the sidebar.

-

If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.

-

The developer of this project can be followed as Gargron@mastodon.social

-
+ +
+

Getting started

+

Mastodon is still in development and one of the lacking areas at the moment is user discovery.

+

You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the form in the bottom of the sidebar.

+

If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.

+

The developer of this project can be followed as Gargron@mastodon.social

+
+
); }; diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx new file mode 100644 index 000000000..dd31dc115 --- /dev/null +++ b/app/assets/javascripts/components/features/public_timeline/index.jsx @@ -0,0 +1,103 @@ +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import StatusList from '../../components/status_list'; +import Column from '../ui/components/column'; +import Immutable from 'immutable'; +import { selectStatus } from '../../reducers/timelines'; +import { + updateTimeline, + refreshTimeline, + expandTimeline +} from '../../actions/timelines'; +import { deleteStatus } from '../../actions/statuses'; +import { replyCompose } from '../../actions/compose'; +import { + favourite, + reblog, + unreblog, + unfavourite +} from '../../actions/interactions'; + +function selectStatuses(state) { + return state.getIn(['timelines', 'public'], Immutable.List()).map(id => selectStatus(state, id)).filterNot(status => status === null); +}; + +const mapStateToProps = (state) => ({ + statuses: selectStatuses(state), + me: state.getIn(['timelines', 'me']) +}); + +const PublicTimeline = React.createClass({ + + propTypes: { + statuses: ImmutablePropTypes.list.isRequired, + me: React.PropTypes.number.isRequired, + dispatch: React.PropTypes.func.isRequired + }, + + mixins: [PureRenderMixin], + + componentWillMount () { + const { dispatch } = this.props; + + dispatch(refreshTimeline('public')); + + if (typeof App !== 'undefined') { + this.subscription = App.cable.subscriptions.create('PublicChannel', { + + received (data) { + dispatch(updateTimeline('public', JSON.parse(data.message))); + } + + }); + } + }, + + componentWillUnmount () { + if (typeof this.subscription !== 'undefined') { + this.subscription.unsubscribe(); + } + }, + + handleReply (status) { + this.props.dispatch(replyCompose(status)); + }, + + handleReblog (status) { + if (status.get('reblogged')) { + this.props.dispatch(unreblog(status)); + } else { + this.props.dispatch(reblog(status)); + } + }, + + handleFavourite (status) { + if (status.get('favourited')) { + this.props.dispatch(unfavourite(status)); + } else { + this.props.dispatch(favourite(status)); + } + }, + + handleDelete (status) { + this.props.dispatch(deleteStatus(status.get('id'))); + }, + + handleScrollToBottom () { + this.props.dispatch(expandTimeline('public')); + }, + + render () { + const { statuses, me } = this.props; + + return ( + + + + ); + }, + +}); + +export default connect(mapStateToProps)(PublicTimeline); diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index c294ac1d6..b282956b1 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -7,6 +7,7 @@ import EmbeddedStatus from '../../components/status'; import LoadingIndicator from '../../components/loading_indicator'; import DetailedStatus from './components/detailed_status'; import ActionBar from './components/action_bar'; +import Column from '../ui/components/column'; import { favourite, reblog } from '../../actions/interactions'; import { replyCompose } from '../../actions/compose'; import { selectStatus } from '../../reducers/timelines'; @@ -64,20 +65,26 @@ const Status = React.createClass({ const { status, ancestors, descendants, me } = this.props; if (status === null) { - return ; + return ( + + + + ); } const account = status.get('account'); return ( -
-
{this.renderChildren(ancestors)}
+ +
+
{this.renderChildren(ancestors)}
- - + + -
{this.renderChildren(descendants)}
-
+
{this.renderChildren(descendants)}
+
+ ); } diff --git a/app/assets/javascripts/components/features/ui/components/column.jsx b/app/assets/javascripts/components/features/ui/components/column.jsx index 499e5f4a5..bb9331267 100644 --- a/app/assets/javascripts/components/features/ui/components/column.jsx +++ b/app/assets/javascripts/components/features/ui/components/column.jsx @@ -29,7 +29,6 @@ const scrollTop = (node) => { }; }; - const Column = React.createClass({ propTypes: { @@ -50,10 +49,6 @@ const Column = React.createClass({ } }, - handleScroll () { - // todo - }, - render () { let header = ''; @@ -61,10 +56,10 @@ const Column = React.createClass({ header = ; } - const style = { width: '350px', flex: '0 0 auto', background: '#282c37', margin: '10px', marginRight: '0', marginBottom: '0', display: 'flex', flexDirection: 'column' }; + const style = { width: '330px', flex: '0 0 auto', background: '#282c37', margin: '10px', marginRight: '0', marginBottom: '0', display: 'flex', flexDirection: 'column' }; return ( -
+
{header} {this.props.children}
diff --git a/app/assets/javascripts/components/features/ui/components/columns_area.jsx b/app/assets/javascripts/components/features/ui/components/columns_area.jsx index fa4c1a9c9..94433539b 100644 --- a/app/assets/javascripts/components/features/ui/components/columns_area.jsx +++ b/app/assets/javascripts/components/features/ui/components/columns_area.jsx @@ -6,7 +6,7 @@ const ColumnsArea = React.createClass({ render () { return ( -
+
{this.props.children}
); diff --git a/app/assets/javascripts/components/features/ui/components/navigation_bar.jsx b/app/assets/javascripts/components/features/ui/components/navigation_bar.jsx index 9d9481d3e..a16852541 100644 --- a/app/assets/javascripts/components/features/ui/components/navigation_bar.jsx +++ b/app/assets/javascripts/components/features/ui/components/navigation_bar.jsx @@ -19,7 +19,7 @@ const NavigationBar = React.createClass({
{this.props.account.get('acct')} - Settings · Logout + Settings · Public timeline · Logout
); diff --git a/app/assets/javascripts/components/features/ui/index.jsx b/app/assets/javascripts/components/features/ui/index.jsx index 323729dd6..0bc235b53 100644 --- a/app/assets/javascripts/components/features/ui/index.jsx +++ b/app/assets/javascripts/components/features/ui/index.jsx @@ -40,9 +40,7 @@ const UI = React.createClass({ - - {this.props.children} - + {this.props.children} -- cgit