diff --git a/src/common/Slider/Slider.js b/src/common/Slider/Slider.js index e700d040a..c877071c3 100644 --- a/src/common/Slider/Slider.js +++ b/src/common/Slider/Slider.js @@ -4,6 +4,12 @@ import classnames from 'classnames'; import styles from './styles'; class Slider extends Component { + componentWillReceiveProps(nextProps) { + if (this.props.orientation !== nextProps.orientation) { + console.warn('changing orientation property at runtime is not supported'); + } + } + shouldComponentUpdate(nextProps, nextState) { return nextProps.value !== this.props.value || nextProps.minValue !== this.props.minValue || @@ -30,14 +36,17 @@ class Slider extends Component { } } - calculateSlidingValue = (mouseX, sliderElement) => { - const { x: sliderX, width: sliderWidth } = sliderElement.getBoundingClientRect(); - const thumbX = Math.min(Math.max(mouseX - sliderX, 0), sliderWidth); - const slidingValue = (thumbX / sliderWidth) * (this.props.maxValue - this.props.minValue) + this.props.minValue; + calculateSlidingValue = ({ mouseX, mouseY, sliderElement }) => { + const { x: sliderX, y: sliderY, width: sliderWidth, height: sliderHeight } = sliderElement.getBoundingClientRect(); + const sliderStart = this.props.orientation === 'horizontal' ? sliderX : sliderY; + const sliderLength = this.props.orientation === 'horizontal' ? sliderWidth : sliderHeight; + const mouseStart = this.props.orientation === 'horizontal' ? mouseX : mouseY; + const thumbStart = Math.min(Math.max(mouseStart - sliderStart, 0), sliderLength); + const slidingValue = (thumbStart / sliderLength) * (this.props.maxValue - this.props.minValue) + this.props.minValue; return Math.floor(slidingValue); } - onStartSliding = ({ currentTarget: sliderElement, clientX: mouseX, button }) => { + onStartSliding = ({ currentTarget: sliderElement, clientX: mouseX, clientY: mouseY, button }) => { if (button !== 0) { return; } @@ -54,12 +63,14 @@ class Slider extends Component { releaseThumb(); this.onSlidingAborted(); }; - const onMouseUp = ({ clientX: mouseX }) => { + const onMouseUp = ({ clientX: mouseX, clientY: mouseY }) => { releaseThumb(); - this.onSlidingCompleted(this.calculateSlidingValue(mouseX, sliderElement)); + const slidingValue = this.calculateSlidingValue({ mouseX, mouseY, sliderElement }); + this.onSlidingCompleted(slidingValue); }; - const onMouseMove = ({ clientX: mouseX }) => { - this.onSliding(this.calculateSlidingValue(mouseX, sliderElement)); + const onMouseMove = ({ clientX: mouseX, clientY: mouseY }) => { + const slidingValue = this.calculateSlidingValue({ mouseX, mouseY, sliderElement }); + this.onSliding(slidingValue); }; window.addEventListener('blur', onBlur); @@ -68,17 +79,18 @@ class Slider extends Component { document.body.style['pointer-events'] = 'none'; document.documentElement.style.cursor = 'pointer'; sliderElement.classList.add(styles['active']); - onMouseMove({ clientX: mouseX }); + onMouseMove({ clientX: mouseX, clientY: mouseY }); } render() { - const thumbLeft = (this.props.value - this.props.minValue) / (this.props.maxValue - this.props.minValue); + const thumbStartProp = this.props.orientation === 'horizontal' ? 'left' : 'top'; + const thumbStart = (this.props.value - this.props.minValue) / (this.props.maxValue - this.props.minValue); return ( -
+
); @@ -91,6 +103,7 @@ Slider.propTypes = { value: PropTypes.number.isRequired, minValue: PropTypes.number.isRequired, maxValue: PropTypes.number.isRequired, + orientation: PropTypes.oneOf(['horizontal', 'vertical']).isRequired, onSliding: PropTypes.func, onSlidingCompleted: PropTypes.func, onSlidingAborted: PropTypes.func @@ -98,7 +111,8 @@ Slider.propTypes = { Slider.defaultProps = { value: 0, minValue: 0, - maxValue: 100 + maxValue: 100, + orientation: 'horizontal' }; export default Slider; diff --git a/src/common/Slider/styles.less b/src/common/Slider/styles.less index cc84039df..ef9638406 100644 --- a/src/common/Slider/styles.less +++ b/src/common/Slider/styles.less @@ -6,10 +6,6 @@ .line { position: absolute; - left: 0; - right: 0; - top: 40%; - bottom: 40%; z-index: 1; background-color: @colorprim; } @@ -19,8 +15,6 @@ z-index: 2; border-radius: 50%; background-color: @colormedium; - transform: translateX(-50%); - transition-property: left; transition-duration: 0.06s; &:hover { @@ -28,6 +22,34 @@ } } + &.horizontal { + .line { + left: 0; + right: 0; + top: 40%; + bottom: 40%; + } + + .thumb { + transform: translateX(-50%); + transition-property: left; + } + } + + &.vertical { + .line { + left: 40%; + right: 40%; + top: 0; + bottom: 0; + } + + .thumb { + transform: translateY(-50%); + transition-property: top; + } + } + &.active { .thumb { background-color: @colorprimlight; diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 27dc9b3c5..3d2859693 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -59,18 +59,19 @@ class ControlBar extends Component { return `${('0' + hours).slice(-2)}:${('0' + minutes).slice(-2)}:${('0' + seconds).slice(-2)}`; } - renderSeekBar() { + renderSeekSlider() { if (this.props.time === null || this.props.duration === null) { return null; } return ( + +
+ +
+
+ ); + } + render() { return (
- {this.renderSeekBar()} + {this.renderSeekSlider()}
{this.renderPlayPauseButton()}
{this.renderTimeLabel()} +
+ {this.renderVolumeButton()}
); diff --git a/src/routes/Player/ControlBar/styles.less b/src/routes/Player/ControlBar/styles.less index 4d930c3c6..3ff74e587 100644 --- a/src/routes/Player/ControlBar/styles.less +++ b/src/routes/Player/ControlBar/styles.less @@ -1,8 +1,8 @@ @import 'stremio-colors'; @control-bar-height: 84px; -@seek-bar-height: 26px; -@buttons-bar-height: (@control-bar-height - @seek-bar-height); +@seek-slider-height: 26px; +@buttons-bar-height: (@control-bar-height - @seek-slider-height); .control-bar-container { height: @control-bar-height; @@ -13,13 +13,14 @@ padding-left: 2%; padding-right: 2%; - .seek-bar { + .seek-slider { width: 100%; - height: @seek-bar-height; + height: @seek-slider-height; + z-index: 1; - .thumb { - width: @seek-bar-height; - height: @seek-bar-height; + .seek-thumb { + width: @seek-slider-height; + height: @seek-slider-height; } } @@ -29,6 +30,7 @@ display: flex; flex-direction: row; align-items: center; + z-index: 2; .button { height: @buttons-bar-height; @@ -39,8 +41,8 @@ cursor: pointer; .icon { - width: 64%; - height: 64%; + width: 60%; + height: 60%; fill: @colorwhite80; } @@ -49,6 +51,37 @@ fill: @colorwhite; } } + + &.volume-button { + position: relative; + + .volume-slider-container { + display: none; + justify-content: center; + width: 100%; + height: 300%; + position: absolute; + bottom: 100%; + + .volume-slider { + width: round((@buttons-bar-height * 0.4)); + height: 100%; + + .volume-thumb { + width: round((@buttons-bar-height * 0.4)); + height: round((@buttons-bar-height * 0.4)); + } + } + } + + &:hover { + .volume-slider-container { + display: flex; + + + } + } + } } .separator { @@ -63,5 +96,9 @@ color: @colorwhite; font-size: 16px; } + + .spacing { + flex: 1 + } } } \ No newline at end of file