diff options
Diffstat (limited to 'app/javascript')
-rw-r--r-- | app/javascript/mastodon/features/compose/components/privacy_dropdown.js | 22 | ||||
-rw-r--r-- | app/javascript/styles/mastodon/stream_entries.scss | 14 |
2 files changed, 30 insertions, 6 deletions
diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js index e5de13178..6b22ba84a 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js @@ -32,6 +32,10 @@ class PrivacyDropdownMenu extends React.PureComponent { onChange: PropTypes.func.isRequired, }; + state = { + mounted: false, + }; + handleDocumentClick = e => { if (this.node && !this.node.contains(e.target)) { this.props.onClose(); @@ -54,6 +58,7 @@ class PrivacyDropdownMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); + this.setState({ mounted: true }); } componentWillUnmount () { @@ -66,12 +71,16 @@ class PrivacyDropdownMenu extends React.PureComponent { } render () { + const { mounted } = this.state; const { style, items, value } = this.props; return ( <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}> {({ opacity, scaleX, scaleY }) => ( - <div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }} ref={this.setRef}> + // It should not be transformed when mounting because the resulting + // size will be used to determine the coordinate of the menu by + // react-overlays + <div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}> {items.map(item => ( <div role='button' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleClick} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })}> <div className='privacy-dropdown__option__icon'> @@ -107,9 +116,10 @@ export default class PrivacyDropdown extends React.PureComponent { state = { open: false, + placement: null, }; - handleToggle = () => { + handleToggle = ({ target }) => { if (this.props.isUserTouching()) { if (this.state.open) { this.props.onModalClose(); @@ -120,6 +130,8 @@ export default class PrivacyDropdown extends React.PureComponent { }); } } else { + const { top } = target.getBoundingClientRect(); + this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ open: !this.state.open }); } } @@ -136,7 +148,7 @@ export default class PrivacyDropdown extends React.PureComponent { handleKeyDown = e => { switch(e.key) { case 'Enter': - this.handleToggle(); + this.handleToggle(e); break; case 'Escape': this.handleClose(); @@ -165,7 +177,7 @@ export default class PrivacyDropdown extends React.PureComponent { render () { const { value, intl } = this.props; - const { open } = this.state; + const { open, placement } = this.state; const valueOption = this.options.find(item => item.value === value); @@ -185,7 +197,7 @@ export default class PrivacyDropdown extends React.PureComponent { /> </div> - <Overlay show={open} placement='bottom' target={this}> + <Overlay show={open} placement={placement} target={this}> <PrivacyDropdownMenu items={this.options} value={value} diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss index 442b143a0..dfdc48d06 100644 --- a/app/javascript/styles/mastodon/stream_entries.scss +++ b/app/javascript/styles/mastodon/stream_entries.scss @@ -6,7 +6,8 @@ background: $simple-background-color; .detailed-status.light, - .status.light { + .status.light, + .more.light { border-bottom: 1px solid $ui-secondary-color; animation: none; } @@ -290,6 +291,17 @@ text-decoration: underline; } } + + .more { + color: $classic-primary-color; + display: block; + padding: 14px; + text-align: center; + + &:not(:hover) { + text-decoration: none; + } + } } .embed { |