Merge commit '6c743831aab13a39f2020827f20933a51bc7cbc2' into glitch-soc/merge-upstream

This commit is contained in:
Claire committed 2025-05-15 18:52:02 +02:00
commit 0fda1f0e94
70 files changed
+537 -183

No files matched your search

@@ -912,6 +912,10 @@ export const AccountHeader: React.FC<{
<div className='account__header__badges'>{badges}</div>
)}
{account.id !== me && signedIn && (
<FamiliarFollowers accountId={accountId} />
)}
{!(suspended || hidden) && (
<div className='account__header__extra'>
<div
@@ -1023,7 +1027,6 @@ export const AccountHeader: React.FC<{
/>
</NavLink>
</div>
{signedIn && <FamiliarFollowers accountId={accountId} />}
</div>
)}
</div>
@@ -5,16 +5,25 @@ 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';
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => (
<Link to={`/@${account?.username}`} data-hover-card-account={account?.id}>
{account?.display_name}
</Link>
);
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => {
if (!account) {
return null;
}
return (
<Link
to={`/@${account.acct}`}
data-hover-card-account={account.id}
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
/>
);
};
const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
familiarFollowers,
@@ -45,7 +54,7 @@ const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
return (
<FormattedMessage
id='account.familiar_followers_many'
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {# other} other {# others}}'
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}'
values={messageData}
/>
);
@@ -74,10 +83,11 @@ export const FamiliarFollowers: React.FC<{ accountId: string }> = ({
return (
<div className='account__header__familiar-followers'>
<AvatarGroup
compact
accountIds={familiarFollowers.slice(0, 3).map((account) => account.id)}
/>
<AvatarGroup compact>
{familiarFollowers.slice(0, 3).map((account) => (
<Avatar withLink key={account.id} account={account} size={28} />
))}
</AvatarGroup>
<FamiliarFollowersReadout familiarFollowers={familiarFollowers} />
</div>
);
@@ -35,8 +35,11 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge';
import { me } from 'mastodon/initial_state';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
const messages = defineMessages({
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
export const messages = defineMessages({
manageMembers: {
id: 'column.list_members',
defaultMessage: 'Manage list members',
},
placeholder: {
id: 'lists.search',
defaultMessage: 'Search',
@@ -255,10 +258,10 @@ const ListMembers: React.FC<{
return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(messages.heading)}
label={intl.formatMessage(messages.manageMembers)}
>
<ColumnHeader
title={intl.formatMessage(messages.heading)}
title={intl.formatMessage(messages.manageMembers)}
icon='list-ul'
iconComponent={ListAltIcon}
multiColumn={multiColumn}
@@ -331,7 +334,7 @@ const ListMembers: React.FC<{
</ScrollableList>
<Helmet>
<title>{intl.formatMessage(messages.heading)}</title>
<title>{intl.formatMessage(messages.manageMembers)}</title>
<meta name='robots' content='noindex' />
</Helmet>
</Column>
+20 -15
View File
@@ -9,16 +9,23 @@ import { isFulfilled } from '@reduxjs/toolkit';
import Toggle from 'react-toggle';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import { fetchList } from 'mastodon/actions/lists';
import { createList, updateList } from 'mastodon/actions/lists_typed';
import { apiGetAccounts } from 'mastodon/api/lists';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type { RepliesPolicyType } from 'mastodon/api_types/lists';
import { Avatar } from 'mastodon/components/avatar';
import { AvatarGroup } from 'mastodon/components/avatar_group';
import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { messages as membersMessages } from './members';
const messages = defineMessages({
edit: { id: 'column.edit_list', defaultMessage: 'Edit list' },
create: { id: 'column.create_list', defaultMessage: 'Create list' },
@@ -27,42 +34,40 @@ const messages = defineMessages({
const MembersLink: React.FC<{
id: string;
}> = ({ id }) => {
const [count, setCount] = useState(0);
const [avatars, setAvatars] = useState<string[]>([]);
const intl = useIntl();
const [avatarCount, setAvatarCount] = useState(0);
const [avatarAccounts, setAvatarAccounts] = useState<ApiAccountJSON[]>([]);
useEffect(() => {
void apiGetAccounts(id)
.then((data) => {
setCount(data.length);
setAvatars(data.slice(0, 3).map((a) => a.avatar));
return '';
setAvatarCount(data.length);
setAvatarAccounts(data.slice(0, 3));
})
.catch(() => {
// Nothing
});
}, [id, setCount, setAvatars]);
}, [id]);
return (
<Link to={`/lists/${id}/members`} className='app-form__link'>
<div className='app-form__link__text'>
<strong>
<FormattedMessage
id='lists.list_members'
defaultMessage='List members'
/>
{intl.formatMessage(membersMessages.manageMembers)}
<Icon id='chevron_right' icon={ChevronRightIcon} />
</strong>
<FormattedMessage
id='lists.list_members_count'
defaultMessage='{count, plural, one {# member} other {# members}}'
values={{ count }}
values={{ count: avatarCount }}
/>
</div>
<div className='avatar-pile'>
{avatars.map((url) => (
<img key={url} src={url} alt='' />
<AvatarGroup compact>
{avatarAccounts.map((a) => (
<Avatar key={a.id} account={a} size={30} />
))}
</div>
</AvatarGroup>
</Link>
);
};
@@ -7,6 +7,7 @@ import { HotKeys } from 'react-hotkeys';
import { replyComposeById } from 'mastodon/actions/compose';
import { navigateToStatus } from 'mastodon/actions/statuses';
import { Avatar } from 'mastodon/components/avatar';
import { AvatarGroup } from 'mastodon/components/avatar_group';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
@@ -17,6 +18,14 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { DisplayedName } from './displayed_name';
import { EmbeddedStatus } from './embedded_status';
export const AvatarById: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((state) => state.accounts.get(accountId));
if (!account) return null;
return <Avatar withLink account={account} size={28} />;
};
export type LabelRenderer = (
displayedName: JSX.Element,
total: number,
@@ -99,12 +108,13 @@ export const NotificationGroupWithStatus: React.FC<{
<div className='notification-group__main'>
<div className='notification-group__main__header'>
<div className='notification-group__main__header__wrapper'>
<AvatarGroup
accountIds={accountIds.slice(
0,
NOTIFICATIONS_GROUP_MAX_AVATARS,
)}
/>
<AvatarGroup>
{accountIds
.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS)
.map((id) => (
<AvatarById key={id} accountId={id} />
))}
</AvatarGroup>
{actions && (
<div className='notification-group__actions'>{actions}</div>