diff options
Diffstat (limited to 'app/javascript/flavours')
26 files changed, 150 insertions, 42 deletions
diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js index 7c0b6d082..c022290a4 100644 --- a/app/javascript/flavours/glitch/components/scrollable_list.js +++ b/app/javascript/flavours/glitch/components/scrollable_list.js @@ -35,6 +35,7 @@ export default class ScrollableList extends PureComponent { alwaysPrepend: PropTypes.bool, emptyMessage: PropTypes.node, children: PropTypes.node, + bindToDocument: PropTypes.bool, }; static defaultProps = { @@ -50,7 +51,9 @@ export default class ScrollableList extends PureComponent { handleScroll = throttle(() => { if (this.node) { - const { scrollTop, scrollHeight, clientHeight } = this.node; + const scrollTop = this.getScrollTop(); + const scrollHeight = this.getScrollHeight(); + const clientHeight = this.getClientHeight(); const offset = scrollHeight - scrollTop - clientHeight; if (400 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) { @@ -80,9 +83,14 @@ export default class ScrollableList extends PureComponent { scrollToTopOnMouseIdle = false; setScrollTop = newScrollTop => { - if (this.node.scrollTop !== newScrollTop) { + if (this.getScrollTop() !== newScrollTop) { this.lastScrollWasSynthetic = true; - this.node.scrollTop = newScrollTop; + + if (this.props.bindToDocument) { + document.scrollingElement.scrollTop = newScrollTop; + } else { + this.node.scrollTop = newScrollTop; + } } }; @@ -100,7 +108,7 @@ export default class ScrollableList extends PureComponent { this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY); - if (!this.mouseMovedRecently && this.node.scrollTop === 0) { + if (!this.mouseMovedRecently && this.getScrollTop() === 0) { // Only set if we just started moving and are scrolled to the top. this.scrollToTopOnMouseIdle = true; } @@ -132,15 +140,27 @@ export default class ScrollableList extends PureComponent { } getScrollPosition = () => { - if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) { - return {height: this.node.scrollHeight, top: this.node.scrollTop}; + if (this.node && (this.getScrollTop() > 0 || this.mouseMovedRecently)) { + return { height: this.getScrollHeight(), top: this.getScrollTop() }; } else { return null; } } + getScrollTop = () => { + return this.props.bindToDocument ? document.scrollingElement.scrollTop : this.node.scrollTop; + } + + getScrollHeight = () => { + return this.props.bindToDocument ? document.scrollingElement.scrollHeight : this.node.scrollHeight; + } + + getClientHeight = () => { + return this.props.bindToDocument ? document.scrollingElement.clientHeight : this.node.clientHeight; + } + updateScrollBottom = (snapshot) => { - const newScrollTop = this.node.scrollHeight - snapshot; + const newScrollTop = this.getScrollHeight() - snapshot; this.setScrollTop(newScrollTop); } @@ -155,8 +175,8 @@ export default class ScrollableList extends PureComponent { this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); const pendingChanged = (prevProps.numPending > 0) !== (this.props.numPending > 0); - if (pendingChanged || someItemInserted && (this.node.scrollTop > 0 || this.mouseMovedRecently)) { - return this.node.scrollHeight - this.node.scrollTop; + if (pendingChanged || someItemInserted && (this.getScrollTop() > 0 || this.mouseMovedRecently)) { + return this.getScrollHeight() - this.getScrollTop(); } else { return null; } @@ -165,7 +185,9 @@ export default class ScrollableList extends PureComponent { componentDidUpdate (prevProps, prevState, snapshot) { // Reset the scroll position when a new child comes in in order not to // jerk the scrollbar around if you're already scrolled down the page. - if (snapshot !== null) this.updateScrollBottom(snapshot); + if (snapshot !== null) { + this.updateScrollBottom(snapshot); + } } componentWillUnmount () { @@ -191,13 +213,23 @@ export default class ScrollableList extends PureComponent { } attachScrollListener () { - this.node.addEventListener('scroll', this.handleScroll); - this.node.addEventListener('wheel', this.handleWheel); + if (this.props.bindToDocument) { + document.addEventListener('scroll', this.handleScroll); + document.addEventListener('wheel', this.handleWheel); + } else { + this.node.addEventListener('scroll', this.handleScroll); + this.node.addEventListener('wheel', this.handleWheel); + } } detachScrollListener () { - this.node.removeEventListener('scroll', this.handleScroll); - this.node.removeEventListener('wheel', this.handleWheel); + if (this.props.bindToDocument) { + document.removeEventListener('scroll', this.handleScroll); + document.removeEventListener('wheel', this.handleWheel); + } else { + this.node.removeEventListener('scroll', this.handleScroll); + this.node.removeEventListener('wheel', this.handleWheel); + } } getFirstChildKey (props) { diff --git a/app/javascript/flavours/glitch/containers/media_container.js b/app/javascript/flavours/glitch/containers/media_container.js index 41547412e..0afe50740 100644 --- a/app/javascript/flavours/glitch/containers/media_container.js +++ b/app/javascript/flavours/glitch/containers/media_container.js @@ -10,6 +10,7 @@ import Poll from 'flavours/glitch/components/poll'; import Hashtag from 'flavours/glitch/components/hashtag'; import Audio from 'flavours/glitch/features/audio'; import ModalRoot from 'flavours/glitch/components/modal_root'; +import { getScrollbarWidth } from 'flavours/glitch/features/ui/components/modal_root'; import MediaModal from 'flavours/glitch/features/ui/components/media_modal'; import { List as ImmutableList, fromJS } from 'immutable'; @@ -33,6 +34,8 @@ export default class MediaContainer extends PureComponent { handleOpenMedia = (media, index) => { document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; + this.setState({ media, index }); } @@ -40,11 +43,15 @@ export default class MediaContainer extends PureComponent { const media = ImmutableList([video]); document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; + this.setState({ media, time }); } handleCloseMedia = () => { document.body.classList.remove('with-modals--active'); + document.documentElement.style.marginRight = 0; + this.setState({ media: null, index: null, time: null }); } diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index 2f0859341..a6ed4564c 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -39,6 +39,7 @@ class AccountTimeline extends ImmutablePureComponent { hasMore: PropTypes.bool, withReplies: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -76,7 +77,7 @@ class AccountTimeline extends ImmutablePureComponent { } render () { - const { statusIds, featuredStatusIds, isLoading, hasMore, isAccount } = this.props; + const { statusIds, featuredStatusIds, isLoading, hasMore, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -108,6 +109,7 @@ class AccountTimeline extends ImmutablePureComponent { hasMore={hasMore} onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js index 8a84f5a55..ae0cdf2fe 100644 --- a/app/javascript/flavours/glitch/features/blocks/index.js +++ b/app/javascript/flavours/glitch/features/blocks/index.js @@ -31,6 +31,7 @@ class Blocks extends ImmutablePureComponent { accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -42,7 +43,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore } = this.props; + const { intl, accountIds, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -62,6 +63,7 @@ class Blocks extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} hasMore={hasMore} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index 5585edc9c..ca437d2b0 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -125,6 +125,7 @@ class CommunityTimeline extends React.PureComponent { timelineId={`community${onlyMedia ? ':media' : ''}`} onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.js b/app/javascript/flavours/glitch/features/domain_blocks/index.js index 49e0368d7..b92ce349b 100644 --- a/app/javascript/flavours/glitch/features/domain_blocks/index.js +++ b/app/javascript/flavours/glitch/features/domain_blocks/index.js @@ -32,6 +32,7 @@ class Blocks extends ImmutablePureComponent { hasMore: PropTypes.bool, domains: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, domains, hasMore } = this.props; + const { intl, domains, hasMore, multiColumn } = this.props; if (!domains) { return ( @@ -63,6 +64,7 @@ class Blocks extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} hasMore={hasMore} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {domains.map(domain => <DomainContainer key={domain} domain={domain} /> diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js index 719a31d6e..99b532294 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js @@ -93,6 +93,7 @@ class Favourites extends ImmutablePureComponent { isLoading={isLoading} onLoadMore={this.handleLoadMore} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js index 7afadf12e..3c0c2a905 100644 --- a/app/javascript/flavours/glitch/features/favourites/index.js +++ b/app/javascript/flavours/glitch/features/favourites/index.js @@ -27,6 +27,7 @@ class Favourites extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -51,7 +52,7 @@ class Favourites extends ImmutablePureComponent { } render () { - const { intl, accountIds } = this.props; + const { intl, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -74,6 +75,7 @@ class Favourites extends ImmutablePureComponent { <ScrollableList scrollKey='favourites' emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js index a7e8f4b61..04c1f3635 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.js +++ b/app/javascript/flavours/glitch/features/follow_requests/index.js @@ -31,6 +31,7 @@ class FollowRequests extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -42,7 +43,7 @@ class FollowRequests extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore } = this.props; + const { intl, accountIds, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -63,6 +64,7 @@ class FollowRequests extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} hasMore={hasMore} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountAuthorizeContainer key={id} id={id} /> diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 2bd0e6e2f..39fdffae6 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -33,6 +33,7 @@ class Followers extends ImmutablePureComponent { accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -70,7 +71,7 @@ class Followers extends ImmutablePureComponent { } render () { - const { accountIds, hasMore, isAccount } = this.props; + const { accountIds, hasMore, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -101,6 +102,7 @@ class Followers extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index f03da0c94..493f86a66 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -33,6 +33,7 @@ class Following extends ImmutablePureComponent { accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -70,7 +71,7 @@ class Following extends ImmutablePureComponent { } render () { - const { accountIds, hasMore, isAccount } = this.props; + const { accountIds, hasMore, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -101,6 +102,7 @@ class Following extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index d39505f46..b64b4bf13 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -155,6 +155,7 @@ class HashtagTimeline extends React.PureComponent { timelineId={`hashtag:${id}`} onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js index defb1dcc1..b01c8cced 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.js +++ b/app/javascript/flavours/glitch/features/home_timeline/index.js @@ -117,6 +117,7 @@ class HomeTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} 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> }} />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js index 8c3d0af51..f4b926e3c 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.js +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -212,6 +212,7 @@ class ListTimeline extends React.PureComponent { timelineId={`list:${id}`} onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet.' />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js index 79bf2e601..8d1b9d3ff 100644 --- a/app/javascript/flavours/glitch/features/lists/index.js +++ b/app/javascript/flavours/glitch/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, lists } = this.props; + const { intl, lists, multiColumn } = this.props; if (!lists) { return ( @@ -69,6 +70,7 @@ class Lists extends ImmutablePureComponent { <ScrollableList scrollKey='lists' emptyMessage={emptyMessage} + 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/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js index 7c20ca9b9..e5a8010b4 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.js +++ b/app/javascript/flavours/glitch/features/mutes/index.js @@ -31,6 +31,7 @@ class Mutes extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -42,7 +43,7 @@ class Mutes extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, hasMore } = this.props; + const { intl, accountIds, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -62,6 +63,7 @@ class Mutes extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} hasMore={hasMore} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 99b2391c7..785a7dc51 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -226,6 +226,7 @@ class Notifications extends React.PureComponent { onScrollToTop={this.handleScrollToTop} onScroll={this.handleScroll} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} > {scrollableContent} </ScrollableList> diff --git a/app/javascript/flavours/glitch/features/pinned_statuses/index.js b/app/javascript/flavours/glitch/features/pinned_statuses/index.js index 8d406ddf4..b0db90c2c 100644 --- a/app/javascript/flavours/glitch/features/pinned_statuses/index.js +++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.js @@ -27,6 +27,7 @@ class PinnedStatuses extends ImmutablePureComponent { statusIds: ImmutablePropTypes.list.isRequired, intl: PropTypes.object.isRequired, hasMore: PropTypes.bool.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -42,7 +43,7 @@ class PinnedStatuses extends ImmutablePureComponent { } render () { - const { intl, statusIds, hasMore } = this.props; + const { intl, statusIds, hasMore, multiColumn } = this.props; return ( <Column icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}> @@ -51,6 +52,7 @@ class PinnedStatuses extends ImmutablePureComponent { statusIds={statusIds} scrollKey='pinned_statuses' hasMore={hasMore} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js index 4bcf3da9d..b64c634ac 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.js +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -124,6 +124,7 @@ class PublicTimeline extends React.PureComponent { trackScroll={!pinned} 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' />} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js index a8e9db7f5..808b25b9e 100644 --- a/app/javascript/flavours/glitch/features/reblogs/index.js +++ b/app/javascript/flavours/glitch/features/reblogs/index.js @@ -27,6 +27,7 @@ class Reblogs extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -51,7 +52,7 @@ class Reblogs extends ImmutablePureComponent { } render () { - const { intl, accountIds } = this.props; + const { intl, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -75,6 +76,7 @@ class Reblogs extends ImmutablePureComponent { <ScrollableList scrollKey='reblogs' emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index 117ce4c55..53334835d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -46,6 +46,28 @@ const MODAL_COMPONENTS = { 'PINNED_ACCOUNTS_EDITOR': PinnedAccountsEditor, }; +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 = { @@ -61,8 +83,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/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index c201cd93d..e5925a484 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -129,12 +129,25 @@ class SwitchingColumnsArea extends React.PureComponent { componentWillMount () { window.addEventListener('resize', this.handleResize, { passive: true }); + + if (this.state.mobile) { + 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) { + document.body.classList.toggle('layout-single-column', this.state.mobile); + document.body.classList.toggle('layout-multiple-columns', !this.state.mobile); + } } componentWillUnmount () { diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index 5a15830df..767fb023c 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -94,14 +94,6 @@ function main() { new Rellax('.parallax', { speed: -1 }); } - if (document.body.classList.contains('with-modals')) { - const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; - const scrollbarWidthStyle = document.createElement('style'); - scrollbarWidthStyle.id = 'scrollbar-width'; - document.head.appendChild(scrollbarWidthStyle); - scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0); - } - delegate(document, '.custom-emoji', 'mouseover', getEmojiAnimationHandler('data-original')); delegate(document, '.custom-emoji', 'mouseout', getEmojiAnimationHandler('data-static')); diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss index 64e543b78..ed02118f0 100644 --- a/app/javascript/flavours/glitch/styles/basics.scss +++ b/app/javascript/flavours/glitch/styles/basics.scss @@ -7,7 +7,7 @@ body { font-family: $font-sans-serif, sans-serif; - background: darken($ui-base-color, 8%); + background: darken($ui-base-color, 7%); font-size: 13px; line-height: 18px; font-weight: 400; @@ -34,11 +34,19 @@ body { } &.app-body { - position: absolute; - width: 100%; - height: 100%; padding: 0; - background: $ui-base-color; + + &.layout-single-column { + height: auto; + min-height: 100%; + overflow-y: scroll; + } + + &.layout-multiple-columns { + position: absolute; + width: 100%; + height: 100%; + } &.with-modals--active { overflow-y: hidden; @@ -55,7 +63,6 @@ body { &--active { overflow-y: hidden; - margin-right: 13px; } } @@ -124,7 +131,6 @@ button { & > div { display: flex; width: 100%; - height: 100%; align-items: center; justify-content: center; outline: 0 !important; diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index 7f3c21163..32f587ca0 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -17,6 +17,7 @@ justify-content: center; width: 100%; height: 100%; + min-height: 100vh; &__pane { height: 100%; @@ -30,6 +31,7 @@ } &__inner { + position: fixed; width: 285px; pointer-events: auto; height: 100%; @@ -83,7 +85,6 @@ flex-direction: column; width: 100%; height: 100%; - background: darken($ui-base-color, 7%); } .column { diff --git a/app/javascript/flavours/glitch/styles/components/single_column.scss b/app/javascript/flavours/glitch/styles/components/single_column.scss index 1d8055fe5..fdee67ed1 100644 --- a/app/javascript/flavours/glitch/styles/components/single_column.scss +++ b/app/javascript/flavours/glitch/styles/components/single_column.scss @@ -127,6 +127,10 @@ top: 15px; } + .scrollable { + overflow: visible; + } + @media screen and (min-width: $no-gap-breakpoint) { padding: 10px 0; } |