Fix #642 - Add "empty column" text to home/notifications

pull/589/head
Eugen Rochko 2017-02-18 02:37:59 +01:00
parent 1d5dfda3d4
commit 9e99b8c068
7 changed files with 89 additions and 44 deletions

View File

@ -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 (

View File

@ -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>
); );
}, },

View File

@ -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 arent 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>
); );
}, },

View File

@ -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 (

View File

@ -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 = () => {

View File

@ -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 => {

View File

@ -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;
}
}
}