diff --git a/app/javascript/mastodon/components/counters.tsx b/app/javascript/mastodon/components/counters.tsx index 151b25a3f7..8b14d2a822 100644 --- a/app/javascript/mastodon/components/counters.tsx +++ b/app/javascript/mastodon/components/counters.tsx @@ -43,3 +43,17 @@ export const FollowersCounter = ( }} /> ); + +export const FollowersYouKnowCounter = ( + displayNumber: React.ReactNode, + pluralReady: number, +) => ( + {displayNumber}, + }} + /> +); diff --git a/app/javascript/mastodon/components/hover_card_account.tsx b/app/javascript/mastodon/components/hover_card_account.tsx index 05033e4ac7..12b74823b5 100644 --- a/app/javascript/mastodon/components/hover_card_account.tsx +++ b/app/javascript/mastodon/components/hover_card_account.tsx @@ -9,11 +9,16 @@ import { fetchAccount } from 'mastodon/actions/accounts'; import { AccountBio } from 'mastodon/components/account_bio'; import { AccountFields } from 'mastodon/components/account_fields'; import { Avatar } from 'mastodon/components/avatar'; -import { FollowersCounter } from 'mastodon/components/counters'; +import { AvatarGroup } from 'mastodon/components/avatar_group'; +import { + FollowersCounter, + FollowersYouKnowCounter, +} from 'mastodon/components/counters'; import { DisplayName } from 'mastodon/components/display_name'; import { FollowButton } from 'mastodon/components/follow_button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { ShortNumber } from 'mastodon/components/short_number'; +import { useFetchFamiliarFollowers } from 'mastodon/features/account_timeline/hooks/familiar_followers'; import { domain } from 'mastodon/initial_state'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; @@ -38,6 +43,8 @@ export const HoverCardAccount = forwardRef< } }, [dispatch, accountId, account]); + const { familiarFollowers } = useFetchFamiliarFollowers({ accountId }); + return (
-
+
+ {familiarFollowers.length > 0 && ( + <> + · +
+ + + {familiarFollowers.slice(0, 3).map((account) => ( + + ))} + +
+ + )}
diff --git a/app/javascript/mastodon/features/account_timeline/components/familiar_followers.tsx b/app/javascript/mastodon/features/account_timeline/components/familiar_followers.tsx index fd6e1d5dfd..41bd8ab4ba 100644 --- a/app/javascript/mastodon/features/account_timeline/components/familiar_followers.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/familiar_followers.tsx @@ -1,15 +1,12 @@ -import { useEffect } from 'react'; - import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; -import { fetchAccountsFamiliarFollowers } from '@/mastodon/actions/accounts_familiar_followers'; import { Avatar } from '@/mastodon/components/avatar'; import { AvatarGroup } from '@/mastodon/components/avatar_group'; import type { Account } from '@/mastodon/models/account'; -import { getAccountFamiliarFollowers } from '@/mastodon/selectors/accounts'; -import { useAppDispatch, useAppSelector } from '@/mastodon/store'; + +import { useFetchFamiliarFollowers } from '../hooks/familiar_followers'; const AccountLink: React.FC<{ account?: Account }> = ({ account }) => { if (!account) { @@ -64,20 +61,11 @@ const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({ export const FamiliarFollowers: React.FC<{ accountId: string }> = ({ accountId, }) => { - const dispatch = useAppDispatch(); - const familiarFollowers = useAppSelector((state) => - getAccountFamiliarFollowers(state, accountId), - ); + const { familiarFollowers, isLoading } = useFetchFamiliarFollowers({ + accountId, + }); - const hasNoData = familiarFollowers === null; - - useEffect(() => { - if (hasNoData) { - void dispatch(fetchAccountsFamiliarFollowers({ id: accountId })); - } - }, [dispatch, accountId, hasNoData]); - - if (hasNoData || familiarFollowers.length === 0) { + if (isLoading || familiarFollowers.length === 0) { return null; } diff --git a/app/javascript/mastodon/features/account_timeline/hooks/familiar_followers.ts b/app/javascript/mastodon/features/account_timeline/hooks/familiar_followers.ts new file mode 100644 index 0000000000..d8c566ad86 --- /dev/null +++ b/app/javascript/mastodon/features/account_timeline/hooks/familiar_followers.ts @@ -0,0 +1,30 @@ +import { useEffect } from 'react'; + +import { fetchAccountsFamiliarFollowers } from '@/mastodon/actions/accounts_familiar_followers'; +import { getAccountFamiliarFollowers } from '@/mastodon/selectors/accounts'; +import { useAppDispatch, useAppSelector } from '@/mastodon/store'; +import { me } from 'mastodon/initial_state'; + +export const useFetchFamiliarFollowers = ({ + accountId, +}: { + accountId?: string; +}) => { + const dispatch = useAppDispatch(); + const familiarFollowers = useAppSelector((state) => + accountId ? getAccountFamiliarFollowers(state, accountId) : null, + ); + + const hasNoData = familiarFollowers === null; + + useEffect(() => { + if (hasNoData && accountId && accountId !== me) { + void dispatch(fetchAccountsFamiliarFollowers({ id: accountId })); + } + }, [dispatch, accountId, hasNoData]); + + return { + familiarFollowers: hasNoData ? [] : familiarFollowers, + isLoading: hasNoData, + }; +}; diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 9882691a20..7b359572e6 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -42,6 +42,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} follower} other {{counter} followers}}", + "account.followers_you_know_counter": "{counter} you know", "account.following": "Following", "account.following_counter": "{count, plural, one {{counter} following} other {{counter} following}}", "account.follows.empty": "This user doesn't follow anyone yet.", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 9c38f5685b..e2ef9af530 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -10745,7 +10745,15 @@ noscript { color: inherit; } - &__number { + &__numbers, + &__familiar-followers { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 10px; + } + + &__numbers { font-size: 15px; line-height: 22px; color: $secondary-text-color;