From 5ebbaffaa308d4e0496f99321bbaeb1205bb8930 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 9 Nov 2018 16:47:50 +0100 Subject: [Glitch] Use local instead of global loading indicator for timelines, account timelines Port dd00cd19d2536ce70442d74d72986721427691a5 to glitch-soc --- .../flavours/glitch/components/scrollable_list.js | 24 ++++++++++++++++++---- .../flavours/glitch/components/status_list.js | 4 ++-- 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js index 3ee710dc9..3a6893b01 100644 --- a/app/javascript/flavours/glitch/components/scrollable_list.js +++ b/app/javascript/flavours/glitch/components/scrollable_list.js @@ -8,6 +8,7 @@ import { throttle } from 'lodash'; import { List as ImmutableList } from 'immutable'; import classNames from 'classnames'; import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen'; +import LoadingIndicator from './loading_indicator'; export default class ScrollableList extends PureComponent { @@ -23,6 +24,7 @@ export default class ScrollableList extends PureComponent { trackScroll: PropTypes.bool, shouldUpdateScroll: PropTypes.func, isLoading: PropTypes.bool, + showLoading: PropTypes.bool, hasMore: PropTypes.bool, prepend: PropTypes.node, emptyMessage: PropTypes.node, @@ -131,12 +133,14 @@ export default class ScrollableList extends PureComponent { getFirstChildKey (props) { const { children } = props; - let firstChild = children; + let firstChild = children; + if (children instanceof ImmutableList) { firstChild = children.get(0); } else if (Array.isArray(children)) { firstChild = children[0]; } + return firstChild && firstChild.key; } @@ -144,7 +148,7 @@ export default class ScrollableList extends PureComponent { this.node = c; } - handleLoadMore = (e) => { + handleLoadMore = e => { e.preventDefault(); this.props.onLoadMore(); } @@ -155,14 +159,26 @@ export default class ScrollableList extends PureComponent { } render () { - const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props; + const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props; const { fullscreen } = this.state; const childrenCount = React.Children.count(children); const loadMore = (hasMore && childrenCount > 0 && onLoadMore) ? : null; let scrollableArea = null; - if (isLoading || childrenCount > 0 || !emptyMessage) { + if (showLoading) { + scrollableArea = ( +
+
+ {prepend} +
+ +
+ +
+
+ ); + } else if (isLoading || childrenCount > 0 || !emptyMessage) { scrollableArea = (
diff --git a/app/javascript/flavours/glitch/components/status_list.js b/app/javascript/flavours/glitch/components/status_list.js index aa902db47..d13bd72f6 100644 --- a/app/javascript/flavours/glitch/components/status_list.js +++ b/app/javascript/flavours/glitch/components/status_list.js @@ -24,7 +24,7 @@ export default class StatusList extends ImmutablePureComponent { hasMore: PropTypes.bool, prepend: PropTypes.node, emptyMessage: PropTypes.node, - timelineId: PropTypes.string.isRequired, + timelineId: PropTypes.string, }; static defaultProps = { @@ -121,7 +121,7 @@ export default class StatusList extends ImmutablePureComponent { } return ( - + {scrollableContent} ); -- cgit From 2fe0cb16239ed86016ebea352425862a561b63a2 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 13 Nov 2018 15:32:29 +0100 Subject: [Glitch] Prepend account header even when status list is empty Partially port 90b64c006998ec3bae365007781c61e8a79eeeef --- app/javascript/flavours/glitch/components/scrollable_list.js | 11 ++++++++--- app/javascript/flavours/glitch/components/status_list.js | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js index 3a6893b01..a05d49829 100644 --- a/app/javascript/flavours/glitch/components/scrollable_list.js +++ b/app/javascript/flavours/glitch/components/scrollable_list.js @@ -27,6 +27,7 @@ export default class ScrollableList extends PureComponent { showLoading: PropTypes.bool, hasMore: PropTypes.bool, prepend: PropTypes.node, + alwaysPrepend: PropTypes.bool, emptyMessage: PropTypes.node, children: PropTypes.node, }; @@ -159,7 +160,7 @@ export default class ScrollableList extends PureComponent { } render () { - const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props; + const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, prepend, alwaysPrepend, emptyMessage, onLoadMore } = this.props; const { fullscreen } = this.state; const childrenCount = React.Children.count(children); @@ -203,8 +204,12 @@ export default class ScrollableList extends PureComponent { ); } else { scrollableArea = ( -
- {emptyMessage} +
+ {alwaysPrepend && prepend} + +
+ {emptyMessage} +
); } diff --git a/app/javascript/flavours/glitch/components/status_list.js b/app/javascript/flavours/glitch/components/status_list.js index d13bd72f6..68cd608b9 100644 --- a/app/javascript/flavours/glitch/components/status_list.js +++ b/app/javascript/flavours/glitch/components/status_list.js @@ -23,6 +23,7 @@ export default class StatusList extends ImmutablePureComponent { isPartial: PropTypes.bool, hasMore: PropTypes.bool, prepend: PropTypes.node, + alwaysPrepend: PropTypes.bool, emptyMessage: PropTypes.node, timelineId: PropTypes.string, }; -- cgit From 86527024aa392ad6edf5b1d0dc7fe936b7ad4968 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 15 Nov 2018 15:35:13 +0100 Subject: In detailed status view, take displayMedia setting into account when changing media Fixes #819 --- app/javascript/flavours/glitch/components/media_gallery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index e8dfd6f8e..d637d7c8e 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -232,7 +232,7 @@ export default class MediaGallery extends React.PureComponent { componentWillReceiveProps (nextProps) { if (!is(nextProps.media, this.props.media)) { - this.setState({ visible: !nextProps.sensitive }); + this.setState({ visible: nextProps.revealed === undefined ? (displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all') : nextProps.revealed }); } } -- cgit From b3ff35a75cf04e4aba2712a9d0897257cf79af82 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 25 Sep 2018 14:46:14 +0200 Subject: Move URLs to backend in their own file --- .../glitch/components/status_action_bar.js | 17 ++++++++++++--- .../features/account/components/action_bar.js | 12 ++++++++--- .../features/composer/direct_warning/index.js | 4 +++- .../glitch/features/composer/warning/index.js | 7 +++++- .../glitch/features/drawer/account/index.js | 25 +++++++++++++--------- .../glitch/features/drawer/header/index.js | 3 ++- .../glitch/features/getting_started/index.js | 5 +++-- .../features/local_settings/navigation/index.js | 3 ++- .../features/status/components/action_bar.js | 17 ++++++++++++--- .../flavours/glitch/util/backend_links.js | 6 ++++++ 10 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 app/javascript/flavours/glitch/util/backend_links.js (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js index f7e741d2d..16abcab4e 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.js +++ b/app/javascript/flavours/glitch/components/status_action_bar.js @@ -7,6 +7,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { me, isStaff } from 'flavours/glitch/util/initial_state'; import RelativeTimestamp from './relative_timestamp'; +import { accountAdminLink, statusAdminLink } from 'flavours/glitch/util/backend_links'; const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, @@ -188,10 +189,20 @@ export default class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); - if (isStaff) { + if (isStaff && (accountAdminLink || statusAdminLink)) { menu.push(null); - menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); - menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); + if (accountAdminLink !== undefined) { + menu.push({ + text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), + href: accountAdminLink(status.getIn(['account', 'id'])), + }); + } + if (statusAdminLink !== undefined) { + menu.push({ + text: intl.formatMessage(messages.admin_status), + href: statusAdminLink(status.getIn(['account', 'id']), status.get('id')), + }); + } } } diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js index acbe46f8a..ffa5b7e5e 100644 --- a/app/javascript/flavours/glitch/features/account/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js @@ -5,6 +5,7 @@ import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_cont import { NavLink } from 'react-router-dom'; import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl'; import { me, isStaff } from 'flavours/glitch/util/initial_state'; +import { profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links'; const messages = defineMessages({ mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' }, @@ -77,7 +78,9 @@ export default class ActionBar extends React.PureComponent { menu.push(null); if (account.get('id') === me) { - menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' }); + if (profileLink !== undefined) { + menu.push({ text: intl.formatMessage(messages.edit_profile), href: profileLink }); + } } else { if (account.getIn(['relationship', 'following'])) { if (account.getIn(['relationship', 'showing_reblogs'])) { @@ -131,9 +134,12 @@ export default class ActionBar extends React.PureComponent { } } - if (account.get('id') !== me && isStaff) { + if (account.get('id') !== me && isStaff && (accountAdminLink !== undefined)) { menu.push(null); - menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` }); + menu.push({ + text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), + href: accountAdminLink(account.get('id')), + }); } return ( diff --git a/app/javascript/flavours/glitch/features/composer/direct_warning/index.js b/app/javascript/flavours/glitch/features/composer/direct_warning/index.js index d1febdd1b..3b1369acd 100644 --- a/app/javascript/flavours/glitch/features/composer/direct_warning/index.js +++ b/app/javascript/flavours/glitch/features/composer/direct_warning/index.js @@ -2,6 +2,7 @@ import React from 'react'; import Motion from 'flavours/glitch/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { defineMessages, FormattedMessage } from 'react-intl'; +import { termsLink} from 'flavours/glitch/util/backend_links'; // This is the spring used with our motion. const motionSpring = spring(1, { damping: 35, stiffness: 400 }); @@ -42,7 +43,8 @@ export default function ComposerDirectWarning () { }} > - + + { termsLink !== undefined && }
)} diff --git a/app/javascript/flavours/glitch/features/composer/warning/index.js b/app/javascript/flavours/glitch/features/composer/warning/index.js index c225b50e8..8be8acbce 100644 --- a/app/javascript/flavours/glitch/features/composer/warning/index.js +++ b/app/javascript/flavours/glitch/features/composer/warning/index.js @@ -2,6 +2,7 @@ import React from 'react'; import Motion from 'flavours/glitch/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { defineMessages, FormattedMessage } from 'react-intl'; +import { profileLink } from 'flavours/glitch/util/backend_links'; // This is the spring used with our motion. const motionSpring = spring(1, { damping: 35, stiffness: 400 }); @@ -20,6 +21,10 @@ const messages = defineMessages({ // The component. export default function ComposerWarning () { + let lockedLink = ; + if (profileLink !== undefined) { + lockedLink = {lockedLink}; + } return ( }} + values={{ locked: lockedLink }} />
)} diff --git a/app/javascript/flavours/glitch/features/drawer/account/index.js b/app/javascript/flavours/glitch/features/drawer/account/index.js index 168d0c2cf..552848641 100644 --- a/app/javascript/flavours/glitch/features/drawer/account/index.js +++ b/app/javascript/flavours/glitch/features/drawer/account/index.js @@ -12,6 +12,7 @@ import Permalink from 'flavours/glitch/components/permalink'; // Utils. import { hiddenComponent } from 'flavours/glitch/util/react_helpers'; +import { profileLink } from 'flavours/glitch/util/backend_links'; // Messages. const messages = defineMessages({ @@ -28,12 +29,14 @@ export default function DrawerAccount ({ account }) { if (!account) { return (
- - - + { profileLink !== undefined && ( + + + + )}
); } @@ -59,10 +62,12 @@ export default function DrawerAccount ({ account }) { > @{account.get('acct')} - + { profileLink !== undefined && ( + + )}
); } diff --git a/app/javascript/flavours/glitch/features/drawer/header/index.js b/app/javascript/flavours/glitch/features/drawer/header/index.js index 7fefd32c9..da5599732 100644 --- a/app/javascript/flavours/glitch/features/drawer/header/index.js +++ b/app/javascript/flavours/glitch/features/drawer/header/index.js @@ -10,6 +10,7 @@ import Icon from 'flavours/glitch/components/icon'; // Utils. import { conditionalRender } from 'flavours/glitch/util/react_helpers'; +import { signOutLink } from 'flavours/glitch/util/backend_links'; // Messages. const messages = defineMessages({ @@ -109,7 +110,7 @@ export default function DrawerHeader ({ diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index ce1ae50e4..c87f76c5e 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -13,6 +13,7 @@ import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { List as ImmutableList } from 'immutable'; import { createSelector } from 'reselect'; import { fetchLists } from 'flavours/glitch/actions/lists'; +import { preferencesLink, profileLink, signOutLink } from 'flavours/glitch/util/backend_links'; const messages = defineMessages({ heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, @@ -157,9 +158,9 @@ export default class GettingStarted extends ImmutablePureComponent { {listItems} - + { preferencesLink !== undefined && } - +
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js index cf02101cf..ce10e3f51 100644 --- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js @@ -5,6 +5,7 @@ import { injectIntl, defineMessages } from 'react-intl'; // Our imports import LocalSettingsNavigationItem from './item'; +import { preferencesLink } from 'flavours/glitch/util/backend_links'; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -71,7 +72,7 @@ export default class LocalSettingsNavigation extends React.PureComponent { /> `/admin/accounts/${id}`; +export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses/${status_id}`; -- cgit From 0d3612482e8b6fb27643dbcefce046897223e890 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 22 Nov 2018 16:43:41 +0100 Subject: Render placeholder instead of image when MediaGallery container width isn't known --- app/javascript/flavours/glitch/components/media_gallery.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index d637d7c8e..10afeb2eb 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -237,7 +237,7 @@ export default class MediaGallery extends React.PureComponent { } componentDidUpdate (prevProps) { - if (this.node && this.node.offsetWidth) { + if (this.node && this.node.offsetWidth && this.node.offsetWidth != this.state.width) { this.setState({ width: this.node.offsetWidth, }); @@ -254,8 +254,7 @@ export default class MediaGallery extends React.PureComponent { handleRef = (node) => { this.node = node; - if (node /*&& this.isStandaloneEligible()*/) { - // offsetWidth triggers a layout, so only calculate when we need to + if (node && node.offsetWidth && node.offsetWidth != this.state.width) { this.setState({ width: node.offsetWidth, }); @@ -276,10 +275,14 @@ export default class MediaGallery extends React.PureComponent { const style = {}; + const computedClass = classNames('media-gallery', { 'full-width': fullwidth }); + if (this.isStandaloneEligible() && width) { style.height = width / this.props.media.getIn([0, 'meta', 'small', 'aspect']); } else if (width) { style.height = width / (16/9); + } else { + return (
); } if (!visible) { @@ -299,8 +302,6 @@ export default class MediaGallery extends React.PureComponent { } } - const computedClass = classNames('media-gallery', { 'full-width': fullwidth }); - return (
{visible ? ( -- cgit