Profile redesign: Simplify header for follower/following lists (#38366)
This commit is contained in:
parent
5ba5a2e552
commit
000199f003
@ -0,0 +1,36 @@
|
|||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
import type { MessageDescriptor } from 'react-intl';
|
||||||
|
|
||||||
|
import { DisplayNameSimple } from '@/mastodon/components/display_name/simple';
|
||||||
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
|
|
||||||
|
import classes from '../styles.module.scss';
|
||||||
|
|
||||||
|
export const AccountListHeader: FC<{
|
||||||
|
accountId: string;
|
||||||
|
total?: number;
|
||||||
|
titleText: MessageDescriptor;
|
||||||
|
}> = ({ accountId, total, titleText }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const account = useAccount(accountId);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className={classes.title}>
|
||||||
|
{intl.formatMessage(titleText, {
|
||||||
|
name: <DisplayNameSimple account={account} />,
|
||||||
|
})}
|
||||||
|
</h1>
|
||||||
|
{!!total && (
|
||||||
|
<h2 className={classes.subtitle}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account_list.total'
|
||||||
|
defaultMessage='{total, plural, one {# account} other {# accounts}}'
|
||||||
|
values={{ total }}
|
||||||
|
/>
|
||||||
|
</h2>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -11,8 +11,6 @@ import { useAccount } from '@/mastodon/hooks/useAccount';
|
|||||||
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
||||||
import { useLayout } from '@/mastodon/hooks/useLayout';
|
import { useLayout } from '@/mastodon/hooks/useLayout';
|
||||||
|
|
||||||
import { AccountHeader } from '../../account_timeline/components/account_header';
|
|
||||||
|
|
||||||
import { RemoteHint } from './remote';
|
import { RemoteHint } from './remote';
|
||||||
|
|
||||||
export interface AccountList {
|
export interface AccountList {
|
||||||
@ -25,6 +23,7 @@ interface AccountListProps {
|
|||||||
accountId?: string | null;
|
accountId?: string | null;
|
||||||
append?: ReactNode;
|
append?: ReactNode;
|
||||||
emptyMessage: ReactNode;
|
emptyMessage: ReactNode;
|
||||||
|
header?: ReactNode;
|
||||||
footer?: ReactNode;
|
footer?: ReactNode;
|
||||||
list?: AccountList | null;
|
list?: AccountList | null;
|
||||||
loadMore: () => void;
|
loadMore: () => void;
|
||||||
@ -36,6 +35,7 @@ export const AccountList: FC<AccountListProps> = ({
|
|||||||
accountId,
|
accountId,
|
||||||
append,
|
append,
|
||||||
emptyMessage,
|
emptyMessage,
|
||||||
|
header,
|
||||||
footer,
|
footer,
|
||||||
list,
|
list,
|
||||||
loadMore,
|
loadMore,
|
||||||
@ -90,7 +90,7 @@ export const AccountList: FC<AccountListProps> = ({
|
|||||||
hasMore={!forceEmptyState && list?.hasMore}
|
hasMore={!forceEmptyState && list?.hasMore}
|
||||||
isLoading={list?.isLoading ?? true}
|
isLoading={list?.isLoading ?? true}
|
||||||
onLoadMore={loadMore}
|
onLoadMore={loadMore}
|
||||||
prepend={<AccountHeader accountId={accountId} hideTabs />}
|
prepend={header}
|
||||||
alwaysPrepend
|
alwaysPrepend
|
||||||
append={append ?? <RemoteHint domain={domain} url={account.url} />}
|
append={append ?? <RemoteHint domain={domain} url={account.url} />}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessage, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
|
||||||
@ -14,8 +14,14 @@ import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
|||||||
|
|
||||||
import type { EmptyMessageProps } from './components/empty';
|
import type { EmptyMessageProps } from './components/empty';
|
||||||
import { BaseEmptyMessage } from './components/empty';
|
import { BaseEmptyMessage } from './components/empty';
|
||||||
|
import { AccountListHeader } from './components/header';
|
||||||
import { AccountList } from './components/list';
|
import { AccountList } from './components/list';
|
||||||
|
|
||||||
|
const titleText = defineMessage({
|
||||||
|
id: 'followers.title',
|
||||||
|
defaultMessage: 'Following {name}',
|
||||||
|
});
|
||||||
|
|
||||||
const Followers: FC = () => {
|
const Followers: FC = () => {
|
||||||
const accountId = useAccountId();
|
const accountId = useAccountId();
|
||||||
const account = useAccount(accountId);
|
const account = useAccount(accountId);
|
||||||
@ -64,6 +70,15 @@ const Followers: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<AccountList
|
<AccountList
|
||||||
accountId={accountId}
|
accountId={accountId}
|
||||||
|
header={
|
||||||
|
accountId && (
|
||||||
|
<AccountListHeader
|
||||||
|
accountId={accountId}
|
||||||
|
titleText={titleText}
|
||||||
|
total={account?.followers_count}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
footer={footer}
|
footer={footer}
|
||||||
emptyMessage={<EmptyMessage account={account} />}
|
emptyMessage={<EmptyMessage account={account} />}
|
||||||
list={followerList}
|
list={followerList}
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 20px 16px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin: 10px 16px;
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessage, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
|
||||||
@ -14,10 +14,16 @@ import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
|||||||
|
|
||||||
import type { EmptyMessageProps } from '../followers/components/empty';
|
import type { EmptyMessageProps } from '../followers/components/empty';
|
||||||
import { BaseEmptyMessage } from '../followers/components/empty';
|
import { BaseEmptyMessage } from '../followers/components/empty';
|
||||||
|
import { AccountListHeader } from '../followers/components/header';
|
||||||
import { AccountList } from '../followers/components/list';
|
import { AccountList } from '../followers/components/list';
|
||||||
|
|
||||||
import { RemoteHint } from './components/remote';
|
import { RemoteHint } from './components/remote';
|
||||||
|
|
||||||
|
const titleText = defineMessage({
|
||||||
|
id: 'following.title',
|
||||||
|
defaultMessage: 'Followed by {name}',
|
||||||
|
});
|
||||||
|
|
||||||
const Followers: FC = () => {
|
const Followers: FC = () => {
|
||||||
const accountId = useAccountId();
|
const accountId = useAccountId();
|
||||||
const account = useAccount(accountId);
|
const account = useAccount(accountId);
|
||||||
@ -69,6 +75,15 @@ const Followers: FC = () => {
|
|||||||
accountId={accountId}
|
accountId={accountId}
|
||||||
append={domain && <RemoteHint domain={domain} url={account.url} />}
|
append={domain && <RemoteHint domain={domain} url={account.url} />}
|
||||||
emptyMessage={<EmptyMessage account={account} />}
|
emptyMessage={<EmptyMessage account={account} />}
|
||||||
|
header={
|
||||||
|
accountId && (
|
||||||
|
<AccountListHeader
|
||||||
|
accountId={accountId}
|
||||||
|
titleText={titleText}
|
||||||
|
total={account?.following_count}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
footer={footer}
|
footer={footer}
|
||||||
list={followingList}
|
list={followingList}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
|
|||||||
@ -234,6 +234,7 @@
|
|||||||
"account_edit_tags.search_placeholder": "Enter a hashtag…",
|
"account_edit_tags.search_placeholder": "Enter a hashtag…",
|
||||||
"account_edit_tags.suggestions": "Suggestions:",
|
"account_edit_tags.suggestions": "Suggestions:",
|
||||||
"account_edit_tags.tag_status_count": "{count, plural, one {# post} other {# posts}}",
|
"account_edit_tags.tag_status_count": "{count, plural, one {# post} other {# posts}}",
|
||||||
|
"account_list.total": "{total, plural, one {# account} other {# accounts}}",
|
||||||
"account_note.placeholder": "Click to add note",
|
"account_note.placeholder": "Click to add note",
|
||||||
"admin.dashboard.daily_retention": "User retention rate by day after sign-up",
|
"admin.dashboard.daily_retention": "User retention rate by day after sign-up",
|
||||||
"admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
|
"admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
|
||||||
@ -674,7 +675,9 @@
|
|||||||
"follow_suggestions.who_to_follow": "Who to follow",
|
"follow_suggestions.who_to_follow": "Who to follow",
|
||||||
"followed_tags": "Followed hashtags",
|
"followed_tags": "Followed hashtags",
|
||||||
"followers.hide_other_followers": "This user has chosen to not make their other followers visible",
|
"followers.hide_other_followers": "This user has chosen to not make their other followers visible",
|
||||||
|
"followers.title": "Following {name}",
|
||||||
"following.hide_other_following": "This user has chosen to not make the rest of who they follow visible",
|
"following.hide_other_following": "This user has chosen to not make the rest of who they follow visible",
|
||||||
|
"following.title": "Followed by {name}",
|
||||||
"footer.about": "About",
|
"footer.about": "About",
|
||||||
"footer.about_mastodon": "About Mastodon",
|
"footer.about_mastodon": "About Mastodon",
|
||||||
"footer.about_server": "About {domain}",
|
"footer.about_server": "About {domain}",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user