status clickable (this also fixes multiple dropdown being openable at the same time)master
@@ -28,7 +28,7 @@ const ColumnBackButton = React.createClass({ | |||||
render () { | render () { | ||||
return ( | return ( | ||||
<div onClick={this.handleClick} style={outerStyle}> | |||||
<div onClick={this.handleClick} style={outerStyle} className='column-back-button'> | |||||
<i className='fa fa-fw fa-chevron-left' style={iconStyle} /> | <i className='fa fa-fw fa-chevron-left' style={iconStyle} /> | ||||
Back | Back | ||||
</div> | </div> | ||||
@@ -7,7 +7,7 @@ const DropdownMenu = ({ icon, items, size }) => { | |||||
<i className={`fa fa-fw fa-${icon}`} style={{ verticalAlign: 'middle' }} /> | <i className={`fa fa-fw fa-${icon}`} style={{ verticalAlign: 'middle' }} /> | ||||
</DropdownTrigger> | </DropdownTrigger> | ||||
<DropdownContent style={{ lineHeight: '18px' }}> | |||||
<DropdownContent style={{ lineHeight: '18px', textAlign: 'left' }}> | |||||
<ul> | <ul> | ||||
{items.map(({ text, action, href = '#' }, i) => <li key={i}><a href={href} target='_blank' rel='noopener' onClick={e => { | {items.map(({ text, action, href = '#' }, i) => <li key={i}><a href={href} target='_blank' rel='noopener' onClick={e => { | ||||
if (typeof action === 'function') { | if (typeof action === 'function') { | ||||
@@ -1,4 +1,6 @@ | |||||
import PureRenderMixin from 'react-addons-pure-render-mixin'; | |||||
import IconButton from './icon_button'; | import IconButton from './icon_button'; | ||||
import { Motion, spring } from 'react-motion'; | |||||
const overlayStyle = { | const overlayStyle = { | ||||
position: 'fixed', | position: 'fixed', | ||||
@@ -6,19 +8,17 @@ const overlayStyle = { | |||||
left: '0', | left: '0', | ||||
width: '100%', | width: '100%', | ||||
height: '100%', | height: '100%', | ||||
justifyContent: 'center', | |||||
alignContent: 'center', | |||||
background: 'rgba(0, 0, 0, 0.5)', | background: 'rgba(0, 0, 0, 0.5)', | ||||
display: 'flex', | display: 'flex', | ||||
justifyContent: 'center', | |||||
alignContent: 'center', | |||||
flexDirection: 'row', | |||||
zIndex: '9999' | zIndex: '9999' | ||||
}; | }; | ||||
const dialogStyle = { | const dialogStyle = { | ||||
color: '#282c37', | color: '#282c37', | ||||
background: '#d9e1e8', | |||||
borderRadius: '4px', | |||||
boxShadow: '0 0 15px rgba(0, 0, 0, 0.4)', | |||||
padding: '10px', | |||||
boxShadow: '0 0 30px rgba(0, 0, 0, 0.8)', | |||||
margin: 'auto', | margin: 'auto', | ||||
position: 'relative' | position: 'relative' | ||||
}; | }; | ||||
@@ -29,25 +29,33 @@ const closeStyle = { | |||||
right: '4px' | right: '4px' | ||||
}; | }; | ||||
const Lightbox = ({ isVisible, onOverlayClicked, onCloseClicked, children }) => { | |||||
if (!isVisible) { | |||||
return <div />; | |||||
} | |||||
const Lightbox = React.createClass({ | |||||
propTypes: { | |||||
isVisible: React.PropTypes.bool, | |||||
onOverlayClicked: React.PropTypes.func, | |||||
onCloseClicked: React.PropTypes.func | |||||
}, | |||||
return ( | |||||
<div className='lightbox' style={overlayStyle} onClick={onOverlayClicked}> | |||||
<div style={dialogStyle}> | |||||
<IconButton title='Close' icon='times' onClick={onCloseClicked} size={16} style={closeStyle} /> | |||||
{children} | |||||
mixins: [PureRenderMixin], | |||||
render () { | |||||
const { isVisible, onOverlayClicked, onCloseClicked, children } = this.props; | |||||
return ( | |||||
<div className='lightbox' style={{...overlayStyle, display: isVisible ? 'flex' : 'none'}} onClick={onOverlayClicked}> | |||||
<Motion defaultStyle={{ y: -200 }} style={{ y: spring(isVisible ? 0 : -200) }}> | |||||
{({ y }) => | |||||
<div style={{...dialogStyle, transform: `translateY(${y}px)`}}> | |||||
<IconButton title='Close' icon='times' onClick={onCloseClicked} size={16} style={closeStyle} /> | |||||
{children} | |||||
</div> | |||||
} | |||||
</Motion> | |||||
</div> | </div> | ||||
</div> | |||||
); | |||||
}; | |||||
); | |||||
} | |||||
Lightbox.propTypes = { | |||||
isVisible: React.PropTypes.bool, | |||||
onOverlayClicked: React.PropTypes.func, | |||||
onCloseClicked: React.PropTypes.func | |||||
}; | |||||
}); | |||||
export default Lightbox; | export default Lightbox; |
@@ -58,7 +58,7 @@ const Status = React.createClass({ | |||||
} | } | ||||
return ( | return ( | ||||
<div style={{ cursor: 'pointer' }} onClick={this.handleClick}> | |||||
<div style={{ cursor: 'default' }}> | |||||
<div style={{ marginLeft: '68px', color: '#616b86', padding: '8px 0', paddingBottom: '2px', fontSize: '14px', position: 'relative' }}> | <div style={{ marginLeft: '68px', color: '#616b86', padding: '8px 0', paddingBottom: '2px', fontSize: '14px', position: 'relative' }}> | ||||
<div style={{ position: 'absolute', 'left': '-26px'}}><i className='fa fa-fw fa-retweet'></i></div> | <div style={{ position: 'absolute', 'left': '-26px'}}><i className='fa fa-fw fa-retweet'></i></div> | ||||
<a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{displayName}</strong></a> reblogged | <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{displayName}</strong></a> reblogged | ||||
@@ -78,7 +78,7 @@ const Status = React.createClass({ | |||||
} | } | ||||
return ( | return ( | ||||
<div style={{ padding: '8px 10px', paddingLeft: '68px', position: 'relative', minHeight: '48px', borderBottom: '1px solid #363c4b', cursor: 'pointer' }} onClick={this.handleClick}> | |||||
<div style={{ padding: '8px 10px', paddingLeft: '68px', position: 'relative', minHeight: '48px', borderBottom: '1px solid #363c4b', cursor: 'default' }}> | |||||
<div style={{ fontSize: '15px' }}> | <div style={{ fontSize: '15px' }}> | ||||
<div style={{ float: 'right', fontSize: '14px' }}> | <div style={{ float: 'right', fontSize: '14px' }}> | ||||
<a href={status.get('url')} className='status__relative-time' style={{ color: '#616b86' }} target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} now={now} /></a> | <a href={status.get('url')} className='status__relative-time' style={{ color: '#616b86' }} target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} now={now} /></a> | ||||
@@ -93,7 +93,7 @@ const Status = React.createClass({ | |||||
</a> | </a> | ||||
</div> | </div> | ||||
<StatusContent status={status} /> | |||||
<StatusContent status={status} onClick={this.handleClick} /> | |||||
{media} | {media} | ||||
@@ -51,7 +51,7 @@ const StatusActionBar = React.createClass({ | |||||
<div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={this.handleReblogClick} /></div> | <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={this.handleReblogClick} /></div> | ||||
<div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> | <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> | ||||
<div onClick={e => e.stopPropagation()} style={{ width: '18px', height: '18px', float: 'left' }}> | |||||
<div style={{ width: '18px', height: '18px', float: 'left' }}> | |||||
<DropdownMenu items={menu} icon='ellipsis-h' size={18} /> | <DropdownMenu items={menu} icon='ellipsis-h' size={18} /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -13,7 +13,8 @@ const StatusContent = React.createClass({ | |||||
}, | }, | ||||
propTypes: { | propTypes: { | ||||
status: ImmutablePropTypes.map.isRequired | |||||
status: ImmutablePropTypes.map.isRequired, | |||||
onClick: React.PropTypes.func | |||||
}, | }, | ||||
mixins: [PureRenderMixin], | mixins: [PureRenderMixin], | ||||
@@ -61,7 +62,7 @@ const StatusContent = React.createClass({ | |||||
render () { | render () { | ||||
const content = { __html: emojione.unicodeToImage(this.props.status.get('content')) }; | const content = { __html: emojione.unicodeToImage(this.props.status.get('content')) }; | ||||
return <div className='status__content' dangerouslySetInnerHTML={content} />; | |||||
return <div className='status__content' style={{ cursor: 'pointer' }} dangerouslySetInnerHTML={content} onClick={this.props.onClick} />; | |||||
}, | }, | ||||
}); | }); | ||||
@@ -28,7 +28,7 @@ const Header = React.createClass({ | |||||
return ( | return ( | ||||
<div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover', position: 'relative' }}> | <div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover', position: 'relative' }}> | ||||
<div style={{ background: 'rgba(47, 52, 65, 0.8)', padding: '20px 10px' }}> | |||||
<div style={{ background: 'rgba(47, 52, 65, 0.9)', padding: '20px 10px' }}> | |||||
<a href={account.get('url')} target='_blank' rel='noopener' style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}> | <a href={account.get('url')} target='_blank' rel='noopener' style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}> | ||||
<div style={{ width: '90px', margin: '0 auto', marginBottom: '10px' }}> | <div style={{ width: '90px', margin: '0 auto', marginBottom: '10px' }}> | ||||
<img src={account.get('avatar')} alt='' style={{ display: 'block', width: '90px', height: '90px', borderRadius: '90px' }} /> | <img src={account.get('avatar')} alt='' style={{ display: 'block', width: '90px', height: '90px', borderRadius: '90px' }} /> | ||||
@@ -18,23 +18,23 @@ const ActionBar = React.createClass({ | |||||
mixins: [PureRenderMixin], | mixins: [PureRenderMixin], | ||||
handleReplyClick () { | handleReplyClick () { | ||||
this.props.onReply(status); | |||||
this.props.onReply(this.props.status); | |||||
}, | }, | ||||
handleReblogClick () { | handleReblogClick () { | ||||
this.props.onReblog(status); | |||||
this.props.onReblog(this.props.status); | |||||
}, | }, | ||||
handleFavouriteClick () { | handleFavouriteClick () { | ||||
this.props.onFavourite(status); | |||||
this.props.onFavourite(this.props.status); | |||||
}, | }, | ||||
handleDeleteClick () { | handleDeleteClick () { | ||||
this.props.onDelete(status); | |||||
this.props.onDelete(this.props.status); | |||||
}, | }, | ||||
handleMentionClick () { | handleMentionClick () { | ||||
this.props.onMention(status.get('account')); | |||||
this.props.onMention(this.props.status.get('account')); | |||||
}, | }, | ||||
render () { | render () { | ||||
@@ -19,9 +19,8 @@ const mapDispatchToProps = dispatch => ({ | |||||
const imageStyle = { | const imageStyle = { | ||||
display: 'block', | display: 'block', | ||||
maxWidth: '100%', | |||||
height: 'auto', | |||||
margin: '0 auto' | |||||
maxWidth: '80vw', | |||||
maxHeight: '80vh' | |||||
}; | }; | ||||
const Modal = React.createClass({ | const Modal = React.createClass({ | ||||
@@ -350,3 +350,9 @@ | |||||
flex: 1 1 auto; | flex: 1 1 auto; | ||||
-webkit-overflow-scrolling: touch; | -webkit-overflow-scrolling: touch; | ||||
} | } | ||||
.column-back-button { | |||||
&:hover { | |||||
text-decoration: underline; | |||||
} | |||||
} |
@@ -43,6 +43,7 @@ | |||||
"dependencies": { | "dependencies": { | ||||
"emojione": "^2.2.6", | "emojione": "^2.2.6", | ||||
"react-autosuggest": "^7.0.1", | "react-autosuggest": "^7.0.1", | ||||
"react-motion": "^0.4.5", | |||||
"react-responsive": "^1.1.5", | "react-responsive": "^1.1.5", | ||||
"react-router-scroll": "^0.3.2" | "react-router-scroll": "^0.3.2" | ||||
} | } | ||||
@@ -3431,6 +3431,10 @@ pbkdf2@^3.0.3: | |||||
dependencies: | dependencies: | ||||
create-hmac "^1.1.2" | create-hmac "^1.1.2" | ||||
performance-now@^0.2.0, performance-now@~0.2.0: | |||||
version "0.2.0" | |||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" | |||||
pinkie-promise@^2.0.0: | pinkie-promise@^2.0.0: | ||||
version "2.0.1" | version "2.0.1" | ||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" | ||||
@@ -3779,6 +3783,12 @@ querystring@^0.2.0, querystring@0.2.0: | |||||
version "0.2.0" | version "0.2.0" | ||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" | resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" | ||||
raf@^3.1.0: | |||||
version "3.3.0" | |||||
resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.0.tgz#93845eeffc773f8129039f677f80a36044eee2c3" | |||||
dependencies: | |||||
performance-now "~0.2.0" | |||||
randomatic@^1.1.3: | randomatic@^1.1.3: | ||||
version "1.1.5" | version "1.1.5" | ||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b" | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b" | ||||
@@ -3887,6 +3897,13 @@ react-modal@^1.2.0, react-modal@^1.2.1: | |||||
exenv "1.2.0" | exenv "1.2.0" | ||||
lodash.assign "^3.2.0" | lodash.assign "^3.2.0" | ||||
react-motion: | |||||
version "0.4.5" | |||||
resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.4.5.tgz#ecc42f692fec9b2de4c92f85e26375071f779b76" | |||||
dependencies: | |||||
performance-now "^0.2.0" | |||||
raf "^3.1.0" | |||||
react-notification@^6.1.1: | react-notification@^6.1.1: | ||||
version "6.2.1" | version "6.2.1" | ||||
resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.2.1.tgz#deeccf15c0899badc24adaa704a1e78583762438" | resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.2.1.tgz#deeccf15c0899badc24adaa704a1e78583762438" | ||||