summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2024-04-24 04:52:29 +0200
committerEugen Rochko <eugen@zeonfederated.com>2024-04-24 04:52:29 +0200
commitb2cca3f711547d2d57f3b200d6d54570370d868f (patch)
tree11b61f7a36e9ea5eb83f2e7097c971c5a114b882
parent3f6887557b23d363e7f8f18518db4447739d64bb (diff)
Change mute options to be in dropdown on muted users list in web UIfix-mute-buttons
-rw-r--r--app/javascript/mastodon/components/account.jsx272
-rw-r--r--app/javascript/styles/mastodon/components.scss14
2 files changed, 150 insertions, 136 deletions
diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx
index 4a99dd0bbf1..3282696d341 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 {
-
- 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,
- };
-
- static defaultProps = {
- size: 46,
- };
-
- handleFollow = () => {
- this.props.onFollow(this.props.account);
- };
-
- handleBlock = () => {
- this.props.onBlock(this.props.account);
- };
-
- handleMute = () => {
- this.props.onMute(this.props.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 <EmptyAccount size={size} minimal={minimal} />;
- }
+const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifications, hidden, minimal, defaultAction, withBio }) => {
+ const intl = useIntl();
- if (hidden) {
- return (
- <>
- {account.get('display_name')}
- {account.get('username')}
- </>
- );
- }
+ const handleFollow = useCallback(() => {
+ onFollow(account);
+ }, [onFollow, account]);
+
+ const handleBlock = useCallback(() => {
+ onBlock(account);
+ }, [onBlock, account]);
+
+ const handleMute = useCallback(() => {
+ onMute(account);
+ }, [onMute, account]);
+
+ const handleMuteNotifications = useCallback(() => {
+ onMuteNotifications(account, true);
+ }, [onMuteNotifications, account]);
+
+ const handleUnmuteNotifications = useCallback(() => {
+ onMuteNotifications(account, false);
+ }, [onMuteNotifications, account]);
+
+ if (!account) {
+ return <EmptyAccount size={size} minimal={minimal} />;
+ }
+
+ 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 = <Button text={intl.formatMessage(messages.cancel_follow_request)} onClick={this.handleFollow} />;
- } else if (blocking) {
- buttons = <Button text={intl.formatMessage(messages.unblock)} onClick={this.handleBlock} />;
- } else if (muting) {
- let hidingNotificationsButton;
-
- if (account.getIn(['relationship', 'muting_notifications'])) {
- hidingNotificationsButton = <Button text={intl.formatMessage(messages.unmute_notifications)} onClick={this.handleUnmuteNotifications} />;
- } else {
- hidingNotificationsButton = <Button text={intl.formatMessage(messages.mute_notifications)} onClick={this.handleMuteNotifications} />;
- }
-
- buttons = (
- <>
- <Button text={intl.formatMessage(messages.unmute)} onClick={this.handleMute} />
- {hidingNotificationsButton}
- </>
- );
- } else if (defaultAction === 'mute') {
- buttons = <Button title={intl.formatMessage(messages.mute)} onClick={this.handleMute} />;
- } else if (defaultAction === 'block') {
- buttons = <Button text={intl.formatMessage(messages.block)} onClick={this.handleBlock} />;
- } else if (!account.get('suspended') && !account.get('moved') || following) {
- buttons = <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} />;
+ 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 = <Button text={intl.formatMessage(messages.cancel_follow_request)} onClick={handleFollow} />;
+ } else if (blocking) {
+ buttons = <Button text={intl.formatMessage(messages.unblock)} onClick={handleBlock} />;
+ } 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 }];
}
- }
- let muteTimeRemaining;
+ buttons = (
+ <>
+ <DropdownMenuContainer
+ items={menu}
+ icon='ellipsis-h'
+ iconComponent={MoreHorizIcon}
+ direction='right'
+ title={intl.formatMessage(messages.more)}
+ />
- if (account.get('mute_expires_at')) {
- muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
+ <Button text={intl.formatMessage(messages.unmute)} onClick={handleMute} />
+ </>
+ );
+ } else if (defaultAction === 'mute') {
+ buttons = <Button title={intl.formatMessage(messages.mute)} onClick={handleMute} />;
+ } else if (defaultAction === 'block') {
+ buttons = <Button text={intl.formatMessage(messages.block)} onClick={handleBlock} />;
+ } else if (!account.get('suspended') && !account.get('moved') || following) {
+ buttons = <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={handleFollow} />;
}
+ }
+
+ let muteTimeRemaining;
- let verification;
+ if (account.get('mute_expires_at')) {
+ muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
+ }
- const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
+ let verification;
- if (firstVerifiedField) {
- verification = <VerifiedBadge link={firstVerifiedField.get('value')} />;
- }
+ const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
- return (
- <div className={classNames('account', { 'account--minimal': minimal })}>
- <div className='account__wrapper'>
- <Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
- <div className='account__avatar-wrapper'>
- <Avatar account={account} size={size} />
- </div>
-
- <div className='account__contents'>
- <DisplayName account={account} />
- {!minimal && (
- <div className='account__details'>
- <ShortNumber value={account.get('followers_count')} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
- </div>
- )}
- </div>
- </Link>
-
- {!minimal && (
- <div className='account__relationship'>
- {buttons}
- </div>
- )}
- </div>
-
- {withBio && (account.get('note').length > 0 ? (
- <div
- className='account__note translate'
- dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
- />
- ) : (
- <div className='account__note account__note--missing'><FormattedMessage id='account.no_bio' defaultMessage='No description provided.' /></div>
- ))}
- </div>
- );
+ if (firstVerifiedField) {
+ verification = <VerifiedBadge link={firstVerifiedField.get('value')} />;
}
-}
+ return (
+ <div className={classNames('account', { 'account--minimal': minimal })}>
+ <div className='account__wrapper'>
+ <Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
+ <div className='account__avatar-wrapper'>
+ <Avatar account={account} size={size} />
+ </div>
+
+ <div className='account__contents'>
+ <DisplayName account={account} />
+ {!minimal && (
+ <div className='account__details'>
+ <ShortNumber value={account.get('followers_count')} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
+ </div>
+ )}
+ </div>
+ </Link>
+
+ {!minimal && (
+ <div className='account__relationship'>
+ {buttons}
+ </div>
+ )}
+ </div>
-export default injectIntl(Account);
+ {withBio && (account.get('note').length > 0 ? (
+ <div
+ className='account__note translate'
+ dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
+ />
+ ) : (
+ <div className='account__note account__note--missing'><FormattedMessage id='account.no_bio' defaultMessage='No description provided.' /></div>
+ ))}
+ </div>
+ );
+};
+
+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 87e13ee45e2..b2139169a59 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 {