diff --git a/app/javascript/gabsocial/components/list.js b/app/javascript/gabsocial/components/list.js index 8566a01e..69a903f4 100644 --- a/app/javascript/gabsocial/components/list.js +++ b/app/javascript/gabsocial/components/list.js @@ -4,6 +4,7 @@ import Block from './block' import ScrollableList from './scrollable_list' import ListItem from './list_item' import Dummy from './dummy' +import ListItemPlaceholder from './placeholder/list_item_placeholder' export default class List extends ImmutablePureComponent { @@ -45,6 +46,8 @@ export default class List extends ImmutablePureComponent { scrollKey={scrollKey} emptyMessage={emptyMessage} showLoading={showLoading} + placeholderComponent={ListItemPlaceholder} + placeholderCount={6} > { items.map((item, i) => ( diff --git a/app/javascript/gabsocial/components/panel/groups_panel.js b/app/javascript/gabsocial/components/panel/groups_panel.js index 80f2a5df..1353c632 100644 --- a/app/javascript/gabsocial/components/panel/groups_panel.js +++ b/app/javascript/gabsocial/components/panel/groups_panel.js @@ -5,6 +5,7 @@ import { fetchGroups } from '../../actions/groups' import PanelLayout from './panel_layout' import GroupListItem from '../group_list_item' import ScrollableList from '../scrollable_list' +import GroupListItemPlaceholder from '../placeholder/group_list_item_placeholder' const messages = defineMessages({ title: { id: 'groups.sidebar-panel.title', defaultMessage: 'Groups you\'re in' }, @@ -86,6 +87,8 @@ class GroupSidebarPanel extends ImmutablePureComponent { { groupIds && groupIds.slice(0, maxCount).map((groupId, i) => ( diff --git a/app/javascript/gabsocial/components/panel/media_gallery_panel.js b/app/javascript/gabsocial/components/panel/media_gallery_panel.js index c7c471c8..92b869b2 100644 --- a/app/javascript/gabsocial/components/panel/media_gallery_panel.js +++ b/app/javascript/gabsocial/components/panel/media_gallery_panel.js @@ -5,6 +5,7 @@ import { expandAccountMediaTimeline } from '../../actions/timelines' import { getAccountGallery } from '../../selectors' import PanelLayout from './panel_layout' import MediaItem from '../media_item' +import MediaGalleryPanelPlaceholder from '../placeholder/media_gallery_panel_placeholder' const messages = defineMessages({ title: { id: 'media_gallery_panel.title', defaultMessage: 'Media' }, @@ -16,6 +17,7 @@ const mapStateToProps = (state, { account }) => { return { accountId, + isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading'], true), attachments: getAccountGallery(state, accountId), } } @@ -29,6 +31,7 @@ class MediaGalleryPanel extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, accountId: PropTypes.string, account: ImmutablePropTypes.map, + isLoading: PropTypes.bool, attachments: ImmutablePropTypes.list.isRequired, intl: PropTypes.object.isRequired, } @@ -49,35 +52,40 @@ class MediaGalleryPanel extends ImmutablePureComponent { render() { const { - intl, account, - attachments + attachments, + intl, + isLoading, } = this.props - if (!account || !attachments) return null + if (!attachments) return null return ( - { - attachments.size > 0 && -
- { - attachments.slice(0, 16).map((attachment, i) => ( - - )) - } -
- } +
+ { + !!account && attachments.size > 0 && + attachments.slice(0, 16).map((attachment, i) => ( + + )) + } + { + !account || (attachments.size === 0 && isLoading) && +
+ +
+ } +
) } diff --git a/app/javascript/gabsocial/components/panel/profile_info_panel.js b/app/javascript/gabsocial/components/panel/profile_info_panel.js index 1000827d..b8af5ce6 100644 --- a/app/javascript/gabsocial/components/panel/profile_info_panel.js +++ b/app/javascript/gabsocial/components/panel/profile_info_panel.js @@ -9,6 +9,7 @@ import Divider from '../divider' import Icon from '../icon' import Text from '../text' import Dummy from '../dummy' +import ProfileInfoPanelPlaceholder from '../placeholder/profile_info_panel_placeholder' const messages = defineMessages({ title: { id: 'about', defaultMessage: 'About' }, @@ -35,7 +36,15 @@ class ProfileInfoPanel extends ImmutablePureComponent { noPanel } = this.props - if (!account) return null + const Wrapper = noPanel ? Dummy : PanelLayout + + if (!account) { + return ( + + + + ) + } const fields = account.get('fields') const content = { __html: account.get('note_emojified') } @@ -46,8 +55,6 @@ class ProfileInfoPanel extends ImmutablePureComponent { const isInvestor = account.get('is_investor') const hasBadges = isPro || isDonor || isInvestor - const Wrapper = noPanel ? Dummy : PanelLayout - return (
diff --git a/app/javascript/gabsocial/components/panel/profile_stats_panel.js b/app/javascript/gabsocial/components/panel/profile_stats_panel.js index e8603d70..ef6e7fdd 100644 --- a/app/javascript/gabsocial/components/panel/profile_stats_panel.js +++ b/app/javascript/gabsocial/components/panel/profile_stats_panel.js @@ -6,6 +6,7 @@ import { shortNumberFormat } from '../../utils/numbers' import PanelLayout from './panel_layout' import UserStat from '../user_stat' import Dummy from '../dummy' +import ProfileStatsPanelPlaceholder from '../placeholder/profile_stats_panel_placeholder' import ResponsiveClassesComponent from '../../features/ui/util/responsive_classes_component' const messages = defineMessages({ @@ -32,12 +33,14 @@ class ProfileStatsPanel extends ImmutablePureComponent { noPanel } = this.props - if (!account) return null - const Wrapper = noPanel ? Dummy : PanelLayout return ( + { + !account && + + } { !!account && { diff --git a/app/javascript/gabsocial/components/panel/who_to_follow_panel.js b/app/javascript/gabsocial/components/panel/who_to_follow_panel.js index e87e0142..208a3feb 100644 --- a/app/javascript/gabsocial/components/panel/who_to_follow_panel.js +++ b/app/javascript/gabsocial/components/panel/who_to_follow_panel.js @@ -5,7 +5,8 @@ import { } from '../../actions/suggestions' import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePropTypes from 'react-immutable-proptypes' -import Account from '../../components/account' +import Account from '../account' +import AccountPlaceholder from '../placeholder/account_placeholder' import PanelLayout from './panel_layout' const messages = defineMessages({ @@ -16,6 +17,7 @@ const messages = defineMessages({ const mapStateToProps = (state) => ({ suggestions: state.getIn(['suggestions', 'related', 'items']), + isLoading: state.getIn(['suggestions', 'related', 'isLoading']), }) const mapDispatchToProps = (dispatch) => ({ @@ -33,6 +35,7 @@ class WhoToFollowPanel extends ImmutablePureComponent { fetchRelatedSuggestions: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, suggestions: ImmutablePropTypes.list.isRequired, + isLoading: PropTypes.bool.isRequired, isLazy: PropTypes.bool, } @@ -69,12 +72,16 @@ class WhoToFollowPanel extends ImmutablePureComponent { render() { const { intl, + isLoading, suggestions, dismissRelatedSuggestion, } = this.props if (suggestions.isEmpty()) return null + const Child = isLoading ? AccountPlaceholder : Account + const arr = isLoading ? Array.apply(null, { length: 6 }) : suggestions + return (
{ - suggestions.map(accountId => ( - ( + : null if (showLoading) { - return + if (Placeholder) { + return ( + + { + Array.apply(null, { + length: placeholderCount + }).map((_, i) => ( + + )) + } + + ) + } + + return ( + + ) } else if (isLoading || childrenCount > 0 || hasMore || !emptyMessage) { return (
diff --git a/app/javascript/gabsocial/components/status.js b/app/javascript/gabsocial/components/status.js index fb2c7d36..561d455b 100644 --- a/app/javascript/gabsocial/components/status.js +++ b/app/javascript/gabsocial/components/status.js @@ -12,6 +12,7 @@ import { me, displayMedia } from '../initial_state' import scheduleIdleTask from '../utils/schedule_idle_task' import ComposeFormContainer from '../features/compose/containers/compose_form_container' import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component' +import CommentPlaceholder from './placeholder/comment_placeholder' import StatusContent from './status_content' import StatusPrepend from './status_prepend' import StatusActionBar from './status_action_bar' @@ -413,6 +414,7 @@ class Status extends ImmutablePureComponent { if (isComment && !ancestorStatus && !isChild) { // Wait to load... + // return if (contextType === 'feature') { return } @@ -585,46 +587,49 @@ class Status extends ImmutablePureComponent { } - + { - status.get('replies_count') > 0 && !commentsLimited && !isNotification && descendantsIds && descendantsIds.size === 0 && + status.get('replies_count') > 0 && !isChild && !isNotification && !commentsLimited &&
- - - } - { - descendantsIds && !isChild && !isNotification && descendantsIds.size > 0 && !commentsLimited && - -
+
+ + {intl.formatMessage(messages.sortBy)} + + +
{ - !commentsLimited && descendantsIds.size > 1 && -
- - {intl.formatMessage(messages.sortBy)} - - -
+ descendantsIds.size === 0 && + + + + + + } + + { + descendantsIds.size > 0 && + } - }
diff --git a/app/javascript/gabsocial/components/status_list.js b/app/javascript/gabsocial/components/status_list.js index 3648a406..1f0e22bb 100644 --- a/app/javascript/gabsocial/components/status_list.js +++ b/app/javascript/gabsocial/components/status_list.js @@ -9,9 +9,9 @@ import { dequeueTimeline } from '../actions/timelines' import { scrollTopTimeline } from '../actions/timelines' import { fetchStatus, fetchContext } from '../actions/statuses' import StatusContainer from '../containers/status_container' +import StatusPlaceholder from './placeholder/status_placeholder' import ScrollableList from './scrollable_list' import TimelineQueueButtonHeader from './timeline_queue_button_header' -import ColumnIndicator from './column_indicator' const makeGetStatusIds = () => createSelector([ (state, { type, id }) => state.getIn(['settings', type], ImmutableMap()), @@ -228,8 +228,15 @@ class StatusList extends ImmutablePureComponent { } = this.props const { fetchedContext, refreshing } = this.state - if (isPartial) { - return + if (isPartial || isLoading && statusIds.size === 0) { + return ( + + + + + + + ) } // : hack : diff --git a/app/javascript/gabsocial/features/notifications.js b/app/javascript/gabsocial/features/notifications.js index 916b9233..cc9e4cc7 100644 --- a/app/javascript/gabsocial/features/notifications.js +++ b/app/javascript/gabsocial/features/notifications.js @@ -17,6 +17,7 @@ import ScrollableList from '../components/scrollable_list' import TimelineQueueButtonHeader from '../components/timeline_queue_button_header' import Block from '../components/block' import Account from '../components/account' +import NotificationPlaceholder from '../components/placeholder/notification_placeholder' const mapStateToProps = (state) => ({ notifications: state.getIn(['notifications', 'items']), @@ -180,6 +181,8 @@ class Notifications extends ImmutablePureComponent { onLoadMore={this.handleLoadOlder} onScrollToTop={this.handleScrollToTop} onScroll={this.handleScroll} + placeholderComponent={NotificationPlaceholder} + placeholderCount={3} > {scrollableContent} diff --git a/app/javascript/gabsocial/features/status.js b/app/javascript/gabsocial/features/status.js index 41ec973f..4ea37a95 100644 --- a/app/javascript/gabsocial/features/status.js +++ b/app/javascript/gabsocial/features/status.js @@ -6,7 +6,7 @@ import { fetchContext, } from '../actions/statuses' import StatusContainer from '../containers/status_container' -import ColumnIndicator from '../components/column_indicator' +import StatusPlaceholder from '../components/placeholder/status_placeholder' const mapStateToProps = (state, props) => { const statusId = props.id || props.params.statusId @@ -73,7 +73,7 @@ class Status extends ImmutablePureComponent { const { status } = this.props if (!status) { - return + return } return (