forked from cybrespace/mastodon
Fix modals sizing and add animation to it, fix #140 by only making the text of
status clickable (this also fixes multiple dropdown being openable at the same time)
This commit is contained in:
parent
0320ea4b85
commit
82fd74d101
|
@ -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',
|
boxShadow: '0 0 30px rgba(0, 0, 0, 0.8)',
|
||||||
borderRadius: '4px',
|
|
||||||
boxShadow: '0 0 15px rgba(0, 0, 0, 0.4)',
|
|
||||||
padding: '10px',
|
|
||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
position: 'relative'
|
position: 'relative'
|
||||||
};
|
};
|
||||||
|
@ -29,25 +29,33 @@ const closeStyle = {
|
||||||
right: '4px'
|
right: '4px'
|
||||||
};
|
};
|
||||||
|
|
||||||
const Lightbox = ({ isVisible, onOverlayClicked, onCloseClicked, children }) => {
|
const Lightbox = React.createClass({
|
||||||
if (!isVisible) {
|
|
||||||
return <div />;
|
propTypes: {
|
||||||
|
isVisible: React.PropTypes.bool,
|
||||||
|
onOverlayClicked: React.PropTypes.func,
|
||||||
|
onCloseClicked: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
});
|
||||||
<div className='lightbox' style={overlayStyle} onClick={onOverlayClicked}>
|
|
||||||
<div style={dialogStyle}>
|
|
||||||
<IconButton title='Close' icon='times' onClick={onCloseClicked} size={16} style={closeStyle} />
|
|
||||||
{children}
|
|
||||||
</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%',
|
maxWidth: '80vw',
|
||||||
height: 'auto',
|
maxHeight: '80vh'
|
||||||
margin: '0 auto'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue