Redesign: Update main actions when visiting the profile of someone you follow (#40809)

This commit is contained in:
diondiondion
2026-10-01 16:09:37 +00:00
committed by GitHub
parent 49e75ef4f2
commit eeab59229e
4 changed files with 113 additions and 47 deletions

View File

@@ -1,11 +1,13 @@
import { useCallback } from 'react';
import type { FC } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { BellIcon, BellSlashIcon } from '@phosphor-icons/react';
import { ChatCircleDotsIcon, UserMinusIcon } from '@phosphor-icons/react';
import { followAccount } from '@/mastodon/actions/accounts';
import { directCompose } from '@/mastodon/actions/compose';
import { openModal } from '@/mastodon/actions/modal';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { useFollowReference } from '@/mastodon/hooks/useFollowReference';
import { getAccountHidden } from '@/mastodon/selectors/accounts';
@@ -14,7 +16,7 @@ import { isRedesignEnabled } from '@/mastodon/utils/environment';
import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react';
import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react';
import { ToggleIconButton } from '../button/redesign';
import { Button, IconButton } from '../button/redesign';
import { CopyIconButton, CopyIconButtonLegacy } from '../copy_button';
import { FollowButton } from '../follow_button';
import { IconButton as LegacyIconButton } from '../icon_button';
@@ -71,12 +73,27 @@ const AccountButtonsOther: FC<
);
const dispatch = useAppDispatch();
const handleNotifyToggle = useCallback(() => {
if (account) {
dispatch(followAccount(account.id, { notify: !relationship?.notifying }));
}
}, [dispatch, account, relationship]);
const sendDirectMessage = useCallback(() => {
if (account) {
dispatch(directCompose(account));
}
}, [dispatch, account]);
const confirmUnfollow = useCallback(() => {
if (account) {
dispatch(
openModal({ modalType: 'CONFIRM_UNFOLLOW', modalProps: { account } }),
);
}
}, [dispatch, account]);
const reference = useFollowReference('profile');
if (!account) {
@@ -86,9 +103,11 @@ const AccountButtonsOther: FC<
const isMovedAndUnfollowedAccount = account.moved && !relationship?.following;
const isFollowing = relationship?.requested || relationship?.following;
const shouldHideMainFollowButton = isRedesignEnabled() && isFollowing;
return (
<>
{!isMovedAndUnfollowedAccount && (
{!shouldHideMainFollowButton && !isMovedAndUnfollowedAccount && (
<FollowButton
compact={isRedesignEnabled()}
accountId={accountId}
@@ -98,39 +117,42 @@ const AccountButtonsOther: FC<
reference={reference}
/>
)}
{isFollowing &&
(isRedesignEnabled() ? (
<ToggleIconButton
{isFollowing && isRedesignEnabled() && (
<>
<Button
leadingIcon={ChatCircleDotsIcon}
size='sm'
icon={relationship.notifying ? BellSlashIcon : BellIcon}
active={relationship.notifying}
onClick={handleNotifyToggle}
variant='solid'
color='accent'
onClick={sendDirectMessage}
>
{intl.formatMessage(
relationship.notifying
? messages.disableNotifications
: messages.enableNotifications,
{ name: account.username },
)}
</ToggleIconButton>
) : (
<LegacyIconButton
icon={relationship.notifying ? 'bell' : 'bell-o'}
iconComponent={
relationship.notifying
? NotificationsActiveIcon
: NotificationsIcon
}
active={relationship.notifying}
title={intl.formatMessage(
relationship.notifying
? messages.disableNotifications
: messages.enableNotifications,
{ name: account.username },
)}
onClick={handleNotifyToggle}
/>
))}
<FormattedMessage
id='account.menu.message'
defaultMessage='Message'
description='Message refers to a direct message. For languages where this is confusing, "chat" or "direct message" can be used.'
/>
</Button>
<IconButton icon={UserMinusIcon} size='sm' onClick={confirmUnfollow}>
<FormattedMessage id='account.unfollow' defaultMessage='Unfollow' />
</IconButton>
</>
)}
{isFollowing && !isRedesignEnabled() && (
<LegacyIconButton
icon={relationship.notifying ? 'bell' : 'bell-o'}
iconComponent={
relationship.notifying ? NotificationsActiveIcon : NotificationsIcon
}
active={relationship.notifying}
title={intl.formatMessage(
relationship.notifying
? messages.disableNotifications
: messages.enableNotifications,
{ name: account.username },
)}
onClick={handleNotifyToggle}
/>
)}
{!noShare &&
(isRedesignEnabled() ? (
<CopyIconButton

View File

@@ -221,6 +221,14 @@ const messages = defineMessages({
id: 'status.admin_domain',
defaultMessage: 'Open moderation interface for {domain}',
},
enableNotifications: {
id: 'account.notify_me',
defaultMessage: 'Notify me about new posts',
},
disableNotifications: {
id: 'account.stop_notifying_me',
defaultMessage: 'Stop notifying me about new posts',
},
languages: {
id: 'account.languages',
defaultMessage: 'Change subscribed languages',
@@ -289,17 +297,19 @@ function getMenuItems({
// Mention and direct message options
if (signedIn && !account.suspended) {
items.push(null);
if (!account.invalid_handle) {
if (isRedesignEnabled()) {
items.push({
text: intl.formatMessage(messages.redesignMessage),
action: () => {
dispatch(directCompose(account));
},
});
if (!relationship?.following) {
items.push(null, {
text: intl.formatMessage(messages.redesignMessage),
action: () => {
dispatch(directCompose(account));
},
});
}
} else {
items.push(
null,
{
text: intl.formatMessage(messages.mention),
action: () => {
@@ -400,6 +410,21 @@ function getMenuItems({
// Timeline options
if (relationship?.following && !relationship.muting) {
if (isRedesignEnabled()) {
items.push({
text: intl.formatMessage(
relationship.notifying
? messages.disableNotifications
: messages.enableNotifications,
{ name: account.username },
),
action: () => {
dispatch(
followAccount(account.id, { notify: !relationship.notifying }),
);
},
});
}
items.push(
{
text: intl.formatMessage(

View File

@@ -5,6 +5,9 @@ import { useIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import type { Icon } from '@phosphor-icons/react';
import { UserMinusIcon, UserPlusIcon } from '@phosphor-icons/react';
import { useIdentity } from '@/mastodon/identity_context';
import {
fetchRelationships,
@@ -69,6 +72,7 @@ interface FollowButtonOptions {
interface FollowButtonReturn {
label: React.ReactNode;
icon: Icon | undefined;
onClick: (() => void) | undefined;
link: MastodonLocationDescriptor | undefined;
disabled: boolean;
@@ -163,11 +167,13 @@ export function useFollowButton({
: messages.follow;
let label: React.ReactNode;
let icon: Icon | undefined;
let disabled =
relationship?.blocked_by || account?.suspended || !!account?.moved;
if (!signedIn) {
label = intl.formatMessage(followMessage);
icon = UserPlusIcon;
} else if (accountId === me) {
label = intl.formatMessage(messages.editProfile);
} else if (!relationship) {
@@ -177,6 +183,7 @@ export function useFollowButton({
disabled = false;
} else if (relationship.following) {
label = intl.formatMessage(messages.unfollow);
icon = UserMinusIcon;
disabled = false;
} else if (relationship.blocking) {
label = intl.formatMessage(messages.unblock);
@@ -186,8 +193,10 @@ export function useFollowButton({
disabled = false;
} else if (relationship.followed_by && !account?.locked) {
label = intl.formatMessage(messages.followBack);
icon = UserPlusIcon;
} else {
label = intl.formatMessage(followMessage);
icon = UserPlusIcon;
}
const isMovedAndUnfollowedAccount =
@@ -197,6 +206,7 @@ export function useFollowButton({
onClick,
link,
label,
icon,
disabled,
following,
secondary,
@@ -242,22 +252,28 @@ const FollowButtonRedesign: React.FC<
FollowButtonOptions &
Pick<RedesignButtonProps, 'size' | 'color' | 'className'>
> = ({ accountId, labelLength, withUnmute, reference, ...buttonProps }) => {
const { onClick, link, label, disabled, secondary, hidden } = useFollowButton(
{
const { onClick, link, label, icon, disabled, secondary, hidden } =
useFollowButton({
accountId,
labelLength,
withUnmute,
reference,
},
);
});
if (hidden) {
return null;
}
const leadingIcon = labelLength === 'long' ? icon : undefined;
if (link) {
return (
<RedesignButton as='link' to={link} {...buttonProps}>
<RedesignButton
as='link'
to={link}
leadingIcon={leadingIcon}
{...buttonProps}
>
{label}
</RedesignButton>
);
@@ -266,6 +282,7 @@ const FollowButtonRedesign: React.FC<
return (
<RedesignButton
{...buttonProps}
leadingIcon={leadingIcon}
onClick={onClick}
disabled={disabled}
variant={secondary ? 'tonal' : 'solid'}

View File

@@ -133,12 +133,14 @@
"account.node_modal.title": "Add a personal note",
"account.note.edit_button": "Edit",
"account.note.title": "Personal note (visible only to you)",
"account.notify_me": "Notify me about new posts",
"account.open_original_page": "Open original page",
"account.pending": "Pending",
"account.posts": "Posts",
"account.requested_follow": "{name} has requested to follow you",
"account.share": "Share @{name}'s profile",
"account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} posts}}",
"account.stop_notifying_me": "Stop notifying me about new posts",
"account.timeline.pinned": "Pinned",
"account.timeline.pinned.view_all": "View all pinned posts",
"account.unblock": "Unblock @{name}",