diff --git a/app/javascript/flavours/glitch/components/follow_button.tsx b/app/javascript/flavours/glitch/components/follow_button.tsx
index e574b43b25..7e84a2580e 100644
--- a/app/javascript/flavours/glitch/components/follow_button.tsx
+++ b/app/javascript/flavours/glitch/components/follow_button.tsx
@@ -8,6 +8,8 @@ import { useIdentity } from '@/flavours/glitch/identity_context';
import {
fetchRelationships,
followAccount,
+ unblockAccount,
+ unmuteAccount,
} from 'flavours/glitch/actions/accounts';
import { openModal } from 'flavours/glitch/actions/modal';
import { Button } from 'flavours/glitch/components/button';
@@ -15,17 +17,49 @@ import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
import { me } from 'flavours/glitch/initial_state';
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
-const messages = defineMessages({
+import { useBreakpoint } from '../features/ui/hooks/useBreakpoint';
+
+const longMessages = defineMessages({
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
+ unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' },
+ unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' },
follow: { id: 'account.follow', defaultMessage: 'Follow' },
followBack: { id: 'account.follow_back', defaultMessage: 'Follow back' },
+ followRequest: {
+ id: 'account.follow_request',
+ defaultMessage: 'Request to follow',
+ },
+ followRequestCancel: {
+ id: 'account.follow_request_cancel',
+ defaultMessage: 'Cancel request',
+ },
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
});
+const shortMessages = {
+ ...longMessages, // Align type signature of shortMessages and longMessages
+ ...defineMessages({
+ followBack: {
+ id: 'account.follow_back_short',
+ defaultMessage: 'Follow back',
+ },
+ followRequest: {
+ id: 'account.follow_request_short',
+ defaultMessage: 'Request',
+ },
+ followRequestCancel: {
+ id: 'account.follow_request_cancel_short',
+ defaultMessage: 'Cancel',
+ },
+ editProfile: { id: 'account.edit_profile_short', defaultMessage: 'Edit' },
+ }),
+};
+
export const FollowButton: React.FC<{
accountId?: string;
compact?: boolean;
-}> = ({ accountId, compact }) => {
+ labelLength?: 'auto' | 'short' | 'long';
+}> = ({ accountId, compact, labelLength = 'auto' }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { signedIn } = useIdentity();
@@ -60,29 +94,48 @@ export const FollowButton: React.FC<{
if (accountId === me) {
return;
+ } else if (relationship.muting) {
+ dispatch(unmuteAccount(accountId));
} else if (account && (relationship.following || relationship.requested)) {
dispatch(
openModal({ modalType: 'CONFIRM_UNFOLLOW', modalProps: { account } }),
);
+ } else if (relationship.blocking) {
+ dispatch(unblockAccount(accountId));
} else {
dispatch(followAccount(accountId));
}
}, [dispatch, accountId, relationship, account, signedIn]);
+ const isNarrow = useBreakpoint('narrow');
+ const useShortLabel =
+ labelLength === 'short' || (labelLength === 'auto' && isNarrow);
+ const messages = useShortLabel ? shortMessages : longMessages;
+
+ const followMessage = account?.locked
+ ? messages.followRequest
+ : messages.follow;
+
let label;
if (!signedIn) {
- label = intl.formatMessage(messages.follow);
+ label = intl.formatMessage(followMessage);
} else if (accountId === me) {
label = intl.formatMessage(messages.edit_profile);
} else if (!relationship) {
label = ;
- } else if (relationship.following || relationship.requested) {
+ } else if (relationship.muting) {
+ label = intl.formatMessage(messages.unmute);
+ } else if (relationship.following) {
label = intl.formatMessage(messages.unfollow);
- } else if (relationship.followed_by) {
+ } else if (relationship.blocking) {
+ label = intl.formatMessage(messages.unblock);
+ } else if (relationship.requested) {
+ label = intl.formatMessage(messages.followRequestCancel);
+ } else if (relationship.followed_by && !account?.locked) {
label = intl.formatMessage(messages.followBack);
} else {
- label = intl.formatMessage(messages.follow);
+ label = intl.formatMessage(followMessage);
}
if (accountId === me) {
diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.tsx b/app/javascript/flavours/glitch/features/directory/components/account_card.tsx
index deb4f4832d..b07928573e 100644
--- a/app/javascript/flavours/glitch/features/directory/components/account_card.tsx
+++ b/app/javascript/flavours/glitch/features/directory/components/account_card.tsx
@@ -1,134 +1,22 @@
-import { useCallback } from 'react';
+import { FormattedMessage } from 'react-intl';
-import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
-
-import classNames from 'classnames';
-
-import {
- followAccount,
- unblockAccount,
- unmuteAccount,
-} from 'flavours/glitch/actions/accounts';
-import { openModal } from 'flavours/glitch/actions/modal';
import { Avatar } from 'flavours/glitch/components/avatar';
-import { Button } from 'flavours/glitch/components/button';
import { DisplayName } from 'flavours/glitch/components/display_name';
+import { FollowButton } from 'flavours/glitch/components/follow_button';
import { Permalink } from 'flavours/glitch/components/permalink';
import { ShortNumber } from 'flavours/glitch/components/short_number';
-import { autoPlayGif, me } from 'flavours/glitch/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
import type { Account } from 'flavours/glitch/models/account';
import { makeGetAccount } from 'flavours/glitch/selectors';
-import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
-
-const messages = defineMessages({
- unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
- follow: { id: 'account.follow', defaultMessage: 'Follow' },
- cancel_follow_request: {
- id: 'account.cancel_follow_request',
- defaultMessage: 'Withdraw follow request',
- },
- requested: {
- id: 'account.requested',
- defaultMessage: 'Awaiting approval. Click to cancel follow request',
- },
- unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' },
- unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' },
- edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
-});
+import { useAppSelector } from 'flavours/glitch/store';
const getAccount = makeGetAccount();
export const AccountCard: React.FC<{ accountId: string }> = ({ accountId }) => {
- const intl = useIntl();
const account = useAppSelector((s) => getAccount(s, accountId));
- const dispatch = useAppDispatch();
-
- const handleFollow = useCallback(() => {
- if (!account) return;
-
- if (
- account.getIn(['relationship', 'following']) ||
- account.getIn(['relationship', 'requested'])
- ) {
- dispatch(
- openModal({ modalType: 'CONFIRM_UNFOLLOW', modalProps: { account } }),
- );
- } else {
- dispatch(followAccount(account.get('id')));
- }
- }, [account, dispatch]);
-
- const handleBlock = useCallback(() => {
- if (account?.relationship?.blocking) {
- dispatch(unblockAccount(account.get('id')));
- }
- }, [account, dispatch]);
-
- const handleMute = useCallback(() => {
- if (account?.relationship?.muting) {
- dispatch(unmuteAccount(account.get('id')));
- }
- }, [account, dispatch]);
-
- const handleEditProfile = useCallback(() => {
- window.open('/settings/profile', '_blank');
- }, []);
if (!account) return null;
- let actionBtn;
-
- if (me !== account.get('id')) {
- if (!account.get('relationship')) {
- // Wait until the relationship is loaded
- actionBtn = '';
- } else if (account.getIn(['relationship', 'requested'])) {
- actionBtn = (
-
- );
- } else if (account.getIn(['relationship', 'muting'])) {
- actionBtn = (
-
- );
- } else if (!account.getIn(['relationship', 'blocking'])) {
- actionBtn = (
-
- );
- } else if (account.getIn(['relationship', 'blocking'])) {
- actionBtn = (
-
- );
- }
- } else {
- actionBtn = (
-
- );
- }
-
return (
- {actionBtn}
+
+
+
);
diff --git a/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.tsx b/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.tsx
index e5aa8d0297..bcbb0962fb 100644
--- a/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.tsx
+++ b/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.tsx
@@ -25,8 +25,6 @@ import { domain } from 'flavours/glitch/initial_state';
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
const messages = defineMessages({
- follow: { id: 'account.follow', defaultMessage: 'Follow' },
- unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
next: { id: 'lightbox.next', defaultMessage: 'Next' },
dismiss: {
diff --git a/app/javascript/flavours/glitch/features/ui/hooks/useBreakpoint.tsx b/app/javascript/flavours/glitch/features/ui/hooks/useBreakpoint.tsx
index af96ab3766..cb7b3551f2 100644
--- a/app/javascript/flavours/glitch/features/ui/hooks/useBreakpoint.tsx
+++ b/app/javascript/flavours/glitch/features/ui/hooks/useBreakpoint.tsx
@@ -1,11 +1,12 @@
import { useState, useEffect } from 'react';
const breakpoints = {
+ narrow: 479, // Device width under which horizontal space is constrained
openable: 759, // Device width at which the sidebar becomes an openable hamburger menu
full: 1174, // Device width at which all 3 columns can be displayed
};
-type Breakpoint = 'openable' | 'full';
+type Breakpoint = keyof typeof breakpoints;
export const useBreakpoint = (breakpoint: Breakpoint) => {
const [isMatching, setIsMatching] = useState(false);