From 9e2e623ebe25b8e58a6c8f4bf947015481f10c66 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 19 Jul 2019 09:25:22 +0200 Subject: [Glitch] Change single-column mode to scroll the whole page Port aa22b38fdbc1842549b6cbc0e0d948f85a71b92a to glitch-soc Signed-off-by: Thibaut Girka --- .../flavours/glitch/components/scrollable_list.js | 60 +++++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js index 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) { -- cgit From fdadd520b184fbf8e0b99c25a19ef7f25ca651f6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 1 Aug 2019 12:26:58 +0200 Subject: [Glitch] Fix column header scrolling with the page Port 706a48ee1f2075ffb35ad4ad9cfc2f23fffbffcb to glitch-soc Signed-off-by: Thibaut Girka --- .../flavours/glitch/components/column_header.js | 12 ++++++++++-- .../flavours/glitch/features/status/index.js | 6 ++++-- .../glitch/features/ui/components/column_loading.js | 2 +- .../glitch/features/ui/components/tabs_bar.js | 10 +++++++--- app/javascript/flavours/glitch/styles/basics.scss | 2 +- .../flavours/glitch/styles/components/columns.scss | 20 ++++++++++++++++++++ .../flavours/glitch/styles/components/index.scss | 3 --- .../glitch/styles/components/single_column.scss | 5 ++--- 8 files changed, 45 insertions(+), 15 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/column_header.js b/app/javascript/flavours/glitch/components/column_header.js index 3a064e90a..dd70d3c31 100644 --- a/app/javascript/flavours/glitch/components/column_header.js +++ b/app/javascript/flavours/glitch/components/column_header.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { createPortal } from 'react-dom'; import classNames from 'classnames'; import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -36,6 +37,7 @@ class ColumnHeader extends React.PureComponent { onEnterCleaningMode: PropTypes.func, children: PropTypes.node, pinned: PropTypes.bool, + placeholder: PropTypes.bool, onPin: PropTypes.func, onMove: PropTypes.func, onClick: PropTypes.func, @@ -104,7 +106,7 @@ class ColumnHeader extends React.PureComponent { } render () { - const { intl, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, notifCleaning, notifCleaningActive } = this.props; + const { intl, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, notifCleaning, notifCleaningActive, placeholder } = this.props; const { collapsed, animating, animatingNCD } = this.state; let title = this.props.title; @@ -185,7 +187,7 @@ class ColumnHeader extends React.PureComponent { const hasTitle = icon && title; - return ( + const component = (

{hasTitle && ( @@ -229,6 +231,12 @@ class ColumnHeader extends React.PureComponent {

); + + if (multiColumn || placeholder) { + return component; + } else { + return createPortal(component, document.getElementById('tabs-bar__portal')); + } } } diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index dd17823ad..ba5025b19 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -155,6 +155,7 @@ class Status extends ImmutablePureComponent { descendantsIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, askReplyConfirmation: PropTypes.bool, + multiColumn: PropTypes.bool, domain: PropTypes.string.isRequired, }; @@ -497,13 +498,13 @@ class Status extends ImmutablePureComponent { render () { let ancestors, descendants; const { setExpansion } = this; - const { status, settings, ancestorsIds, descendantsIds, intl, domain } = this.props; + const { status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn } = this.props; const { fullscreen, isExpanded } = this.state; if (status === null) { return ( - + ); @@ -537,6 +538,7 @@ class Status extends ImmutablePureComponent { title={intl.formatMessage(messages.tootHeading)} onClick={this.handleHeaderClick} showBackButton + multiColumn={multiColumn} extraButton={( )} diff --git a/app/javascript/flavours/glitch/features/ui/components/column_loading.js b/app/javascript/flavours/glitch/features/ui/components/column_loading.js index ba2d0824e..22c00c915 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_loading.js +++ b/app/javascript/flavours/glitch/features/ui/components/column_loading.js @@ -21,7 +21,7 @@ export default class ColumnLoading extends ImmutablePureComponent { let { title, icon } = this.props; return ( - +
); diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js index 90e645a82..a67405215 100644 --- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js +++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js @@ -73,9 +73,13 @@ class TabsBar extends React.PureComponent { const { intl: { formatMessage } } = this.props; return ( - +
+ + +
+
); } diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss index ed02118f0..77631097a 100644 --- a/app/javascript/flavours/glitch/styles/basics.scss +++ b/app/javascript/flavours/glitch/styles/basics.scss @@ -38,7 +38,7 @@ body { &.layout-single-column { height: auto; - min-height: 100%; + min-height: 100vh; overflow-y: scroll; } diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index 32f587ca0..1ff4ac554 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -52,6 +52,26 @@ } } +.tabs-bar__wrapper { + background: darken($ui-base-color, 8%); + position: sticky; + top: 0; + z-index: 2; + padding-top: 0; + + @media screen and (min-width: $no-gap-breakpoint) { + padding-top: 10px; + } + + .tabs-bar { + margin-bottom: 0; + + @media screen and (min-width: $no-gap-breakpoint) { + margin-bottom: 10px; + } + } +} + .react-swipeable-view-container { &, .columns-area, diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 743abfd2a..6f0d4c0be 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -639,9 +639,6 @@ background: lighten($ui-base-color, 8%); flex: 0 0 auto; overflow-y: auto; - position: sticky; - top: 0; - z-index: 3; } .tabs-bar__link { diff --git a/app/javascript/flavours/glitch/styles/components/single_column.scss b/app/javascript/flavours/glitch/styles/components/single_column.scss index fd99ffaa2..edf705b5f 100644 --- a/app/javascript/flavours/glitch/styles/components/single_column.scss +++ b/app/javascript/flavours/glitch/styles/components/single_column.scss @@ -137,6 +137,7 @@ @media screen and (min-width: $no-gap-breakpoint) { padding: 10px 0; + padding-top: 0; } @media screen and (min-width: 630px) { @@ -225,13 +226,11 @@ @media screen and (min-width: $no-gap-breakpoint) { .tabs-bar { - margin: 10px auto; - margin-bottom: 0; width: 100%; } .react-swipeable-view-container .columns-area--mobile { - height: calc(100% - 20px) !important; + height: calc(100% - 10px) !important; } .getting-started__wrapper, -- cgit From 90bdbddbfe44be77de1d2cd88bb7f469f5d6132f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 1 Aug 2019 19:17:17 +0200 Subject: [Glitch] Fix scroll to top in single column UI Port 2dee293c4c98486d387105224023fad02b8b0d96 to glitch-soc Signed-off-by: Thibaut Girka --- app/javascript/flavours/glitch/components/column.js | 15 ++++++++++++--- .../flavours/glitch/components/column_back_button.js | 15 ++++++++++++++- .../features/account/components/profile_column_header.js | 4 +++- .../flavours/glitch/features/account_gallery/index.js | 5 +++-- .../flavours/glitch/features/account_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/blocks/index.js | 2 +- .../flavours/glitch/features/community_timeline/index.js | 2 +- .../flavours/glitch/features/direct_timeline/index.js | 2 +- .../flavours/glitch/features/domain_blocks/index.js | 2 +- .../flavours/glitch/features/favourited_statuses/index.js | 2 +- .../flavours/glitch/features/favourites/index.js | 1 + .../flavours/glitch/features/follow_requests/index.js | 2 +- .../flavours/glitch/features/followers/index.js | 2 +- .../flavours/glitch/features/following/index.js | 2 +- .../flavours/glitch/features/getting_started/index.js | 2 +- .../flavours/glitch/features/hashtag_timeline/index.js | 1 + .../flavours/glitch/features/home_timeline/index.js | 2 +- .../flavours/glitch/features/keyboard_shortcuts/index.js | 4 ++-- .../flavours/glitch/features/list_timeline/index.js | 1 + app/javascript/flavours/glitch/features/lists/index.js | 2 +- app/javascript/flavours/glitch/features/mutes/index.js | 2 +- .../flavours/glitch/features/notifications/index.js | 1 + .../flavours/glitch/features/pinned_statuses/index.js | 2 +- .../flavours/glitch/features/public_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/reblogs/index.js | 1 + app/javascript/flavours/glitch/features/status/index.js | 2 +- .../flavours/glitch/styles/components/columns.scss | 2 ++ 27 files changed, 57 insertions(+), 25 deletions(-) (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/column.js b/app/javascript/flavours/glitch/components/column.js index dc87818a5..5819d5362 100644 --- a/app/javascript/flavours/glitch/components/column.js +++ b/app/javascript/flavours/glitch/components/column.js @@ -10,10 +10,11 @@ export default class Column extends React.PureComponent { extraClasses: PropTypes.string, name: PropTypes.string, label: PropTypes.string, + bindToDocument: PropTypes.bool, }; scrollTop () { - const scrollable = this.node.querySelector('.scrollable'); + const scrollable = this.props.bindToDocument ? document.scrollingElement : this.node.querySelector('.scrollable'); if (!scrollable) { return; @@ -35,11 +36,19 @@ export default class Column extends React.PureComponent { } componentDidMount () { - this.node.addEventListener('wheel', this.handleWheel, detectPassiveEvents.hasSupport ? { passive: true } : false); + if (this.props.bindToDocument) { + document.addEventListener('wheel', this.handleWheel, detectPassiveEvents.hasSupport ? { passive: true } : false); + } else { + this.node.addEventListener('wheel', this.handleWheel, detectPassiveEvents.hasSupport ? { passive: true } : false); + } } componentWillUnmount () { - this.node.removeEventListener('wheel', this.handleWheel); + if (this.props.bindToDocument) { + document.removeEventListener('wheel', this.handleWheel); + } else { + this.node.removeEventListener('wheel', this.handleWheel); + } } render () { diff --git a/app/javascript/flavours/glitch/components/column_back_button.js b/app/javascript/flavours/glitch/components/column_back_button.js index a0260e5af..8326cbb79 100644 --- a/app/javascript/flavours/glitch/components/column_back_button.js +++ b/app/javascript/flavours/glitch/components/column_back_button.js @@ -2,6 +2,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import Icon from 'flavours/glitch/components/icon'; +import { createPortal } from 'react-dom'; export default class ColumnBackButton extends React.PureComponent { @@ -9,6 +10,10 @@ export default class ColumnBackButton extends React.PureComponent { router: PropTypes.object, }; + static propTypes = { + multiColumn: PropTypes.bool, + }; + handleClick = (event) => { // if history is exhausted, or we would leave mastodon, just go to root. if (window.history.state) { @@ -24,12 +29,20 @@ export default class ColumnBackButton extends React.PureComponent { } render () { - return ( + const { multiColumn } = this.props; + + const component = ( ); + + if (multiColumn) { + return component; + } else { + return createPortal(component, document.getElementById('tabs-bar__portal')); + } } } diff --git a/app/javascript/flavours/glitch/features/account/components/profile_column_header.js b/app/javascript/flavours/glitch/features/account/components/profile_column_header.js index b6d373a2c..17c08e375 100644 --- a/app/javascript/flavours/glitch/features/account/components/profile_column_header.js +++ b/app/javascript/flavours/glitch/features/account/components/profile_column_header.js @@ -12,11 +12,12 @@ class ProfileColumnHeader extends React.PureComponent { static propTypes = { onClick: PropTypes.func, + multiColumn: PropTypes.bool, intl: PropTypes.object.isRequired, }; render() { - const { onClick, intl } = this.props; + const { onClick, intl, multiColumn } = this.props; return ( ); } diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index ff39764bb..f5fe6c930 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -55,6 +55,7 @@ class AccountGallery extends ImmutablePureComponent { isLoading: PropTypes.bool, hasMore: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; state = { @@ -130,7 +131,7 @@ class AccountGallery extends ImmutablePureComponent { } render () { - const { attachments, isLoading, hasMore, isAccount } = this.props; + const { attachments, isLoading, hasMore, isAccount, multiColumn } = this.props; const { width } = this.state; if (!isAccount) { @@ -157,7 +158,7 @@ class AccountGallery extends ImmutablePureComponent { return ( - +
diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index a6ed4564c..1f02c1be5 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -97,7 +97,7 @@ class AccountTimeline extends ImmutablePureComponent { return ( - + } diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js index ae0cdf2fe..9eb6fe02e 100644 --- a/app/javascript/flavours/glitch/features/blocks/index.js +++ b/app/javascript/flavours/glitch/features/blocks/index.js @@ -56,7 +56,7 @@ class Blocks extends ImmutablePureComponent { const emptyMessage = ; return ( - + + + ; return ( - + ; return ( - + ; return ( - + - + - + +
{!multiColumn && } diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index b64b4bf13..16dd80c4f 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -145,6 +145,7 @@ class HashtagTimeline extends React.PureComponent { pinned={pinned} multiColumn={multiColumn} showBackButton + bindToDocument={!multiColumn} > {columnId && } diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js index b01c8cced..9b71a4404 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.js +++ b/app/javascript/flavours/glitch/features/home_timeline/index.js @@ -97,7 +97,7 @@ class HomeTimeline extends React.PureComponent { const pinned = !!columnId; return ( - + +
diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js index f4b926e3c..908a65597 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.js +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -174,6 +174,7 @@ class ListTimeline extends React.PureComponent { onClick={this.handleHeaderClick} pinned={pinned} multiColumn={multiColumn} + bindToDocument={!multiColumn} >
); - } else if (multiColumn) { + } else if (multiColumn && this.props.onPin) { pinButton = ; } @@ -181,7 +181,7 @@ class ColumnHeader extends React.PureComponent { collapsedContent.push(pinButton); } - if (children || multiColumn) { + if (children || (multiColumn && this.props.onPin)) { collapseButton = ; } -- cgit