diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx
index 4a99dd0bbf..3282696d34 100644
--- a/app/javascript/mastodon/components/account.jsx
+++ b/app/javascript/mastodon/components/account.jsx
@@ -1,17 +1,19 @@
import PropTypes from 'prop-types';
+import { useCallback } from 'react';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
+import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { EmptyAccount } from 'mastodon/components/empty_account';
import { ShortNumber } from 'mastodon/components/short_number';
import { VerifiedBadge } from 'mastodon/components/verified_badge';
+import DropdownMenuContainer from '../containers/dropdown_menu_container';
import { me } from '../initial_state';
import { Avatar } from './avatar';
@@ -30,151 +32,151 @@ const messages = defineMessages({
unmute_notifications: { id: 'account.unmute_notifications_short', defaultMessage: 'Unmute notifications' },
mute: { id: 'account.mute_short', defaultMessage: 'Mute' },
block: { id: 'account.block_short', defaultMessage: 'Block' },
+ more: { id: 'status.more', defaultMessage: 'More' },
});
-class Account extends ImmutablePureComponent {
+const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifications, hidden, minimal, defaultAction, withBio }) => {
+ const intl = useIntl();
- static propTypes = {
- size: PropTypes.number,
- account: ImmutablePropTypes.record,
- onFollow: PropTypes.func,
- onBlock: PropTypes.func,
- onMute: PropTypes.func,
- onMuteNotifications: PropTypes.func,
- intl: PropTypes.object.isRequired,
- hidden: PropTypes.bool,
- minimal: PropTypes.bool,
- defaultAction: PropTypes.string,
- withBio: PropTypes.bool,
- };
+ const handleFollow = useCallback(() => {
+ onFollow(account);
+ }, [onFollow, account]);
- static defaultProps = {
- size: 46,
- };
+ const handleBlock = useCallback(() => {
+ onBlock(account);
+ }, [onBlock, account]);
- handleFollow = () => {
- this.props.onFollow(this.props.account);
- };
+ const handleMute = useCallback(() => {
+ onMute(account);
+ }, [onMute, account]);
- handleBlock = () => {
- this.props.onBlock(this.props.account);
- };
+ const handleMuteNotifications = useCallback(() => {
+ onMuteNotifications(account, true);
+ }, [onMuteNotifications, account]);
- handleMute = () => {
- this.props.onMute(this.props.account);
- };
+ const handleUnmuteNotifications = useCallback(() => {
+ onMuteNotifications(account, false);
+ }, [onMuteNotifications, account]);
- handleMuteNotifications = () => {
- this.props.onMuteNotifications(this.props.account, true);
- };
-
- handleUnmuteNotifications = () => {
- this.props.onMuteNotifications(this.props.account, false);
- };
-
- render () {
- const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props;
-
- if (!account) {
- return ;
- }
-
- if (hidden) {
- return (
- <>
- {account.get('display_name')}
- {account.get('username')}
- >
- );
- }
-
- let buttons;
-
- if (account.get('id') !== me && account.get('relationship', null) !== null) {
- const following = account.getIn(['relationship', 'following']);
- const requested = account.getIn(['relationship', 'requested']);
- const blocking = account.getIn(['relationship', 'blocking']);
- const muting = account.getIn(['relationship', 'muting']);
-
- if (requested) {
- buttons = ;
- } else if (blocking) {
- buttons = ;
- } else if (muting) {
- let hidingNotificationsButton;
-
- if (account.getIn(['relationship', 'muting_notifications'])) {
- hidingNotificationsButton = ;
- } else {
- hidingNotificationsButton = ;
- }
-
- buttons = (
- <>
-
- {hidingNotificationsButton}
- >
- );
- } else if (defaultAction === 'mute') {
- buttons = ;
- } else if (defaultAction === 'block') {
- buttons = ;
- } else if (!account.get('suspended') && !account.get('moved') || following) {
- buttons = ;
- }
- }
-
- let muteTimeRemaining;
-
- if (account.get('mute_expires_at')) {
- muteTimeRemaining = <>· >;
- }
-
- let verification;
-
- const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
-
- if (firstVerifiedField) {
- verification = ;
- }
+ if (!account) {
+ return ;
+ }
+ if (hidden) {
return (
-
-
-
-
-
-
-
- {!minimal && (
-
- {verification} {muteTimeRemaining}
-
- )}
-
-
-
- {!minimal && (
-
- {buttons}
-
- )}
-
-
- {withBio && (account.get('note').length > 0 ? (
-
- ) : (
-
- ))}
-
+ <>
+ {account.get('display_name')}
+ {account.get('username')}
+ >
);
}
-}
+ let buttons;
-export default injectIntl(Account);
+ if (account.get('id') !== me && account.get('relationship', null) !== null) {
+ const following = account.getIn(['relationship', 'following']);
+ const requested = account.getIn(['relationship', 'requested']);
+ const blocking = account.getIn(['relationship', 'blocking']);
+ const muting = account.getIn(['relationship', 'muting']);
+
+ if (requested) {
+ buttons = ;
+ } else if (blocking) {
+ buttons = ;
+ } else if (muting) {
+ let menu;
+
+ if (account.getIn(['relationship', 'muting_notifications'])) {
+ menu = [{ text: intl.formatMessage(messages.unmute_notifications), action: handleUnmuteNotifications }];
+ } else {
+ menu = [{ text: intl.formatMessage(messages.mute_notifications), action: handleMuteNotifications }];
+ }
+
+ buttons = (
+ <>
+
+
+
+ >
+ );
+ } else if (defaultAction === 'mute') {
+ buttons = ;
+ } else if (defaultAction === 'block') {
+ buttons = ;
+ } else if (!account.get('suspended') && !account.get('moved') || following) {
+ buttons = ;
+ }
+ }
+
+ let muteTimeRemaining;
+
+ if (account.get('mute_expires_at')) {
+ muteTimeRemaining = <>· >;
+ }
+
+ let verification;
+
+ const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
+
+ if (firstVerifiedField) {
+ verification = ;
+ }
+
+ return (
+
+
+
+
+
+
+
+ {!minimal && (
+
+ {verification} {muteTimeRemaining}
+
+ )}
+
+
+
+ {!minimal && (
+
+ {buttons}
+
+ )}
+
+
+ {withBio && (account.get('note').length > 0 ? (
+
+ ) : (
+
+ ))}
+
+ );
+};
+
+Account.propTypes = {
+ size: PropTypes.number,
+ account: ImmutablePropTypes.record,
+ onFollow: PropTypes.func,
+ onBlock: PropTypes.func,
+ onMute: PropTypes.func,
+ onMuteNotifications: PropTypes.func,
+ intl: PropTypes.object.isRequired,
+ hidden: PropTypes.bool,
+ minimal: PropTypes.bool,
+ defaultAction: PropTypes.string,
+ withBio: PropTypes.bool,
+};
+
+export default Account;
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 87e13ee45e..b2139169a5 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2015,7 +2015,19 @@ a .account__avatar {
white-space: nowrap;
display: flex;
align-items: center;
- gap: 4px;
+ gap: 8px;
+
+ .icon-button {
+ border: 1px solid var(--background-border-color);
+ border-radius: 4px;
+ box-sizing: content-box;
+ padding: 5px;
+
+ .icon {
+ width: 24px;
+ height: 24px;
+ }
+ }
}
.account-authorize {