parent
74ee5bdf37
commit
1fb4bf87f7
6 changed files with 69 additions and 33 deletions
|
@ -45,9 +45,8 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
||||||
export const connectCommunityStream = () => connectTimelineStream('community', 'public:local');
|
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
||||||
export const connectMediaStream = () => connectTimelineStream('community', 'public:local');
|
export const connectPublicStream = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);
|
||||||
export const connectPublicStream = () => connectTimelineStream('public', 'public');
|
export const connectHashtagStream = tag => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
||||||
export const connectHashtagStream = (tag) => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
|
||||||
export const connectDirectStream = () => connectTimelineStream('direct', 'direct');
|
export const connectDirectStream = () => connectTimelineStream('direct', 'direct');
|
||||||
export const connectListStream = (id) => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||||
|
|
|
@ -70,8 +70,8 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||||
export const expandPublicTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('public', '/api/v1/timelines/public', { max_id: maxId }, done);
|
export const expandPublicTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
export const expandCommunityTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('community', '/api/v1/timelines/public', { local: true, max_id: maxId }, done);
|
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done);
|
export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done);
|
||||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
||||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import { NavLink } from 'react-router-dom';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
|
import { expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
|
||||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
import { connectCommunityStream } from 'flavours/glitch/actions/streaming';
|
import { connectCommunityStream } from 'flavours/glitch/actions/streaming';
|
||||||
|
|
||||||
|
@ -14,20 +15,25 @@ const messages = defineMessages({
|
||||||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||||
hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0,
|
hasUnread: state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps)
|
||||||
@injectIntl
|
@injectIntl
|
||||||
export default class CommunityTimeline extends React.PureComponent {
|
export default class CommunityTimeline extends React.PureComponent {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
onlyMedia: false,
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
hasUnread: PropTypes.bool,
|
hasUnread: PropTypes.bool,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
|
onlyMedia: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
handlePin = () => {
|
||||||
|
@ -50,10 +56,10 @@ export default class CommunityTimeline extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { dispatch } = this.props;
|
const { dispatch, onlyMedia } = this.props;
|
||||||
|
|
||||||
dispatch(expandCommunityTimeline());
|
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||||
this.disconnect = dispatch(connectCommunityStream());
|
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -68,13 +74,22 @@ export default class CommunityTimeline extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLoadMore = maxId => {
|
handleLoadMore = maxId => {
|
||||||
this.props.dispatch(expandCommunityTimeline({ maxId }));
|
const { dispatch, onlyMedia } = this.props;
|
||||||
|
|
||||||
|
dispatch(expandCommunityTimeline({ maxId, onlyMedia }));
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props;
|
||||||
const pinned = !!columnId;
|
const pinned = !!columnId;
|
||||||
|
|
||||||
|
const headline = (
|
||||||
|
<div className='community-timeline__section-headline'>
|
||||||
|
<NavLink exact to='/timelines/public/local' replace><FormattedMessage id='timeline.posts' defaultMessage='Toots' /></NavLink>
|
||||||
|
<NavLink exact to='/timelines/public/local/media' replace><FormattedMessage id='timeline.media' defaultMessage='Media' /></NavLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef} name='local' label={intl.formatMessage(messages.title)}>
|
<Column ref={this.setRef} name='local' label={intl.formatMessage(messages.title)}>
|
||||||
<ColumnHeader
|
<ColumnHeader
|
||||||
|
@ -91,9 +106,11 @@ export default class CommunityTimeline extends React.PureComponent {
|
||||||
</ColumnHeader>
|
</ColumnHeader>
|
||||||
|
|
||||||
<StatusListContainer
|
<StatusListContainer
|
||||||
|
prepend={headline}
|
||||||
trackScroll={!pinned}
|
trackScroll={!pinned}
|
||||||
scrollKey={`community_timeline-${columnId}`}
|
scrollKey={`community_timeline-${columnId}`}
|
||||||
timelineId='community'
|
shouldUpdateScroll={this.shouldUpdateScroll}
|
||||||
|
timelineId={`community${onlyMedia ? ':media' : ''}`}
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import { NavLink } from 'react-router-dom';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { expandPublicTimeline } from 'flavours/glitch/actions/timelines';
|
import { expandPublicTimeline } from 'flavours/glitch/actions/timelines';
|
||||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
import { connectPublicStream } from 'flavours/glitch/actions/streaming';
|
import { connectPublicStream } from 'flavours/glitch/actions/streaming';
|
||||||
|
|
||||||
|
@ -14,20 +15,25 @@ const messages = defineMessages({
|
||||||
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||||
hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0,
|
hasUnread: state.getIn(['timelines', `public${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps)
|
||||||
@injectIntl
|
@injectIntl
|
||||||
export default class PublicTimeline extends React.PureComponent {
|
export default class PublicTimeline extends React.PureComponent {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
onlyMedia: false,
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
hasUnread: PropTypes.bool,
|
hasUnread: PropTypes.bool,
|
||||||
|
onlyMedia: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
handlePin = () => {
|
||||||
|
@ -50,10 +56,10 @@ export default class PublicTimeline extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { dispatch } = this.props;
|
const { dispatch, onlyMedia } = this.props;
|
||||||
|
|
||||||
dispatch(expandPublicTimeline());
|
dispatch(expandPublicTimeline({ onlyMedia }));
|
||||||
this.disconnect = dispatch(connectPublicStream());
|
this.disconnect = dispatch(connectPublicStream({ onlyMedia }));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -68,13 +74,22 @@ export default class PublicTimeline extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLoadMore = maxId => {
|
handleLoadMore = maxId => {
|
||||||
this.props.dispatch(expandPublicTimeline({ maxId }));
|
const { dispatch, onlyMedia } = this.props;
|
||||||
|
|
||||||
|
dispatch(expandPublicTimeline({ maxId, onlyMedia }));
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, columnId, hasUnread, multiColumn } = this.props;
|
const { intl, columnId, hasUnread, multiColumn, onlyMedia } = this.props;
|
||||||
const pinned = !!columnId;
|
const pinned = !!columnId;
|
||||||
|
|
||||||
|
const headline = (
|
||||||
|
<div className='public-timeline__section-headline'>
|
||||||
|
<NavLink exact to='/timelines/public' replace><FormattedMessage id='timeline.posts' defaultMessage='Toots' /></NavLink>
|
||||||
|
<NavLink exact to='/timelines/public/media' replace><FormattedMessage id='timeline.media' defaultMessage='Media' /></NavLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef} name='federated' label={intl.formatMessage(messages.title)}>
|
<Column ref={this.setRef} name='federated' label={intl.formatMessage(messages.title)}>
|
||||||
<ColumnHeader
|
<ColumnHeader
|
||||||
|
@ -91,7 +106,8 @@ export default class PublicTimeline extends React.PureComponent {
|
||||||
</ColumnHeader>
|
</ColumnHeader>
|
||||||
|
|
||||||
<StatusListContainer
|
<StatusListContainer
|
||||||
timelineId='public'
|
prepend={headline}
|
||||||
|
timelineId={`public${onlyMedia ? ':media' : ''}`}
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
trackScroll={!pinned}
|
trackScroll={!pinned}
|
||||||
scrollKey={`public_timeline-${columnId}`}
|
scrollKey={`public_timeline-${columnId}`}
|
||||||
|
|
|
@ -467,7 +467,9 @@ export default class UI extends React.Component {
|
||||||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||||
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
||||||
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
|
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
|
||||||
|
<WrappedRoute path='/timelines/public/media' extract component={PublicTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||||
<WrappedRoute path='/timelines/public/local' component={CommunityTimeline} content={children} />
|
<WrappedRoute path='/timelines/public/local' component={CommunityTimeline} content={children} />
|
||||||
|
<WrappedRoute path='/timelines/public/local/media' component={CommunityTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||||
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
|
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
|
||||||
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
||||||
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
||||||
|
|
|
@ -446,6 +446,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__filter-bar,
|
.notification__filter-bar,
|
||||||
|
.community-timeline__section-headline,
|
||||||
|
.public-timeline__section-headline,
|
||||||
.account__section-headline {
|
.account__section-headline {
|
||||||
background: darken($ui-base-color, 4%);
|
background: darken($ui-base-color, 4%);
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
|
Loading…
Reference in a new issue