diff --git a/app/soapbox/components/timeline_queue_button_header.js b/app/soapbox/components/timeline_queue_button_header.js index 6a85e2130..bb02b0193 100644 --- a/app/soapbox/components/timeline_queue_button_header.js +++ b/app/soapbox/components/timeline_queue_button_header.js @@ -1,8 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { injectIntl } from 'react-intl'; +import { throttle } from 'lodash'; import classNames from 'classnames'; -import SvgIcon from 'soapbox/components/svg_icon'; +import Icon from 'soapbox/components/icon'; export default @injectIntl class TimelineQueueButtonHeader extends React.PureComponent { @@ -11,25 +12,68 @@ class TimelineQueueButtonHeader extends React.PureComponent { onClick: PropTypes.func.isRequired, count: PropTypes.number, message: PropTypes.object.isRequired, + threshold: PropTypes.number, intl: PropTypes.object.isRequired, }; static defaultProps = { count: 0, + threshold: 400, }; + state = { + scrolled: false, + } + + componentDidMount() { + this.window = window; + this.documentElement = document.scrollingElement || document.documentElement; + + this.attachScrollListener(); + } + + componentWillUnmount() { + this.detachScrollListener(); + } + + attachScrollListener() { + this.window.addEventListener('scroll', this.handleScroll); + } + + detachScrollListener() { + this.window.removeEventListener('scroll', this.handleScroll); + } + + handleScroll = throttle(() => { + const { scrollTop } = (document.scrollingElement || document.documentElement); + const { threshold } = this.props; + + if (scrollTop > threshold) { + this.setState({ scrolled: true }); + } else { + this.setState({ scrolled: false }); + } + }, 150, { trailing: true }); + render() { const { count, message, onClick, intl } = this.props; + const { scrolled } = this.state; + + const visible = count > 0 && scrolled; const classes = classNames('timeline-queue-header', { - 'hidden': (count <= 0), + 'hidden': !visible, }); return (
- - {(count > 0) && intl.formatMessage(message, { count })} + + {(count > 0) && ( +
+ {intl.formatMessage(message, { count })} +
+ )}
); diff --git a/app/styles/components/remote-timeline.scss b/app/styles/components/remote-timeline.scss index e059d7af7..803c315e8 100644 --- a/app/styles/components/remote-timeline.scss +++ b/app/styles/components/remote-timeline.scss @@ -29,9 +29,11 @@ } .pinned-hosts-picker { - margin-left: 10px; + padding: 10px 0 0 10px; display: inline-flex; flex-wrap: wrap; + background: var(--foreground-color); + border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2); .pinned-host { margin-right: 10px; diff --git a/app/styles/components/timeline-queue-header.scss b/app/styles/components/timeline-queue-header.scss index 405c7c5d8..93cf73d6f 100644 --- a/app/styles/components/timeline-queue-header.scss +++ b/app/styles/components/timeline-queue-header.scss @@ -1,35 +1,35 @@ .timeline-queue-header { display: flex; + align-self: center; align-items: center; justify-content: space-evenly; - max-height: 30px; - position: sticky; + height: 30px; + position: fixed; top: 60px; margin: 0 auto; - margin-bottom: 8px; background-color: var(--brand-color); color: #fff; - border-bottom: 1px solid; - border-top: 1px solid; - border-color: var(--brand-color--faint); border-radius: 100px; - transition: max-height 150ms ease; + transition: 150ms ease; overflow: hidden; - opacity: 1; - left: 0; - right: 0; padding: 0 10px; z-index: 500; + .sub-navigation ~ & { + top: calc(60px + 41px); + } + .svg-icon { margin-right: 5px; } &.hidden { - max-height: 0; - opacity: 0; - margin: 0; - border: 0; + transform: scaleY(0); + pointer-events: none; + + .timeline-queue-header__label { + opacity: 0; + } } &__btn { @@ -46,4 +46,8 @@ height: 46px; } } + + &__label { + transition: 150ms ease; + } }