forked from cybrespace/mastodon
Fix #642 - Add "empty column" text to home/notifications
This commit is contained in:
parent
1d5dfda3d4
commit
9e99b8c068
|
@ -14,7 +14,8 @@ const StatusList = React.createClass({
|
||||||
onScroll: React.PropTypes.func,
|
onScroll: React.PropTypes.func,
|
||||||
trackScroll: React.PropTypes.bool,
|
trackScroll: React.PropTypes.bool,
|
||||||
isLoading: React.PropTypes.bool,
|
isLoading: React.PropTypes.bool,
|
||||||
prepend: React.PropTypes.node
|
prepend: React.PropTypes.node,
|
||||||
|
emptyMessage: React.PropTypes.node
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps () {
|
getDefaultProps () {
|
||||||
|
@ -71,27 +72,36 @@ const StatusList = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { statusIds, onScrollToBottom, trackScroll, isLoading, prepend } = this.props;
|
const { statusIds, onScrollToBottom, trackScroll, isLoading, prepend, emptyMessage } = this.props;
|
||||||
|
|
||||||
let loadMore = '';
|
let loadMore = '';
|
||||||
|
let scrollableArea = '';
|
||||||
|
|
||||||
if (!isLoading && statusIds.size > 0) {
|
if (!isLoading && statusIds.size > 0) {
|
||||||
loadMore = <LoadMore onClick={this.handleLoadMore} />;
|
loadMore = <LoadMore onClick={this.handleLoadMore} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollableArea = (
|
if (isLoading || statusIds.size > 0 || !emptyMessage) {
|
||||||
<div className='scrollable' ref={this.setRef}>
|
scrollableArea = (
|
||||||
<div>
|
<div className='scrollable' ref={this.setRef}>
|
||||||
{prepend}
|
<div>
|
||||||
|
{prepend}
|
||||||
|
|
||||||
{statusIds.map((statusId) => {
|
{statusIds.map((statusId) => {
|
||||||
return <StatusContainer key={statusId} id={statusId} />;
|
return <StatusContainer key={statusId} id={statusId} />;
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{loadMore}
|
{loadMore}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
} else {
|
||||||
|
scrollableArea = (
|
||||||
|
<div className='empty-column-indicator' ref={this.setRef}>
|
||||||
|
{emptyMessage}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (trackScroll) {
|
if (trackScroll) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
deleteFromTimelines
|
deleteFromTimelines
|
||||||
} from '../../actions/timelines';
|
} from '../../actions/timelines';
|
||||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import createStream from '../../stream';
|
import createStream from '../../stream';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -76,7 +77,7 @@ const HashtagTimeline = React.createClass({
|
||||||
return (
|
return (
|
||||||
<Column icon='hashtag' heading={id}>
|
<Column icon='hashtag' heading={id}>
|
||||||
<ColumnBackButtonSlim />
|
<ColumnBackButtonSlim />
|
||||||
<StatusListContainer type='tag' id={id} />
|
<StatusListContainer type='tag' id={id} emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />} />
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
import StatusListContainer from '../ui/containers/status_list_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.home', defaultMessage: 'Home' }
|
title: { id: 'column.home', defaultMessage: 'Home' }
|
||||||
|
@ -22,7 +23,7 @@ const HomeTimeline = React.createClass({
|
||||||
return (
|
return (
|
||||||
<Column icon='home' heading={intl.formatMessage(messages.title)}>
|
<Column icon='home' heading={intl.formatMessage(messages.title)}>
|
||||||
<ColumnSettingsContainer />
|
<ColumnSettingsContainer />
|
||||||
<StatusListContainer {...this.props} type='home' />
|
<StatusListContainer {...this.props} type='home' emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage="You aren’t following anyone yet. Visit {public} or use search to get started and meet other users." values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />} />
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Column from '../ui/components/column';
|
||||||
import { expandNotifications, clearNotifications } from '../../actions/notifications';
|
import { expandNotifications, clearNotifications } from '../../actions/notifications';
|
||||||
import NotificationContainer from './containers/notification_container';
|
import NotificationContainer from './containers/notification_container';
|
||||||
import { ScrollContainer } from 'react-router-scroll';
|
import { ScrollContainer } from 'react-router-scroll';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
|
@ -76,20 +76,29 @@ const Notifications = React.createClass({
|
||||||
render () {
|
render () {
|
||||||
const { intl, notifications, trackScroll, isLoading } = this.props;
|
const { intl, notifications, trackScroll, isLoading } = this.props;
|
||||||
|
|
||||||
let loadMore = '';
|
let loadMore = '';
|
||||||
|
let scrollableArea = '';
|
||||||
|
|
||||||
if (!isLoading && notifications.size > 0) {
|
if (!isLoading && notifications.size > 0) {
|
||||||
loadMore = <LoadMore onClick={this.handleLoadMore} />;
|
loadMore = <LoadMore onClick={this.handleLoadMore} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollableArea = (
|
if (isLoading || notifications.size > 0) {
|
||||||
<div className='scrollable' onScroll={this.handleScroll} ref={this.setRef}>
|
scrollableArea = (
|
||||||
<div>
|
<div className='scrollable' onScroll={this.handleScroll} ref={this.setRef}>
|
||||||
{notifications.map(item => <NotificationContainer key={item.get('id')} notification={item} accountId={item.get('account')} />)}
|
<div>
|
||||||
{loadMore}
|
{notifications.map(item => <NotificationContainer key={item.get('id')} notification={item} accountId={item.get('account')} />)}
|
||||||
|
{loadMore}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
} else {
|
||||||
|
scrollableArea = (
|
||||||
|
<div className='empty-column-indicator' ref={this.setRef}>
|
||||||
|
<FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. Interact with others to start the conversation." />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (trackScroll) {
|
if (trackScroll) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,29 +1,34 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { fetchStatus } from '../../actions/statuses';
|
import { fetchStatus } from '../../actions/statuses';
|
||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
import EmbeddedStatus from '../../components/status';
|
import EmbeddedStatus from '../../components/status';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import LoadingIndicator from '../../components/loading_indicator';
|
||||||
import DetailedStatus from './components/detailed_status';
|
import DetailedStatus from './components/detailed_status';
|
||||||
import ActionBar from './components/action_bar';
|
import ActionBar from './components/action_bar';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
import { favourite, reblog } from '../../actions/interactions';
|
import {
|
||||||
|
favourite,
|
||||||
|
unfavourite,
|
||||||
|
reblog,
|
||||||
|
unreblog
|
||||||
|
} from '../../actions/interactions';
|
||||||
import {
|
import {
|
||||||
replyCompose,
|
replyCompose,
|
||||||
mentionCompose
|
mentionCompose
|
||||||
} from '../../actions/compose';
|
} from '../../actions/compose';
|
||||||
import { deleteStatus } from '../../actions/statuses';
|
import { deleteStatus } from '../../actions/statuses';
|
||||||
import { initReport } from '../../actions/reports';
|
import { initReport } from '../../actions/reports';
|
||||||
import {
|
import {
|
||||||
makeGetStatus,
|
makeGetStatus,
|
||||||
getStatusAncestors,
|
getStatusAncestors,
|
||||||
getStatusDescendants
|
getStatusDescendants
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import { ScrollContainer } from 'react-router-scroll';
|
import { ScrollContainer } from 'react-router-scroll';
|
||||||
import ColumnBackButton from '../../components/column_back_button';
|
import ColumnBackButton from '../../components/column_back_button';
|
||||||
import StatusContainer from '../../containers/status_container';
|
import StatusContainer from '../../containers/status_container';
|
||||||
import { openMedia } from '../../actions/modal';
|
import { openMedia } from '../../actions/modal';
|
||||||
import { isMobile } from '../../is_mobile'
|
import { isMobile } from '../../is_mobile'
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
|
|
@ -126,8 +126,8 @@ export default function compose(state = initialState, action) {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.set('in_reply_to', action.status.get('id'));
|
map.set('in_reply_to', action.status.get('id'));
|
||||||
map.set('text', statusToTextMentions(state, action.status));
|
map.set('text', statusToTextMentions(state, action.status));
|
||||||
map.set('unlisted', action.status.get('visibility') === 'unlisted');
|
map.set('unlisted', action.status.get('visibility') === 'unlisted' || state.get('default_privacy') === 'unlisted');
|
||||||
map.set('private', action.status.get('visibility') === 'private');
|
map.set('private', action.status.get('visibility') === 'private' || state.get('default_privacy') === 'private');
|
||||||
});
|
});
|
||||||
case COMPOSE_REPLY_CANCEL:
|
case COMPOSE_REPLY_CANCEL:
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
|
|
|
@ -1182,3 +1182,22 @@ button.active i.fa-retweet {
|
||||||
background: rgba($color8, 0.1);
|
background: rgba($color8, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-column-indicator {
|
||||||
|
color: lighten($color1, 20%);
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
padding-top: 100px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $color4;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue