@@ -4,16 +4,42 @@ const ExtendedVideoPlayer = React.createClass({ | |||
propTypes: { | |||
src: React.PropTypes.string.isRequired, | |||
time: React.PropTypes.number, | |||
controls: React.PropTypes.bool.isRequired, | |||
muted: React.PropTypes.bool.isRequired | |||
}, | |||
mixins: [PureRenderMixin], | |||
handleLoadedData () { | |||
if (this.props.time) { | |||
this.video.currentTime = this.props.time; | |||
} | |||
}, | |||
componentDidMount () { | |||
this.video.addEventListener('loadeddata', this.handleLoadedData); | |||
}, | |||
componentWillUnmount () { | |||
this.video.removeEventListener('loadeddata', this.handleLoadedData); | |||
}, | |||
setRef (c) { | |||
this.video = c; | |||
}, | |||
render () { | |||
return ( | |||
<div> | |||
<video src={this.props.src} autoPlay muted={this.props.muted} controls={this.props.controls} loop /> | |||
<div className='extended-video-player'> | |||
<video | |||
ref={this.setRef} | |||
src={this.props.src} | |||
autoPlay | |||
muted={this.props.muted} | |||
controls={this.props.controls} | |||
loop={!this.props.controls} | |||
/> | |||
</div> | |||
); | |||
}, | |||
@@ -13,7 +13,8 @@ const IconButton = React.createClass({ | |||
activeStyle: React.PropTypes.object, | |||
disabled: React.PropTypes.bool, | |||
inverted: React.PropTypes.bool, | |||
animate: React.PropTypes.bool | |||
animate: React.PropTypes.bool, | |||
overlay: React.PropTypes.bool | |||
}, | |||
getDefaultProps () { | |||
@@ -21,7 +22,8 @@ const IconButton = React.createClass({ | |||
size: 18, | |||
active: false, | |||
disabled: false, | |||
animate: false | |||
animate: false, | |||
overlay: false | |||
}; | |||
}, | |||
@@ -39,7 +41,7 @@ const IconButton = React.createClass({ | |||
let style = { | |||
fontSize: `${this.props.size}px`, | |||
width: `${this.props.size * 1.28571429}px`, | |||
height: `${this.props.size}px`, | |||
height: `${this.props.size * 1.28571429}px`, | |||
lineHeight: `${this.props.size}px`, | |||
...this.props.style | |||
}; | |||
@@ -48,13 +50,31 @@ const IconButton = React.createClass({ | |||
style = { ...style, ...this.props.activeStyle }; | |||
} | |||
const classes = ['icon-button']; | |||
if (this.props.active) { | |||
classes.push('active'); | |||
} | |||
if (this.props.disabled) { | |||
classes.push('disabled'); | |||
} | |||
if (this.props.inverted) { | |||
classes.push('inverted'); | |||
} | |||
if (this.props.overlay) { | |||
classes.push('overlayed'); | |||
} | |||
return ( | |||
<Motion defaultStyle={{ rotate: this.props.active ? -360 : 0 }} style={{ rotate: this.props.animate ? spring(this.props.active ? -360 : 0, { stiffness: 120, damping: 7 }) : 0 }}> | |||
{({ rotate }) => | |||
<button | |||
aria-label={this.props.title} | |||
title={this.props.title} | |||
className={`icon-button ${this.props.active ? 'active' : ''} ${this.props.disabled ? 'disabled' : ''} ${this.props.inverted ? 'inverted' : ''}`} | |||
className={classes.join(' ')} | |||
onClick={this.handleClick} | |||
style={style}> | |||
<i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${this.props.icon}`} aria-hidden='true' /> | |||
@@ -39,8 +39,8 @@ const spoilerSubSpanStyle = { | |||
const spoilerButtonStyle = { | |||
position: 'absolute', | |||
top: '6px', | |||
left: '8px', | |||
top: '4px', | |||
left: '4px', | |||
zIndex: '100' | |||
}; | |||
@@ -232,8 +232,8 @@ const MediaGallery = React.createClass({ | |||
return ( | |||
<div style={{ ...outerStyle, height: `${this.props.height}px` }}> | |||
<div style={spoilerButtonStyle}> | |||
<IconButton title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} onClick={this.handleOpen} /> | |||
<div style={{ ...spoilerButtonStyle, display: !this.state.visible ? 'none' : 'block' }}> | |||
<IconButton title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} overlay onClick={this.handleOpen} /> | |||
</div> | |||
{children} | |||
@@ -22,8 +22,8 @@ const videoStyle = { | |||
const muteStyle = { | |||
position: 'absolute', | |||
top: '10px', | |||
right: '10px', | |||
top: '4px', | |||
right: '4px', | |||
color: 'white', | |||
textShadow: "0px 1px 1px black, 1px 0px 1px black", | |||
opacity: '0.8', | |||
@@ -55,8 +55,8 @@ const spoilerSubSpanStyle = { | |||
const spoilerButtonStyle = { | |||
position: 'absolute', | |||
top: '6px', | |||
left: '8px', | |||
top: '4px', | |||
left: '4px', | |||
color: 'white', | |||
textShadow: "0px 1px 1px black, 1px 0px 1px black", | |||
zIndex: '100' | |||
@@ -64,8 +64,8 @@ const spoilerButtonStyle = { | |||
const expandButtonStyle = { | |||
position: 'absolute', | |||
bottom: '6px', | |||
right: '8px', | |||
bottom: '4px', | |||
right: '4px', | |||
color: 'white', | |||
textShadow: "0px 1px 1px black, 1px 0px 1px black", | |||
zIndex: '100' | |||
@@ -128,10 +128,8 @@ const VideoPlayer = React.createClass({ | |||
}, | |||
handleExpand () { | |||
const node = ReactDOM.findDOMNode(this).querySelector('video'); | |||
node.pause(); | |||
this.props.onOpenVideo(this.props.media); | |||
this.video.pause(); | |||
this.props.onOpenVideo(this.props.media, this.video.currentTime); | |||
}, | |||
setRef (c) { | |||
@@ -172,14 +170,14 @@ const VideoPlayer = React.createClass({ | |||
const { media, intl, width, height, sensitive, autoplay } = this.props; | |||
let spoilerButton = ( | |||
<div style={spoilerButtonStyle} > | |||
<IconButton title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} onClick={this.handleVisibility} /> | |||
<div style={{...spoilerButtonStyle, display: !this.state.visible ? 'none' : 'block'}} > | |||
<IconButton overlay title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} onClick={this.handleVisibility} /> | |||
</div> | |||
); | |||
let expandButton = ( | |||
<div style={expandButtonStyle} > | |||
<IconButton title={intl.formatMessage(messages.expand_video)} icon='expand' onClick={this.handleExpand} /> | |||
<IconButton overlay title={intl.formatMessage(messages.expand_video)} icon='expand' onClick={this.handleExpand} /> | |||
</div> | |||
); | |||
@@ -188,7 +186,7 @@ const VideoPlayer = React.createClass({ | |||
if (this.state.hasAudio) { | |||
muteButton = ( | |||
<div style={muteStyle}> | |||
<IconButton title={intl.formatMessage(messages.toggle_sound)} icon={this.state.muted ? 'volume-off' : 'volume-up'} onClick={this.handleClick} /> | |||
<IconButton overlay title={intl.formatMessage(messages.toggle_sound)} icon={this.state.muted ? 'volume-off' : 'volume-up'} onClick={this.handleClick} /> | |||
</div> | |||
); | |||
} | |||
@@ -75,8 +75,8 @@ const mapDispatchToProps = (dispatch) => ({ | |||
dispatch(openModal('MEDIA', { media, index })); | |||
}, | |||
onOpenVideo (media) { | |||
dispatch(openModal('VIDEO', { media })); | |||
onOpenVideo (media, time) { | |||
dispatch(openModal('VIDEO', { media, time })); | |||
}, | |||
onBlock (account) { | |||
@@ -112,8 +112,8 @@ const Status = React.createClass({ | |||
this.props.dispatch(openModal('MEDIA', { media, index })); | |||
}, | |||
handleOpenVideo (media) { | |||
this.props.dispatch(openModal('VIDEO', { media })); | |||
handleOpenVideo (media, time) { | |||
this.props.dispatch(openModal('VIDEO', { media, time })); | |||
}, | |||
handleReport (status) { | |||
@@ -20,6 +20,7 @@ const VideoModal = React.createClass({ | |||
propTypes: { | |||
media: ImmutablePropTypes.map.isRequired, | |||
time: React.PropTypes.number, | |||
onClose: React.PropTypes.func.isRequired, | |||
intl: React.PropTypes.object.isRequired | |||
}, | |||
@@ -27,15 +28,15 @@ const VideoModal = React.createClass({ | |||
mixins: [PureRenderMixin], | |||
render () { | |||
const { media, intl, onClose } = this.props; | |||
const { media, intl, time, onClose } = this.props; | |||
const url = media.get('url'); | |||
return ( | |||
<div className='modal-root__modal media-modal'> | |||
<div> | |||
<IconButton title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} style={closeStyle} /> | |||
<ExtendedVideoPlayer src={url} muted={false} controls={true} /> | |||
<div style={closeStyle}><IconButton title={intl.formatMessage(messages.close)} icon='times' overlay onClick={onClose} /></div> | |||
<ExtendedVideoPlayer src={url} muted={false} controls={true} time={time} /> | |||
</div> | |||
</div> | |||
); | |||
@@ -112,6 +112,18 @@ | |||
color: $color3; | |||
} | |||
} | |||
&.overlayed { | |||
box-sizing: content-box; | |||
background: rgba($color8, 0.6); | |||
color: rgba($color5, 0.7); | |||
border-radius: 4px; | |||
padding: 2px; | |||
&:hover { | |||
background: rgba($color8, 0.9); | |||
} | |||
} | |||
} | |||
.text-icon-button { | |||