From bc91069e08e0dadcb523b6e372c0c0830376706c Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 13 Dec 2022 19:41:53 +0100 Subject: [Glitch] Change default reply language to be default language when replying to a translated reply Port f70bdba9264bd7c572cee3c45421733919b7d03c to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/reducers/compose.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch/reducers') diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 9b50ec23a..ddc3fa41e 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -421,8 +421,10 @@ export default function compose(state = initialState, action) { map.set('preselectDate', new Date()); map.set('idempotencyKey', uuid()); - if (action.status.get('language')) { + if (action.status.get('language') && !action.status.has('translation')) { map.set('language', action.status.get('language')); + } else { + map.set('language', state.get('default_language')); } if (action.status.get('spoiler_text').length > 0) { -- cgit From cdba1ec5f4edd3e3095c161f34f8d1cc3beebaef Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 15 Dec 2022 17:47:43 +0100 Subject: [Glitch] Fix being stuck in edit mode when deleting the edited status Port ebf1d74e409ece10864a8615691cd80c434c9055 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/reducers/compose.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/javascript/flavours/glitch/reducers') diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index ddc3fa41e..814b6a1a7 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -538,6 +538,8 @@ export default function compose(state = initialState, action) { case TIMELINE_DELETE: if (action.id === state.get('in_reply_to')) { return state.set('in_reply_to', null); + } else if (action.id === state.get('id')) { + return state.set('id', null); } else { return state; } -- cgit From 0912fb736d435b132779828376cd10cf7ad8e56e Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 15 Dec 2022 18:50:11 +0100 Subject: [Glitch] Add follow request banner on account header Port 70415714f14e067aba518a105c96475db31fa124 to glitch-soc Signed-off-by: Claire --- .../account/components/follow_request_note.js | 37 ++++++++++++++++++++++ .../glitch/features/account/components/header.js | 3 ++ .../containers/follow_request_note_container.js | 15 +++++++++ .../flavours/glitch/reducers/relationships.js | 11 +++++++ .../glitch/styles/components/accounts.scss | 34 ++++++++++++++++++++ .../flavours/glitch/styles/components/index.scss | 24 ++++++++++++++ 6 files changed, 124 insertions(+) create mode 100644 app/javascript/flavours/glitch/features/account/components/follow_request_note.js create mode 100644 app/javascript/flavours/glitch/features/account/containers/follow_request_note_container.js (limited to 'app/javascript/flavours/glitch/reducers') diff --git a/app/javascript/flavours/glitch/features/account/components/follow_request_note.js b/app/javascript/flavours/glitch/features/account/components/follow_request_note.js new file mode 100644 index 000000000..73c1737a6 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account/components/follow_request_note.js @@ -0,0 +1,37 @@ +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { FormattedMessage } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import Icon from 'flavours/glitch/components/icon'; + +export default class FollowRequestNote extends ImmutablePureComponent { + + static propTypes = { + account: ImmutablePropTypes.map.isRequired, + }; + + render () { + const { account, onAuthorize, onReject } = this.props; + + return ( +
+
+ }} /> +
+ +
+ + + +
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index d261c6ea5..b0fb527c7 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -13,6 +13,7 @@ import Button from 'flavours/glitch/components/button'; import { NavLink } from 'react-router-dom'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; import AccountNoteContainer from '../containers/account_note_container'; +import FollowRequestNoteContainer from '../containers/follow_request_note_container'; import { PERMISSION_MANAGE_USERS } from 'flavours/glitch/permissions'; import { Helmet } from 'react-helmet'; @@ -314,6 +315,8 @@ class Header extends ImmutablePureComponent { return (
+ {!(suspended || hidden || account.get('moved')) && account.getIn(['relationship', 'requested_by']) && } +
{info} diff --git a/app/javascript/flavours/glitch/features/account/containers/follow_request_note_container.js b/app/javascript/flavours/glitch/features/account/containers/follow_request_note_container.js new file mode 100644 index 000000000..c6a3afb7e --- /dev/null +++ b/app/javascript/flavours/glitch/features/account/containers/follow_request_note_container.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import FollowRequestNote from '../components/follow_request_note'; +import { authorizeFollowRequest, rejectFollowRequest } from 'flavours/glitch/actions/accounts'; + +const mapDispatchToProps = (dispatch, { account }) => ({ + onAuthorize () { + dispatch(authorizeFollowRequest(account.get('id'))); + }, + + onReject () { + dispatch(rejectFollowRequest(account.get('id'))); + }, +}); + +export default connect(null, mapDispatchToProps)(FollowRequestNote); diff --git a/app/javascript/flavours/glitch/reducers/relationships.js b/app/javascript/flavours/glitch/reducers/relationships.js index 49dd77ef5..e4b9acea2 100644 --- a/app/javascript/flavours/glitch/reducers/relationships.js +++ b/app/javascript/flavours/glitch/reducers/relationships.js @@ -1,3 +1,6 @@ +import { + NOTIFICATIONS_UPDATE, +} from '../actions/notifications'; import { ACCOUNT_FOLLOW_SUCCESS, ACCOUNT_FOLLOW_REQUEST, @@ -12,6 +15,8 @@ import { ACCOUNT_PIN_SUCCESS, ACCOUNT_UNPIN_SUCCESS, RELATIONSHIPS_FETCH_SUCCESS, + FOLLOW_REQUEST_AUTHORIZE_SUCCESS, + FOLLOW_REQUEST_REJECT_SUCCESS, } from 'flavours/glitch/actions/accounts'; import { DOMAIN_BLOCK_SUCCESS, @@ -44,6 +49,12 @@ const initialState = ImmutableMap(); export default function relationships(state = initialState, action) { switch(action.type) { + case FOLLOW_REQUEST_AUTHORIZE_SUCCESS: + return state.setIn([action.id, 'followed_by'], true).setIn([action.id, 'requested_by'], false); + case FOLLOW_REQUEST_REJECT_SUCCESS: + return state.setIn([action.id, 'followed_by'], false).setIn([action.id, 'requested_by'], false); + case NOTIFICATIONS_UPDATE: + return action.notification.type === 'follow_request' ? state.setIn([action.notification.account.id, 'requested_by'], true) : state; case ACCOUNT_FOLLOW_REQUEST: return state.getIn([action.id, 'following']) ? state : state.setIn([action.id, action.locked ? 'requested' : 'following'], true); case ACCOUNT_FOLLOW_FAIL: diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index 2a955f426..5b3e1db1b 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -756,3 +756,37 @@ } } } + +.moved-account-banner, +.follow-request-banner { + padding: 20px; + background: lighten($ui-base-color, 4%); + display: flex; + align-items: center; + flex-direction: column; + &__message { + color: $darker-text-color; + padding: 8px 0; + padding-top: 0; + padding-bottom: 4px; + font-size: 14px; + font-weight: 500; + text-align: center; + margin-bottom: 16px; + } + &__action { + display: flex; + justify-content: space-between; + align-items: center; + gap: 15px; + width: 100%; + } + + .detailed-status__display-name { + margin-bottom: 0; + } +} + +.follow-request-banner .button { + width: 100%; +} diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 84aca2ebc..b7a54cd2b 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -141,6 +141,30 @@ &:disabled { opacity: 0.5; } + + &.button--confirmation { + color: $valid-value-color; + border-color: $valid-value-color; + + &:active, + &:focus, + &:hover { + background: $valid-value-color; + color: $primary-text-color; + } + } + + &.button--destructive { + color: $error-value-color; + border-color: $error-value-color; + + &:active, + &:focus, + &:hover { + background: $error-value-color; + color: $primary-text-color; + } + } } &.button--block { -- cgit From a36dfbb2aa53b8ce3e4c88826aeda9f25d98e49a Mon Sep 17 00:00:00 2001 From: Peter Simonsson Date: Wed, 11 Jan 2023 21:58:46 +0100 Subject: [Glitch] Fix dropdown menu positions when scrolling Port fd33bcb3b25d3eaf593ade0aa8709a1184fc254e to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/dropdown_menu.js | 4 +- .../flavours/glitch/components/dropdown_menu.js | 102 ++++++++------------- .../containers/dropdown_menu_container.js | 5 +- .../glitch/containers/dropdown_menu_container.js | 5 +- .../glitch/features/compose/components/dropdown.js | 47 +++++++--- .../features/compose/components/dropdown_menu.js | 46 +--------- .../compose/components/emoji_picker_dropdown.js | 39 ++++---- .../compose/components/language_dropdown.js | 81 ++++++++-------- .../glitch/features/compose/components/search.js | 51 +++++------ .../flavours/glitch/reducers/dropdown_menu.js | 4 +- .../glitch/styles/components/compose_form.scss | 2 - .../flavours/glitch/styles/components/index.scss | 85 ++++++++++++----- .../flavours/glitch/styles/components/modal.scss | 1 - .../glitch/styles/mastodon-light/diff.scss | 18 +--- 14 files changed, 234 insertions(+), 256 deletions(-) (limited to 'app/javascript/flavours/glitch/reducers') diff --git a/app/javascript/flavours/glitch/actions/dropdown_menu.js b/app/javascript/flavours/glitch/actions/dropdown_menu.js index fb6e55612..023151d4b 100644 --- a/app/javascript/flavours/glitch/actions/dropdown_menu.js +++ b/app/javascript/flavours/glitch/actions/dropdown_menu.js @@ -1,8 +1,8 @@ export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN'; export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE'; -export function openDropdownMenu(id, placement, keyboard, scroll_key) { - return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard, scroll_key }; +export function openDropdownMenu(id, keyboard, scroll_key) { + return { type: DROPDOWN_MENU_OPEN, id, keyboard, scroll_key }; } export function closeDropdownMenu(id) { diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.js b/app/javascript/flavours/glitch/components/dropdown_menu.js index 036e0b909..7c70f750f 100644 --- a/app/javascript/flavours/glitch/components/dropdown_menu.js +++ b/app/javascript/flavours/glitch/components/dropdown_menu.js @@ -2,9 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import IconButton from './icon_button'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from '../features/ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import { CircularProgress } from 'flavours/glitch/components/loading_indicator'; @@ -24,9 +22,6 @@ class DropdownMenu extends React.PureComponent { scrollable: PropTypes.bool, onClose: PropTypes.func.isRequired, style: PropTypes.object, - placement: PropTypes.string, - arrowOffsetLeft: PropTypes.string, - arrowOffsetTop: PropTypes.string, openedViaKeyboard: PropTypes.bool, renderItem: PropTypes.func, renderHeader: PropTypes.func, @@ -35,11 +30,6 @@ class DropdownMenu extends React.PureComponent { static defaultProps = { style: {}, - placement: 'bottom', - }; - - state = { - mounted: false, }; handleDocumentClick = e => { @@ -56,8 +46,6 @@ class DropdownMenu extends React.PureComponent { if (this.focusedItem && this.props.openedViaKeyboard) { this.focusedItem.focus({ preventScroll: true }); } - - this.setState({ mounted: true }); } componentWillUnmount () { @@ -139,40 +127,28 @@ class DropdownMenu extends React.PureComponent { } render () { - const { items, style, placement, arrowOffsetLeft, arrowOffsetTop, scrollable, renderHeader, loading } = this.props; - const { mounted } = this.state; + const { items, scrollable, renderHeader, loading } = this.props; let renderItem = this.props.renderItem || this.renderItem; return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
-
- -
- {loading && ( - - )} - - {!loading && renderHeader && ( -
- {renderHeader(items)} -
- )} - - {!loading && ( -
    - {items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))} -
- )} -
+
+ {loading && ( + + )} + + {!loading && renderHeader && ( +
+ {renderHeader(items)}
)} - + + {!loading && ( +
    + {items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))} +
+ )} +
); } @@ -197,7 +173,6 @@ export default class Dropdown extends React.PureComponent { isUserTouching: PropTypes.func, onOpen: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, - dropdownPlacement: PropTypes.string, openDropdownId: PropTypes.number, openedViaKeyboard: PropTypes.bool, renderItem: PropTypes.func, @@ -213,13 +188,11 @@ export default class Dropdown extends React.PureComponent { id: id++, }; - handleClick = ({ target, type }) => { + handleClick = ({ type }) => { if (this.state.id === this.props.openDropdownId) { this.handleClose(); } else { - const { top } = target.getBoundingClientRect(); - const placement = top * 2 < innerHeight ? 'bottom' : 'top'; - this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click'); + this.props.onOpen(this.state.id, this.handleItemClick, type !== 'click'); } } @@ -303,7 +276,6 @@ export default class Dropdown extends React.PureComponent { disabled, loading, scrollable, - dropdownPlacement, openDropdownId, openedViaKeyboard, children, @@ -314,7 +286,6 @@ export default class Dropdown extends React.PureComponent { const open = this.state.id === openDropdownId; const button = children ? React.cloneElement(React.Children.only(children), { - ref: this.setTargetRef, onClick: this.handleClick, onMouseDown: this.handleMouseDown, onKeyDown: this.handleButtonKeyDown, @@ -326,7 +297,6 @@ export default class Dropdown extends React.PureComponent { active={open} disabled={disabled} size={size} - ref={this.setTargetRef} onClick={this.handleClick} onMouseDown={this.handleMouseDown} onKeyDown={this.handleButtonKeyDown} @@ -336,19 +306,27 @@ export default class Dropdown extends React.PureComponent { return ( - {button} - - - + + {button} + + + {({ props, arrowProps, placement }) => ( +
+
+
+ +
+
+ )} ); diff --git a/app/javascript/flavours/glitch/components/edited_timestamp/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/components/edited_timestamp/containers/dropdown_menu_container.js index 8b73663d4..a1519757d 100644 --- a/app/javascript/flavours/glitch/components/edited_timestamp/containers/dropdown_menu_container.js +++ b/app/javascript/flavours/glitch/components/edited_timestamp/containers/dropdown_menu_container.js @@ -4,7 +4,6 @@ import { fetchHistory } from 'flavours/glitch/actions/history'; import DropdownMenu from 'flavours/glitch/components/dropdown_menu'; const mapStateToProps = (state, { statusId }) => ({ - dropdownPlacement: state.getIn(['dropdown_menu', 'placement']), openDropdownId: state.getIn(['dropdown_menu', 'openId']), openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), items: state.getIn(['history', statusId, 'items']), @@ -13,9 +12,9 @@ const mapStateToProps = (state, { statusId }) => ({ const mapDispatchToProps = (dispatch, { statusId }) => ({ - onOpen (id, onItemClick, dropdownPlacement, keyboard) { + onOpen (id, onItemClick, keyboard) { dispatch(fetchHistory(statusId)); - dispatch(openDropdownMenu(id, dropdownPlacement, keyboard)); + dispatch(openDropdownMenu(id, keyboard)); }, onClose (id) { diff --git a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js index b2dff63db..43ce8ca63 100644 --- a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js +++ b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js @@ -5,18 +5,17 @@ import DropdownMenu from 'flavours/glitch/components/dropdown_menu'; import { isUserTouching } from '../is_mobile'; const mapStateToProps = state => ({ - dropdownPlacement: state.getIn(['dropdown_menu', 'placement']), openDropdownId: state.getIn(['dropdown_menu', 'openId']), openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), }); const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ - onOpen(id, onItemClick, dropdownPlacement, keyboard) { + onOpen(id, onItemClick, keyboard) { dispatch(isUserTouching() ? openModal('ACTIONS', { status, actions: items, onClick: onItemClick, - }) : openDropdownMenu(id, dropdownPlacement, keyboard, scrollKey)); + }) : openDropdownMenu(id, keyboard, scrollKey)); }, onClose(id) { diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown.js b/app/javascript/flavours/glitch/features/compose/components/dropdown.js index 3de198c45..924618930 100644 --- a/app/javascript/flavours/glitch/features/compose/components/dropdown.js +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown.js @@ -2,7 +2,7 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import Overlay from 'react-overlays/lib/Overlay'; +import Overlay from 'react-overlays/Overlay'; // Components. import IconButton from 'flavours/glitch/components/icon_button'; @@ -45,7 +45,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent { }; // Toggles opening and closing the dropdown. - handleToggle = ({ target, type }) => { + handleToggle = ({ type }) => { const { onModalOpen } = this.props; const { open } = this.state; @@ -59,11 +59,9 @@ export default class ComposerOptionsDropdown extends React.PureComponent { } } } else { - const { top } = target.getBoundingClientRect(); if (this.state.open && this.activeElement) { this.activeElement.focus({ preventScroll: true }); } - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ open: !this.state.open, openedViaKeyboard: type !== 'click' }); } } @@ -158,6 +156,18 @@ export default class ComposerOptionsDropdown extends React.PureComponent { }; } + setTargetRef = c => { + this.target = c; + } + + findTarget = () => { + return this.target; + } + + handleOverlayEnter = (state) => { + this.setState({ placement: state.placement }); + } + // Rendering. render () { const { @@ -179,6 +189,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
- + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js index 09e8fc35a..c4895dfd0 100644 --- a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js @@ -1,7 +1,6 @@ // Package imports. import PropTypes from 'prop-types'; import React from 'react'; -import spring from 'react-motion/lib/spring'; import ImmutablePureComponent from 'react-immutable-pure-component'; import classNames from 'classnames'; @@ -10,15 +9,8 @@ import Icon from 'flavours/glitch/components/icon'; // Utils. import { withPassive } from 'flavours/glitch/utils/dom_helpers'; -import Motion from '../../ui/util/optional_motion'; import { assignHandlers } from 'flavours/glitch/utils/react_helpers'; -// The spring to use with our motion. -const springMotion = spring(1, { - damping: 35, - stiffness: 400, -}); - // The component. export default class ComposerOptionsDropdownContent extends React.PureComponent { @@ -44,7 +36,6 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent }; state = { - mounted: false, value: this.props.openedViaKeyboard ? this.props.items[0].name : undefined, }; @@ -56,7 +47,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent } // Stores our node in `this.node`. - handleRef = (node) => { + setRef = (node) => { this.node = node; } @@ -69,7 +60,6 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent } else { this.node.firstChild.focus({ preventScroll: true }); } - this.setState({ mounted: true }); } // On unmounting, we remove our listeners. @@ -191,7 +181,6 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent // Rendering. render () { - const { mounted } = this.state; const { items, onChange, @@ -201,36 +190,9 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent // The result. return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
- {!!items && items.map((item, i) => this.renderItem(item, i))} -
- )} -
+
+ {!!items && items.map((item, i) => this.renderItem(item, i))} +
); } diff --git a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js index 546d398a0..38c735551 100644 --- a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components'; -import Overlay from 'react-overlays/lib/Overlay'; +import Overlay from 'react-overlays/Overlay'; import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { supportsPassiveEvents } from 'detect-passive-events'; @@ -155,9 +155,6 @@ class EmojiPickerMenu extends React.PureComponent { onClose: PropTypes.func.isRequired, onPick: PropTypes.func.isRequired, style: PropTypes.object, - placement: PropTypes.string, - arrowOffsetLeft: PropTypes.string, - arrowOffsetTop: PropTypes.string, intl: PropTypes.object.isRequired, skinTone: PropTypes.number.isRequired, onSkinTone: PropTypes.func.isRequired, @@ -326,14 +323,13 @@ class EmojiPickerDropdown extends React.PureComponent { state = { active: false, loading: false, - placement: null, }; setRef = (c) => { this.dropdown = c; } - onShowDropdown = ({ target }) => { + onShowDropdown = () => { this.setState({ active: true }); if (!EmojiPicker) { @@ -348,9 +344,6 @@ class EmojiPickerDropdown extends React.PureComponent { this.setState({ loading: false, active: false }); }); } - - const { top } = target.getBoundingClientRect(); - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); } onHideDropdown = () => { @@ -384,7 +377,7 @@ class EmojiPickerDropdown extends React.PureComponent { render () { const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis, button } = this.props; const title = intl.formatMessage(messages.emoji); - const { active, loading, placement } = this.state; + const { active, loading } = this.state; return (
@@ -396,16 +389,22 @@ class EmojiPickerDropdown extends React.PureComponent { />}
- - + + {({ props, placement })=> ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js index a3256aa9b..07d138f52 100644 --- a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js +++ b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js @@ -2,9 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { injectIntl, defineMessages } from 'react-intl'; import TextIconButton from './text_icon_button'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from 'flavours/glitch/features/ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import { languages as preloadedLanguages } from 'flavours/glitch/initial_state'; @@ -22,10 +20,8 @@ const listenerOptions = supportsPassiveEvents ? { passive: true } : false; class LanguageDropdownMenu extends React.PureComponent { static propTypes = { - style: PropTypes.object, value: PropTypes.string.isRequired, frequentlyUsedLanguages: PropTypes.arrayOf(PropTypes.string).isRequired, - placement: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, languages: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), @@ -37,7 +33,6 @@ class LanguageDropdownMenu extends React.PureComponent { }; state = { - mounted: false, searchValue: '', }; @@ -50,7 +45,6 @@ class LanguageDropdownMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); - this.setState({ mounted: true }); // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need // to wait for a frame before focusing @@ -222,29 +216,22 @@ class LanguageDropdownMenu extends React.PureComponent { } render () { - const { style, placement, intl } = this.props; - const { mounted, searchValue } = this.state; + const { intl } = this.props; + const { searchValue } = this.state; const isSearching = searchValue !== ''; const results = this.search(); return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
-
- - -
+
+
+ + +
-
- {results.map(this.renderItem)} -
-
- )} - +
+ {results.map(this.renderItem)} +
+
); } @@ -266,14 +253,11 @@ class LanguageDropdown extends React.PureComponent { placement: 'bottom', }; - handleToggle = ({ target }) => { - const { top } = target.getBoundingClientRect(); - + handleToggle = () => { if (this.state.open && this.activeElement) { this.activeElement.focus({ preventScroll: true }); } - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ open: !this.state.open }); } @@ -293,13 +277,25 @@ class LanguageDropdown extends React.PureComponent { onChange(value); } + setTargetRef = c => { + this.target = c; + } + + findTarget = () => { + return this.target; + } + + handleOverlayEnter = (state) => { + this.setState({ placement: state.placement }); + } + render () { const { value, intl, frequentlyUsedLanguages } = this.props; const { open, placement } = this.state; return ( -
-
+
+
- - + + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/flavours/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js index 9f90a767d..e5874de75 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search.js +++ b/app/javascript/flavours/glitch/features/compose/components/search.js @@ -3,13 +3,12 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; -import spring from 'react-motion/lib/spring'; import { injectIntl, FormattedMessage, defineMessages, } from 'react-intl'; -import Overlay from 'react-overlays/lib/Overlay'; +import Overlay from 'react-overlays/Overlay'; // Components. import Icon from 'flavours/glitch/components/icon'; @@ -17,7 +16,6 @@ import Icon from 'flavours/glitch/components/icon'; // Utils. import { focusRoot } from 'flavours/glitch/utils/dom_helpers'; import { searchEnabled } from 'flavours/glitch/initial_state'; -import Motion from '../../ui/util/optional_motion'; const messages = defineMessages({ placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }, @@ -26,31 +24,20 @@ const messages = defineMessages({ class SearchPopout extends React.PureComponent { - static propTypes = { - style: PropTypes.object, - }; - render () { - const { style } = this.props; const extraInformation = searchEnabled ? : ; return ( -
- - {({ opacity, scaleX, scaleY }) => ( -
-

- -
    -
  • #example
  • -
  • @username@domain
  • -
  • URL
  • -
  • URL
  • -
- - {extraInformation} -
- )} -
+
+

+ +
    +
  • #example
  • +
  • @username@domain
  • +
  • URL
  • +
  • URL
  • +
+ + {extraInformation}
); } @@ -136,6 +123,10 @@ class Search extends React.PureComponent { } } + findTarget = () => { + return this.searchForm; + } + render () { const { intl, value, submitted } = this.props; const { expanded } = this.state; @@ -161,8 +152,14 @@ class Search extends React.PureComponent {
- - + + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/flavours/glitch/reducers/dropdown_menu.js b/app/javascript/flavours/glitch/reducers/dropdown_menu.js index a78a11acc..51bf9375b 100644 --- a/app/javascript/flavours/glitch/reducers/dropdown_menu.js +++ b/app/javascript/flavours/glitch/reducers/dropdown_menu.js @@ -4,12 +4,12 @@ import { DROPDOWN_MENU_CLOSE, } from '../actions/dropdown_menu'; -const initialState = Immutable.Map({ openId: null, placement: null, keyboard: false, scroll_key: null }); +const initialState = Immutable.Map({ openId: null, keyboard: false, scroll_key: null }); export default function dropdownMenu(state = initialState, action) { switch (action.type) { case DROPDOWN_MENU_OPEN: - return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard, scroll_key: action.scroll_key }); + return state.merge({ openId: action.id, keyboard: action.keyboard, scroll_key: action.scroll_key }); case DROPDOWN_MENU_CLOSE: return state.get('openId') === action.id ? state.set('openId', null).set('scroll_key', null) : state; default: diff --git a/app/javascript/flavours/glitch/styles/components/compose_form.scss b/app/javascript/flavours/glitch/styles/components/compose_form.scss index 72d3aad1d..aa2d52ed0 100644 --- a/app/javascript/flavours/glitch/styles/components/compose_form.scss +++ b/app/javascript/flavours/glitch/styles/components/compose_form.scss @@ -586,7 +586,6 @@ } .privacy-dropdown__dropdown { - position: absolute; border-radius: 4px; box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); background: $simple-background-color; @@ -653,7 +652,6 @@ .language-dropdown { &__dropdown { - position: absolute; background: $simple-background-color; box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); border-radius: 4px; diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index b7a54cd2b..d50316366 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -346,9 +346,8 @@ } } -.dropdown-menu { - position: absolute; - transform-origin: 50% 0; +body > [data-popper-placement] { + z-index: 3; } .invisible { @@ -532,6 +531,42 @@ } } +.dropdown-animation { + animation: dropdown 300ms cubic-bezier(0.1, 0.7, 0.1, 1); + + @keyframes dropdown { + from { + opacity: 0; + transform: scaleX(0.85) scaleY(0.75); + } + + to { + opacity: 1; + transform: scaleX(1) scaleY(1); + } + } + + &.top { + transform-origin: bottom; + } + + &.right { + transform-origin: left; + } + + &.bottom { + transform-origin: top; + } + + &.left { + transform-origin: right; + } + + .reduce-motion & { + animation: none; + } +} + .dropdown { display: inline-block; } @@ -600,36 +635,42 @@ .dropdown-menu__arrow { position: absolute; - width: 0; - height: 0; - border: 0 solid transparent; - &.left { - right: -5px; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: $ui-secondary-color; + &::before { + content: ''; + display: block; + width: 14px; + height: 5px; + background-color: $ui-secondary-color; + mask-image: url("data:image/svg+xml;utf8,"); } &.top { bottom: -5px; - margin-left: -7px; - border-width: 5px 7px 0; - border-top-color: $ui-secondary-color; + + &::before { + transform: rotate(180deg); + } + } + + &.right { + left: -9px; + + &::before { + transform: rotate(-90deg); + } } &.bottom { top: -5px; - margin-left: -7px; - border-width: 0 7px 5px; - border-bottom-color: $ui-secondary-color; } - &.right { - left: -5px; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: $ui-secondary-color; + &.left { + right: -9px; + + &::before { + transform: rotate(90deg); + } } } diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss index 8ba8bec10..972e01e7d 100644 --- a/app/javascript/flavours/glitch/styles/components/modal.scss +++ b/app/javascript/flavours/glitch/styles/components/modal.scss @@ -37,7 +37,6 @@ .modal-root__modal { pointer-events: auto; display: flex; - z-index: 9999; } .media-modal__zoom-button { diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 9fc1aed2a..2ec2da833 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -285,22 +285,8 @@ html { .dropdown-menu { background: $white; - &__arrow { - &.left { - border-left-color: $white; - } - - &.top { - border-top-color: $white; - } - - &.bottom { - border-bottom-color: $white; - } - - &.right { - border-right-color: $white; - } + &__arrow::before { + background-color: $white; } &__item { -- cgit