Emoji Rendering (#35424)
This commit is contained in:
25 files changed
+1064
-70
No files matched your search
@@ -2,27 +2,44 @@ import { useCallback } from 'react';
|
||||
|
||||
import { useLinks } from 'mastodon/hooks/useLinks';
|
||||
|
||||
import { EmojiHTML } from '../features/emoji/emoji_html';
|
||||
import { isFeatureEnabled } from '../initial_state';
|
||||
import { useAppSelector } from '../store';
|
||||
|
||||
interface AccountBioProps {
|
||||
note: string;
|
||||
className: string;
|
||||
dropdownAccountId?: string;
|
||||
accountId: string;
|
||||
showDropdown?: boolean;
|
||||
}
|
||||
|
||||
export const AccountBio: React.FC<AccountBioProps> = ({
|
||||
note,
|
||||
className,
|
||||
dropdownAccountId,
|
||||
accountId,
|
||||
showDropdown = false,
|
||||
}) => {
|
||||
const handleClick = useLinks(!!dropdownAccountId);
|
||||
const handleClick = useLinks(showDropdown);
|
||||
const handleNodeChange = useCallback(
|
||||
(node: HTMLDivElement | null) => {
|
||||
if (!dropdownAccountId || !node || node.childNodes.length === 0) {
|
||||
if (!showDropdown || !node || node.childNodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
addDropdownToHashtags(node, dropdownAccountId);
|
||||
addDropdownToHashtags(node, accountId);
|
||||
},
|
||||
[dropdownAccountId],
|
||||
[showDropdown, accountId],
|
||||
);
|
||||
const note = useAppSelector((state) => {
|
||||
const account = state.accounts.get(accountId);
|
||||
if (!account) {
|
||||
return '';
|
||||
}
|
||||
return isFeatureEnabled('modern_emojis')
|
||||
? account.note
|
||||
: account.note_emojified;
|
||||
});
|
||||
const extraEmojis = useAppSelector((state) => {
|
||||
const account = state.accounts.get(accountId);
|
||||
return account?.emojis;
|
||||
});
|
||||
|
||||
if (note.length === 0) {
|
||||
return null;
|
||||
@@ -31,10 +48,11 @@ export const AccountBio: React.FC<AccountBioProps> = ({
|
||||
return (
|
||||
<div
|
||||
className={`${className} translate`}
|
||||
dangerouslySetInnerHTML={{ __html: note }}
|
||||
onClickCapture={handleClick}
|
||||
ref={handleNodeChange}
|
||||
/>
|
||||
>
|
||||
<EmojiHTML htmlString={note} extraEmojis={extraEmojis} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ export const HoverCardAccount = forwardRef<
|
||||
<>
|
||||
<div className='hover-card__text-row'>
|
||||
<AccountBio
|
||||
note={account.note_emojified}
|
||||
accountId={account.id}
|
||||
className='hover-card__bio'
|
||||
/>
|
||||
<AccountFields fields={account.fields} limit={2} />
|
||||
|
||||
@@ -13,7 +13,8 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { Poll } from 'mastodon/components/poll';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
|
||||
import { autoPlayGif, isFeatureEnabled, languages as preloadedLanguages } from 'mastodon/initial_state';
|
||||
import { EmojiHTML } from '../features/emoji/emoji_html';
|
||||
|
||||
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
||||
|
||||
@@ -23,6 +24,9 @@ const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getStatusContent(status) {
|
||||
if (isFeatureEnabled('modern_emojis')) {
|
||||
return status.getIn(['translation', 'content']) || status.get('content');
|
||||
}
|
||||
return status.getIn(['translation', 'contentHtml']) || status.get('contentHtml');
|
||||
}
|
||||
|
||||
@@ -228,7 +232,7 @@ class StatusContent extends PureComponent {
|
||||
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
|
||||
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
|
||||
|
||||
const content = { __html: statusContent ?? getStatusContent(status) };
|
||||
const content = statusContent ?? getStatusContent(status);
|
||||
const language = status.getIn(['translation', 'language']) || status.get('language');
|
||||
const classNames = classnames('status__content', {
|
||||
'status__content--with-action': this.props.onClick && this.props.history,
|
||||
@@ -253,7 +257,12 @@ class StatusContent extends PureComponent {
|
||||
return (
|
||||
<>
|
||||
<div className={classNames} ref={this.setRef} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
<div className='status__content__text status__content__text--visible translate' lang={language} dangerouslySetInnerHTML={content} />
|
||||
<EmojiHTML
|
||||
className='status__content__text status__content__text--visible translate'
|
||||
lang={language}
|
||||
htmlString={content}
|
||||
extraEmojis={status.get('emojis')}
|
||||
/>
|
||||
|
||||
{poll}
|
||||
{translateButton}
|
||||
@@ -265,7 +274,12 @@ class StatusContent extends PureComponent {
|
||||
} else {
|
||||
return (
|
||||
<div className={classNames} ref={this.setRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
<div className='status__content__text status__content__text--visible translate' lang={language} dangerouslySetInnerHTML={content} />
|
||||
<EmojiHTML
|
||||
className='status__content__text status__content__text--visible translate'
|
||||
lang={language}
|
||||
htmlString={content}
|
||||
extraEmojis={status.get('emojis')}
|
||||
/>
|
||||
|
||||
{poll}
|
||||
{translateButton}
|
||||
|
||||
Reference in new issue
Block a user