diff options
Diffstat (limited to 'app/javascript/mastodon/features')
20 files changed, 78 insertions, 12 deletions
diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js index 27581bfdc..9914b7e65 100644 --- a/app/javascript/mastodon/features/account_timeline/index.js +++ b/app/javascript/mastodon/features/account_timeline/index.js @@ -44,6 +44,7 @@ class AccountTimeline extends ImmutablePureComponent { withReplies: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -77,7 +78,7 @@ class AccountTimeline extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -112,6 +113,7 @@ class AccountTimeline extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/blocks/index.js b/app/javascript/mastodon/features/blocks/index.js index 96a219c94..8fb0f051b 100644 --- a/app/javascript/mastodon/features/blocks/index.js +++ b/app/javascript/mastodon/features/blocks/index.js @@ -32,6 +32,7 @@ class Blocks extends ImmutablePureComponent { accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, shouldUpdateScroll, hasMore } = this.props; + const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class Blocks extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js index 7d26c98b0..2f6999f61 100644 --- a/app/javascript/mastodon/features/community_timeline/index.js +++ b/app/javascript/mastodon/features/community_timeline/index.js @@ -126,6 +126,7 @@ class CommunityTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js index 7c075f5a5..16e200b31 100644 --- a/app/javascript/mastodon/features/domain_blocks/index.js +++ b/app/javascript/mastodon/features/domain_blocks/index.js @@ -33,6 +33,7 @@ class Blocks extends ImmutablePureComponent { hasMore: PropTypes.bool, domains: ImmutablePropTypes.orderedSet, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -44,7 +45,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, domains, shouldUpdateScroll, hasMore } = this.props; + const { intl, domains, shouldUpdateScroll, hasMore, multiColumn } = this.props; if (!domains) { return ( @@ -65,6 +66,7 @@ class Blocks extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {domains.map(domain => <DomainContainer key={domain} domain={domain} /> diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js index fa9401b90..8c7b23869 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.js +++ b/app/javascript/mastodon/features/favourited_statuses/index.js @@ -95,6 +95,7 @@ class Favourites extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js index d1ac229a2..464f7aeb0 100644 --- a/app/javascript/mastodon/features/favourites/index.js +++ b/app/javascript/mastodon/features/favourites/index.js @@ -23,6 +23,7 @@ class Favourites extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, shouldUpdateScroll: PropTypes.func, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -36,7 +37,7 @@ class Favourites extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, accountIds } = this.props; + const { shouldUpdateScroll, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -56,6 +57,7 @@ class Favourites extends ImmutablePureComponent { scrollKey='favourites' shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/follow_requests/index.js b/app/javascript/mastodon/features/follow_requests/index.js index 44624cb40..570cf57c8 100644 --- a/app/javascript/mastodon/features/follow_requests/index.js +++ b/app/javascript/mastodon/features/follow_requests/index.js @@ -32,6 +32,7 @@ class FollowRequests extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class FollowRequests extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, shouldUpdateScroll, accountIds, hasMore } = this.props; + const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class FollowRequests extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountAuthorizeContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js index e3387e1be..dce05bdc6 100644 --- a/app/javascript/mastodon/features/followers/index.js +++ b/app/javascript/mastodon/features/followers/index.js @@ -36,6 +36,7 @@ class Followers extends ImmutablePureComponent { hasMore: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -55,7 +56,7 @@ class Followers extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -87,6 +88,7 @@ class Followers extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {blockedBy ? [] : accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js index 3bf89fb2b..d9f2ef079 100644 --- a/app/javascript/mastodon/features/following/index.js +++ b/app/javascript/mastodon/features/following/index.js @@ -36,6 +36,7 @@ class Following extends ImmutablePureComponent { hasMore: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -55,7 +56,7 @@ class Following extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -87,6 +88,7 @@ class Following extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {blockedBy ? [] : accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index 0d3c97a64..c50f6a79a 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -157,6 +157,7 @@ class HashtagTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index 097f91c16..bf8ff117b 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -119,6 +119,7 @@ class HomeTimeline extends React.PureComponent { timelineId='home' emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! 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> }} />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js index 0db6d2228..844c93db1 100644 --- a/app/javascript/mastodon/features/list_timeline/index.js +++ b/app/javascript/mastodon/features/list_timeline/index.js @@ -184,6 +184,7 @@ class ListTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/lists/index.js b/app/javascript/mastodon/features/lists/index.js index 015e21b68..a06e0b934 100644 --- a/app/javascript/mastodon/features/lists/index.js +++ b/app/javascript/mastodon/features/lists/index.js @@ -40,6 +40,7 @@ class Lists extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, lists: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -47,7 +48,7 @@ class Lists extends ImmutablePureComponent { } render () { - const { intl, shouldUpdateScroll, lists } = this.props; + const { intl, shouldUpdateScroll, lists, multiColumn } = this.props; if (!lists) { return ( @@ -70,6 +71,7 @@ class Lists extends ImmutablePureComponent { shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />} + bindToDocument={!multiColumn} > {lists.map(list => <ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} /> diff --git a/app/javascript/mastodon/features/mutes/index.js b/app/javascript/mastodon/features/mutes/index.js index 4ed29a1ce..57d8b9915 100644 --- a/app/javascript/mastodon/features/mutes/index.js +++ b/app/javascript/mastodon/features/mutes/index.js @@ -32,6 +32,7 @@ class Mutes extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class Mutes extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, shouldUpdateScroll, hasMore, accountIds } = this.props; + const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class Mutes extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js index df4ad6f2a..e708c4fcf 100644 --- a/app/javascript/mastodon/features/notifications/index.js +++ b/app/javascript/mastodon/features/notifications/index.js @@ -191,6 +191,7 @@ class Notifications extends React.PureComponent { onScrollToTop={this.handleScrollToTop} onScroll={this.handleScroll} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} > {scrollableContent} </ScrollableList> diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js index 98cdbda3c..64ebfc7ae 100644 --- a/app/javascript/mastodon/features/pinned_statuses/index.js +++ b/app/javascript/mastodon/features/pinned_statuses/index.js @@ -28,6 +28,7 @@ class PinnedStatuses extends ImmutablePureComponent { statusIds: ImmutablePropTypes.list.isRequired, intl: PropTypes.object.isRequired, hasMore: PropTypes.bool.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class PinnedStatuses extends ImmutablePureComponent { } render () { - const { intl, shouldUpdateScroll, statusIds, hasMore } = this.props; + const { intl, shouldUpdateScroll, statusIds, hasMore, multiColumn } = this.props; return ( <Column icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}> @@ -53,6 +54,7 @@ class PinnedStatuses extends ImmutablePureComponent { scrollKey='pinned_statuses' hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js index 2b7d9c56f..1edb303b8 100644 --- a/app/javascript/mastodon/features/public_timeline/index.js +++ b/app/javascript/mastodon/features/public_timeline/index.js @@ -126,6 +126,7 @@ class PublicTimeline extends React.PureComponent { scrollKey={`public_timeline-${columnId}`} emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js index c05d21c74..26f93ad1b 100644 --- a/app/javascript/mastodon/features/reblogs/index.js +++ b/app/javascript/mastodon/features/reblogs/index.js @@ -23,6 +23,7 @@ class Reblogs extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, shouldUpdateScroll: PropTypes.func, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -36,7 +37,7 @@ class Reblogs extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, accountIds } = this.props; + const { shouldUpdateScroll, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -56,6 +57,7 @@ class Reblogs extends ImmutablePureComponent { scrollKey='reblogs' shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js index cc2ab6c8c..06f9e1bc4 100644 --- a/app/javascript/mastodon/features/ui/components/modal_root.js +++ b/app/javascript/mastodon/features/ui/components/modal_root.js @@ -32,6 +32,28 @@ const MODAL_COMPONENTS = { 'LIST_ADDER':ListAdder, }; +let cachedScrollbarWidth = null; + +export const getScrollbarWidth = () => { + if (cachedScrollbarWidth !== null) { + return cachedScrollbarWidth; + } + + const outer = document.createElement('div'); + outer.style.visibility = 'hidden'; + outer.style.overflow = 'scroll'; + document.body.appendChild(outer); + + const inner = document.createElement('div'); + outer.appendChild(inner); + + const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; + cachedScrollbarWidth = scrollbarWidth; + outer.parentNode.removeChild(outer); + + return scrollbarWidth; +}; + export default class ModalRoot extends React.PureComponent { static propTypes = { @@ -47,8 +69,10 @@ export default class ModalRoot extends React.PureComponent { componentDidUpdate (prevProps, prevState, { visible }) { if (visible) { document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; } else { document.body.classList.remove('with-modals--active'); + document.documentElement.style.marginRight = 0; } } diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index 791133afd..d1a3dc949 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -110,12 +110,25 @@ class SwitchingColumnsArea extends React.PureComponent { componentWillMount () { window.addEventListener('resize', this.handleResize, { passive: true }); + + if (this.state.mobile || forceSingleColumn) { + document.body.classList.toggle('layout-single-column', true); + document.body.classList.toggle('layout-multiple-columns', false); + } else { + document.body.classList.toggle('layout-single-column', false); + document.body.classList.toggle('layout-multiple-columns', true); + } } - componentDidUpdate (prevProps) { + componentDidUpdate (prevProps, prevState) { if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { this.node.handleChildrenContentChange(); } + + if (prevState.mobile !== this.state.mobile && !forceSingleColumn) { + document.body.classList.toggle('layout-single-column', this.state.mobile); + document.body.classList.toggle('layout-multiple-columns', !this.state.mobile); + } } componentWillUnmount () { |