Add even more features to feature usage counter (#40340)

This commit is contained in:
Eugen Rochko
2026-08-31 16:49:38 +00:00
committed by GitHub
parent 74b4fc07df
commit 76bd33296a
19 changed files with 81 additions and 20 deletions

View File

@@ -309,8 +309,9 @@ export const Account: React.FC<AccountProps> = ({
<Link
className='account__display-name focusable'
title={account?.acct}
to={`/@${account?.acct}`}
to={{ pathname: `/@${account?.acct}`, state: { reference } }}
data-hover-card-account={id}
data-hover-card-reference={reference}
>
<div className='account__avatar-wrapper'>
{account ? (

View File

@@ -3,6 +3,8 @@ import type { FC } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useLocation } from 'react-router-dom';
import { followAccount } from '@/mastodon/actions/accounts';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { getAccountHidden } from '@/mastodon/selectors/accounts';
@@ -81,6 +83,10 @@ const AccountButtonsOther: FC<
});
}
}, [accountUrl]);
const { state } = useLocation<{
reference?: string;
} | null>();
const reference = state?.reference ?? 'profile';
if (!account) {
return null;
@@ -96,7 +102,7 @@ const AccountButtonsOther: FC<
accountId={accountId}
className={classes.followButton}
labelLength='long'
reference='profile'
reference={reference}
/>
)}
{isFollowing && (

View File

@@ -27,6 +27,7 @@ import classes from './styles.module.scss';
export interface RenderButtonOptions {
accountId: string | undefined;
relationship: Relationship | null | undefined;
reference?: string;
}
type Stat = 'followers' | 'following' | 'posts' | 'joined' | 'last-active';
@@ -38,6 +39,7 @@ interface Props {
withBorder?: boolean;
badge?: ReactNode;
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
reference?: string;
}
const DEFAULT_STATS: Stat[] = ['followers', 'posts', 'last-active'];
@@ -56,6 +58,7 @@ export const AccountListItem: React.FC<Props> = ({
withBorder = true,
badge: badgeProp,
renderButton = defaultRenderButton,
reference,
}) => {
const intl = useIntl();
const account = useAccount(accountId);
@@ -83,13 +86,14 @@ export const AccountListItem: React.FC<Props> = ({
icon={<Avatar account={account} size={40} />}
sideContent={
<span className={classes.button}>
{renderButton({ accountId, relationship })}
{renderButton({ accountId, relationship, reference })}
</span>
}
>
<ListItemLink
to={`/@${account.acct}`}
to={{ pathname: `/@${account.acct}`, state: { reference } }}
data-hover-card-account={accountId}
data-hover-card-reference={reference}
subtitle={<span className={classes.handle}>{handle}</span>}
>
<DisplayNameSimple
@@ -193,8 +197,8 @@ export const AccountListItem: React.FC<Props> = ({
);
};
const defaultRenderButton = ({ accountId }: RenderButtonOptions) => (
<AccountListItemFollowButton accountId={accountId} />
const defaultRenderButton = ({ accountId, reference }: RenderButtonOptions) => (
<AccountListItemFollowButton accountId={accountId} reference={reference} />
);
export const AccountListItemFollowButton: React.FC<{

View File

@@ -29,8 +29,9 @@ export const DisplayName: FC<
export const LinkedDisplayName: FC<
Omit<LinkProps, 'to'> & {
displayProps: DisplayNameProps & ComponentPropsWithoutRef<'span'>;
reference?: string;
}
> = ({ displayProps, children, ...linkProps }) => {
> = ({ displayProps, reference, children, ...linkProps }) => {
const { account } = displayProps;
if (!account) {
return <DisplayName {...displayProps} />;
@@ -38,10 +39,11 @@ export const LinkedDisplayName: FC<
return (
<Link
to={`/@${account.acct}`}
to={{ pathname: `/@${account.acct}`, state: { reference } }}
title={`@${account.acct}`}
data-id={account.id}
data-hover-card-account={account.id}
data-hover-card-reference={reference}
{...linkProps}
>
{children}

View File

@@ -25,8 +25,8 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
export const HoverCardAccount = forwardRef<
HTMLDivElement,
{ accountId?: string }
>(({ accountId }, ref) => {
{ accountId?: string; reference?: string }
>(({ accountId, reference }, ref) => {
const dispatch = useAppDispatch();
const account = useAppSelector((state) =>
@@ -171,7 +171,10 @@ export const HoverCardAccount = forwardRef<
)}
</div>
<FollowButton accountId={accountId} />
<FollowButton
accountId={accountId}
reference={reference ?? 'hover_card'}
/>
</>
)}
</>

View File

@@ -21,6 +21,7 @@ const isHoverCardAnchor = (element: HTMLElement) =>
export const HoverCardController: React.FC = () => {
const [open, setOpen] = useState(false);
const [accountId, setAccountId] = useState<string | undefined>();
const [reference, setReference] = useState<string | undefined>();
const [anchor, setAnchor] = useState<HTMLElement | null>(null);
const cardRef = useRef<HTMLDivElement>(null);
const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout();
@@ -53,6 +54,9 @@ export const HoverCardController: React.FC = () => {
setOpen(true);
setAnchor(target);
setAccountId(target.getAttribute('data-hover-card-account') ?? undefined);
setReference(
target.getAttribute('data-hover-card-reference') ?? undefined,
);
};
const close = () => {
@@ -61,6 +65,7 @@ export const HoverCardController: React.FC = () => {
setOpen(false);
setAnchor(null);
setAccountId(undefined);
setReference(undefined);
};
const handleTouchStart = () => {
@@ -216,7 +221,11 @@ export const HoverCardController: React.FC = () => {
>
{({ props }) => (
<div {...props} className='hover-card-controller'>
<HoverCardAccount accountId={accountId} ref={cardRef} />
<HoverCardAccount
accountId={accountId}
reference={reference}
ref={cardRef}
/>
</div>
)}
</Popover>

View File

@@ -432,6 +432,7 @@ class Status extends ImmutablePureComponent {
variant: 'simple'
}}
className='status__display-name muted'
reference='status'
/>
)

View File

@@ -53,9 +53,10 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
return (
<Link
className={classNames('mention', className)}
to={`/@${mention.acct}`}
to={{ pathname: `/@${mention.acct}`, state: { reference: 'status' } }}
title={`@${mention.acct}`}
data-hover-card-account={mention.id}
data-hover-card-reference='status'
>
{children}
</Link>

View File

@@ -118,6 +118,7 @@ const StatusDisplayName: FC<{
<LinkedDisplayName
displayProps={{ account: statusAccount }}
className='status__display-name'
reference='status'
>
<div className='status__avatar'>
<AccountComponent

View File

@@ -151,7 +151,10 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
aria-posinset={index + 1}
aria-setsize={featuredAccountIds.size}
>
<AccountListItem accountId={featuredAccountId} />
<AccountListItem
accountId={featuredAccountId}
reference='featured_account'
/>
</Article>
))}
</ItemList>

View File

@@ -197,6 +197,7 @@ export const CollectionAccountsList: React.FC<{
withBorder={!isLastElement}
badge={item.state === 'pending' ? <PendingBadge /> : null}
renderButton={renderAccountItemButton}
reference='collection'
/>
</Article>
),

View File

@@ -15,6 +15,7 @@ export const AuthorLink: FC<{ accountId: string }> = ({ accountId }) => {
<LinkedDisplayName
displayProps={{ account, variant: 'simple' }}
className='story__details__shared__author-link'
reference='author_attribution'
>
<Avatar account={account} size={16} />
</LinkedDisplayName>

View File

@@ -97,8 +97,12 @@ export const Card: React.FC<{ id: string; source: SuggestionSource }> = ({
<div className='explore-suggestions-card__body'>
<Link
to={`/@${account.get('acct')}`}
to={{
pathname: `/@${account.get('acct')}`,
state: { reference: 'suggestions' },
}}
data-hover-card-account={account.id}
data-hover-card-reference='suggestions'
className='explore-suggestions-card__link'
>
<Avatar

View File

@@ -88,7 +88,7 @@ class Favourites extends ImmutablePureComponent {
bindToDocument={!multiColumn}
>
{accountIds.map(id =>
<Account key={id} id={id} />,
<Account key={id} id={id} reference='status' />,
)}
</ScrollableList>

View File

@@ -60,6 +60,7 @@ export const AccountList: FC<AccountListProps> = ({
accountId={followerId}
withBio={false}
badge={withoutFollowsYouBadge ? false : null}
reference='profile'
/>
)) ?? [];
@@ -70,6 +71,7 @@ export const AccountList: FC<AccountListProps> = ({
accountId={prependAccountId}
withBio={false}
badge={withoutFollowsYouBadge ? false : null}
reference='profile'
/>,
);
}

View File

@@ -142,13 +142,27 @@ const Card: React.FC<{
/>
<div className='inline-follow-suggestions__body__scrollable__card__avatar'>
<Link to={`/@${account?.acct}`} data-hover-card-account={account?.id}>
<Link
to={{
pathname: `/@${account?.acct}`,
state: { reference: 'inline_suggestions' },
}}
data-hover-card-account={account?.id}
data-hover-card-reference='inline_suggestions'
>
<Avatar account={account} size={72} />
</Link>
</div>
<div className='inline-follow-suggestions__body__scrollable__card__text-stack'>
<Link to={`/@${account?.acct}`} data-hover-card-account={account?.id}>
<Link
to={{
pathname: `/@${account?.acct}`,
state: { reference: 'inline_suggestions' },
}}
data-hover-card-account={account?.id}
data-hover-card-reference='inline_suggestions'
>
<DisplayName account={account} />
</Link>
{firstVerifiedField ? (

View File

@@ -88,7 +88,7 @@ class Reblogs extends ImmutablePureComponent {
bindToDocument={!multiColumn}
>
{accountIds.map(id =>
<Account key={id} id={id} />,
<Account key={id} id={id} reference='status' />,
)}
</ScrollableList>

View File

@@ -441,8 +441,12 @@ export const DetailedStatus: React.FC<{
</div>
)}
<Link
to={`/@${status.getIn(['account', 'acct'])}`}
to={{
pathname: `/@${status.getIn(['account', 'acct'])}`,
state: { reference: 'status' },
}}
data-hover-card-account={status.getIn(['account', 'id'])}
data-hover-card-reference='status'
className='detailed-status__display-name'
>
<div className='detailed-status__display-avatar'>

View File

@@ -8,11 +8,15 @@ class FeatureUsageTracker
).freeze
REF_VALUES = %w(
author_attribution
collection
featured_account
hover_card
inline_suggestions
onboarding
profile
search
status
suggestions
).freeze