parent
							
								
									4fa6472523
								
							
						
					
					
						commit
						aa22b38fdb
					
				
					 25 changed files with 162 additions and 42 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue