@@ -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.clearMouseIdleTimer(); | |||
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; | |||
} | |||
@@ -135,15 +143,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); | |||
} | |||
@@ -153,8 +173,8 @@ export default class ScrollableList extends PureComponent { | |||
React.Children.count(prevProps.children) < React.Children.count(this.props.children) && | |||
this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); | |||
if (someItemInserted && (this.node.scrollTop > 0 || this.mouseMovedRecently)) { | |||
return this.node.scrollHeight - this.node.scrollTop; | |||
if (someItemInserted && (this.getScrollTop() > 0 || this.mouseMovedRecently)) { | |||
return this.getScrollHeight() - this.getScrollTop(); | |||
} else { | |||
return null; | |||
} | |||
@@ -164,7 +184,7 @@ export default class ScrollableList extends PureComponent { | |||
// 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.setScrollTop(this.node.scrollHeight - snapshot); | |||
this.setScrollTop(this.getScrollHeight() - snapshot); | |||
} | |||
} | |||
@@ -197,13 +217,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) { | |||
@@ -8,6 +8,7 @@ import Video from '../features/video'; | |||
import Card from '../features/status/components/card'; | |||
import Poll from 'mastodon/components/poll'; | |||
import ModalRoot from '../components/modal_root'; | |||
import { getScrollbarWidth } from '../features/ui/components/modal_root'; | |||
import MediaModal from '../features/ui/components/media_modal'; | |||
import { List as ImmutableList, fromJS } from 'immutable'; | |||
@@ -31,6 +32,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 }); | |||
} | |||
@@ -38,11 +41,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 }); | |||
} | |||
@@ -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> | |||
); | |||
@@ -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} /> | |||
@@ -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> | |||
); | |||
@@ -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} /> | |||
@@ -95,6 +95,7 @@ class Favourites extends ImmutablePureComponent { | |||
onLoadMore={this.handleLoadMore} | |||
shouldUpdateScroll={shouldUpdateScroll} | |||
emptyMessage={emptyMessage} | |||
bindToDocument={!multiColumn} | |||
/> | |||
</Column> | |||
); | |||
@@ -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} /> | |||
@@ -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} /> | |||
@@ -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} /> | |||
@@ -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} /> | |||
@@ -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> | |||
); | |||
@@ -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> | |||
); | |||
@@ -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> | |||
); | |||
@@ -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')} /> | |||
@@ -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} /> | |||
@@ -191,6 +191,7 @@ class Notifications extends React.PureComponent { | |||
onScrollToTop={this.handleScrollToTop} | |||
onScroll={this.handleScroll} | |||
shouldUpdateScroll={shouldUpdateScroll} | |||
bindToDocument={!multiColumn} | |||
> | |||
{scrollableContent} | |||
</ScrollableList> | |||
@@ -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> | |||
); | |||
@@ -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> | |||
); | |||
@@ -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} /> | |||
@@ -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; | |||
} | |||
} | |||
@@ -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 () { | |||
@@ -108,14 +108,6 @@ function main() { | |||
if (parallaxComponents.length > 0 ) { | |||
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, '.webapp-btn', 'click', ({ target, button }) => { | |||
@@ -8,7 +8,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; | |||
@@ -35,11 +35,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; | |||
@@ -56,7 +64,6 @@ body { | |||
&--active { | |||
overflow-y: hidden; | |||
margin-right: 13px; | |||
} | |||
} | |||
@@ -134,9 +141,22 @@ button { | |||
& > div { | |||
display: flex; | |||
width: 100%; | |||
height: 100%; | |||
align-items: center; | |||
justify-content: center; | |||
outline: 0 !important; | |||
} | |||
} | |||
.layout-single-column .app-holder { | |||
&, | |||
& > div { | |||
min-height: 100%; | |||
} | |||
} | |||
.layout-multiple-columns .app-holder { | |||
&, | |||
& > div { | |||
height: 100%; | |||
} | |||
} |
@@ -1804,6 +1804,7 @@ a.account__display-name { | |||
justify-content: center; | |||
width: 100%; | |||
height: 100%; | |||
min-height: 100vh; | |||
&__pane { | |||
height: 100%; | |||
@@ -1817,6 +1818,7 @@ a.account__display-name { | |||
} | |||
&__inner { | |||
position: fixed; | |||
width: 285px; | |||
pointer-events: auto; | |||
height: 100%; | |||
@@ -1871,7 +1873,6 @@ a.account__display-name { | |||
flex-direction: column; | |||
width: 100%; | |||
height: 100%; | |||
background: darken($ui-base-color, 7%); | |||
} | |||
.drawer { | |||
@@ -2012,6 +2013,10 @@ a.account__display-name { | |||
top: 15px; | |||
} | |||
.scrollable { | |||
overflow: visible; | |||
} | |||
@media screen and (min-width: $no-gap-breakpoint) { | |||
padding: 10px 0; | |||
} | |||