From 0f226853f5466b8c4d71075b6bf03242512a19b0 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 12 Nov 2018 12:57:21 +0100 Subject: [PATCH] add scroll indicator gradients to top and bottom of room sub list --- res/css/structures/_AutoHideScrollbar.scss | 28 ++++++--- res/css/structures/_RoomSubList.scss | 30 +++++++++ .../structures/AutoHideScrollbar.js | 3 + .../structures/IndicatorScrollbar.js | 62 +++++++++++++++++++ src/components/structures/RoomSubList.js | 6 +- 5 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 src/components/structures/IndicatorScrollbar.js diff --git a/res/css/structures/_AutoHideScrollbar.scss b/res/css/structures/_AutoHideScrollbar.scss index 70dbbe8d07..60aea7ce8f 100644 --- a/res/css/structures/_AutoHideScrollbar.scss +++ b/res/css/structures/_AutoHideScrollbar.scss @@ -41,14 +41,26 @@ is overflowing. This is what Firefox ends up using. Overflow is detected in javascript, and adds the mx_AutoHideScrollbar_overflow class to the container. This only works in Firefox, which should be fine as this fallback is only needed there. */ -body.mx_scrollbar_nooverlay .mx_AutoHideScrollbar { - overflow-y: hidden; -} +body.mx_scrollbar_nooverlay { + .mx_AutoHideScrollbar { + overflow-y: hidden; + } -body.mx_scrollbar_nooverlay .mx_AutoHideScrollbar:hover { - overflow-y: auto; -} + .mx_AutoHideScrollbar:hover { + overflow-y: auto; + } -body.mx_scrollbar_nooverlay .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow > .mx_AutoHideScrollbar_offset { - margin-right: calc(-1 * var(--scrollbar-width)); + /* + offset scrollbar width with negative margin-right + + include before and after psuedo-elements here so they can + be used to do something interesting like scroll-indicating + gradients (see IndicatorScrollBar) + */ + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow > .mx_AutoHideScrollbar_offset, + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::before, + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::after + { + margin-right: calc(-1 * var(--scrollbar-width)); + } } diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 142a43af95..c156f1f07e 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -110,6 +110,36 @@ limitations under the License. padding: 0 8px; } +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_topOverflow::before, +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_bottomOverflow::after { + position: sticky; + left: 0; + right: 0; + height: 40px; + content: ""; + display: block; + z-index: 100; + pointer-events: none; +} + + +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_topOverflow > .mx_AutoHideScrollbar_offset { + margin-top: -40px; +} +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_bottomOverflow > .mx_AutoHideScrollbar_offset { + margin-bottom: -40px; +} + +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_topOverflow::before { + top: 0; + background: linear-gradient($secondary-accent-color, transparent); +} + +.mx_RoomSubList_scroll.mx_IndicatorScrollbar_bottomOverflow::after { + bottom: 0; + background: linear-gradient(transparent, $secondary-accent-color); +} + .collapsed { .mx_RoomSubList_scroll { diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index a462b2bf14..a328d478bc 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -97,6 +97,9 @@ export default class AutoHideScrollbar extends React.Component { this.onUnderflow(); } } + if (this.props.wrappedRef) { + this.props.wrappedRef(ref); + } } componentWillUnmount() { diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js new file mode 100644 index 0000000000..247131cfab --- /dev/null +++ b/src/components/structures/IndicatorScrollbar.js @@ -0,0 +1,62 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import AutoHideScrollbar from "./AutoHideScrollbar"; + +export default class IndicatorScrollbar extends React.Component { + constructor(props) { + super(props); + this._collectScroller = this._collectScroller.bind(this); + this.checkOverflow = this.checkOverflow.bind(this); + } + + _collectScroller(scroller) { + if (scroller && !this._scroller) { + this._scroller = scroller; + this._scroller.addEventListener("scroll", this.checkOverflow); + this.checkOverflow(); + } + } + + checkOverflow() { + const hasTopOverflow = this._scroller.scrollTop > 0; + const hasBottomOverflow = this._scroller.scrollHeight > + (this._scroller.scrollTop + this._scroller.clientHeight); + if (hasTopOverflow) { + this._scroller.classList.add("mx_IndicatorScrollbar_topOverflow"); + } else { + this._scroller.classList.remove("mx_IndicatorScrollbar_topOverflow"); + } + if (hasBottomOverflow) { + this._scroller.classList.add("mx_IndicatorScrollbar_bottomOverflow"); + } else { + this._scroller.classList.remove("mx_IndicatorScrollbar_bottomOverflow"); + } + } + + componentWillUnmount() { + if (this._scroller) { + this._scroller.removeEventListener("scroll", this.checkOverflow); + } + } + + render() { + return ( + { this.props.children } + ); + } +} diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 0bebc50da6..6399fd80d9 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -23,7 +23,7 @@ import dis from '../../dispatcher'; import Unread from '../../Unread'; import * as RoomNotifs from '../../RoomNotifs'; import * as FormattingUtils from '../../utils/FormattingUtils'; -import AutoHideScrollbar from './AutoHideScrollbar'; +import IndicatorScrollbar from './IndicatorScrollbar'; import { KeyCode } from '../../Keyboard'; import { Group } from 'matrix-js-sdk'; import PropTypes from 'prop-types'; @@ -333,9 +333,9 @@ const RoomSubList = React.createClass({ tiles.push(...this.props.extraTiles); return
{this._getHeaderJsx()} - + { tiles } - +
; } } else {