2
0

Adds DisplayName component (#35985)

This commit is contained in:
Echo
2025-09-04 12:09:27 +02:00
committed by GitHub
parent d7d83d44e6
commit 42be0ca0eb
7 changed files with 259 additions and 33 deletions

View File

@@ -0,0 +1,81 @@
import type { ComponentProps } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { accountFactoryState } from '@/testing/factories';
import { DisplayName, LinkedDisplayName } from './index';
type PageProps = Omit<ComponentProps<typeof DisplayName>, 'account'> & {
name: string;
username: string;
loading: boolean;
};
const meta = {
title: 'Components/DisplayName',
args: {
username: 'mastodon@mastodon.social',
name: 'Test User 🧪',
loading: false,
simple: false,
noDomain: false,
localDomain: 'mastodon.social',
},
tags: [],
render({ name, username, loading, ...args }) {
const account = !loading
? accountFactoryState({
display_name: name,
acct: username,
})
: undefined;
return <DisplayName {...args} account={account} />;
},
} satisfies Meta<PageProps>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {},
};
export const Loading: Story = {
args: {
loading: true,
},
};
export const NoDomain: Story = {
args: {
noDomain: true,
},
};
export const Simple: Story = {
args: {
simple: true,
},
};
export const LocalUser: Story = {
args: {
username: 'localuser',
name: 'Local User',
localDomain: '',
},
};
export const Linked: Story = {
render({ name, username, loading, ...args }) {
const account = !loading
? accountFactoryState({
display_name: name,
acct: username,
})
: undefined;
return <LinkedDisplayName {...args} account={account} />;
},
};

View File

@@ -0,0 +1,122 @@
import type { ComponentPropsWithoutRef, FC } from 'react';
import { useMemo } from 'react';
import classNames from 'classnames';
import type { LinkProps } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { EmojiHTML } from '@/mastodon/features/emoji/emoji_html';
import type { Account } from '@/mastodon/models/account';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { Skeleton } from '../skeleton';
interface Props {
account?: Account;
localDomain?: string;
simple?: boolean;
noDomain?: boolean;
}
export const DisplayName: FC<Props & ComponentPropsWithoutRef<'span'>> = ({
account,
localDomain,
simple = false,
noDomain = false,
className,
...props
}) => {
const username = useMemo(() => {
if (!account || noDomain) {
return null;
}
let acct = account.get('acct');
if (!acct.includes('@') && localDomain) {
acct = `${acct}@${localDomain}`;
}
return `@${acct}`;
}, [account, localDomain, noDomain]);
if (!account) {
if (simple) {
return null;
}
return (
<span {...props} className={classNames('display-name', className)}>
<bdi>
<strong className='display-name__html'>
<Skeleton width='10ch' />
</strong>
</bdi>
{!noDomain && (
<span className='display-name__account'>
&nbsp;
<Skeleton width='7ch' />
</span>
)}
</span>
);
}
const accountName = isModernEmojiEnabled()
? account.get('display_name')
: account.get('display_name_html');
if (simple) {
return (
<bdi>
<EmojiHTML {...props} htmlString={accountName} shallow as='span' />
</bdi>
);
}
return (
<span {...props} className={classNames('display-name', className)}>
<bdi>
<EmojiHTML
className='display-name__html'
htmlString={accountName}
shallow
as='strong'
/>
</bdi>
{username && (
<span className='display-name__account'>&nbsp;{username}</span>
)}
</span>
);
};
export const LinkedDisplayName: FC<
Props & { asProps?: ComponentPropsWithoutRef<'span'> } & Partial<LinkProps>
> = ({
account,
asProps = {},
className,
localDomain,
simple,
noDomain,
...linkProps
}) => {
const displayProps = {
account,
className,
localDomain,
simple,
noDomain,
...asProps,
};
if (!account) {
return <DisplayName {...displayProps} />;
}
return (
<Link
to={`/@${account.acct}`}
title={`@${account.acct}`}
data-hover-card-account={account.id}
{...linkProps}
>
<DisplayName {...displayProps} />
</Link>
);
};