Add back an emojifyText function, do it during render
This commit is contained in:
parent
3cd479b601
commit
c27e4c6556
|
@ -15,6 +15,7 @@ import VerificationBadge from 'soapbox/components/verification-badge.tsx';
|
|||
import ActionButton from 'soapbox/features/ui/components/action-button.tsx';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { getAcct } from 'soapbox/utils/accounts.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { displayFqn } from 'soapbox/utils/state.ts';
|
||||
|
||||
import Badge from './badge.tsx';
|
||||
|
@ -233,7 +234,7 @@ const Account = ({
|
|||
<LinkEl {...linkProps}>
|
||||
<HStack space={1} alignItems='center' grow>
|
||||
<Text size='sm' weight='semibold' truncate>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{account.verified && <VerificationBadge />}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import { getAcct } from '../utils/accounts.ts';
|
||||
|
||||
|
@ -10,7 +11,7 @@ import VerificationBadge from './verification-badge.tsx';
|
|||
import type { Account } from 'soapbox/schemas/index.ts';
|
||||
|
||||
interface IDisplayName {
|
||||
account: Pick<Account, 'id' | 'acct' | 'fqn' | 'verified' | 'display_name'>;
|
||||
account: Pick<Account, 'id' | 'acct' | 'emojis' | 'fqn' | 'verified' | 'display_name'>;
|
||||
withSuffix?: boolean;
|
||||
}
|
||||
|
||||
|
@ -25,7 +26,7 @@ const DisplayNameInline: React.FC<IDisplayName> = ({ account, withSuffix = true
|
|||
weight='normal'
|
||||
truncate
|
||||
>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{verified && <VerificationBadge />}
|
||||
|
|
|
@ -2,16 +2,15 @@ import HoverRefWrapper from 'soapbox/components/hover-ref-wrapper.tsx';
|
|||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
|
||||
|
||||
import { getAcct } from '../utils/accounts.ts';
|
||||
|
||||
import { getAcct } from 'soapbox/utils/accounts.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import VerificationBadge from './verification-badge.tsx';
|
||||
|
||||
import type { Account } from 'soapbox/schemas/index.ts';
|
||||
|
||||
interface IDisplayName {
|
||||
account: Pick<Account, 'id' | 'acct' | 'fqn' | 'verified' | 'display_name'>;
|
||||
account: Pick<Account, 'id' | 'acct' | 'emojis' | 'fqn' | 'verified' | 'display_name'>;
|
||||
withSuffix?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
@ -27,7 +26,7 @@ const DisplayName: React.FC<IDisplayName> = ({ account, children, withSuffix = t
|
|||
weight='semibold'
|
||||
truncate
|
||||
>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{verified && <VerificationBadge />}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { useState, useRef, useLayoutEffect, useMemo, memo } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import Icon from 'soapbox/components/icon.tsx';
|
||||
|
||||
import { getTextDirection } from '../utils/rtl.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { getTextDirection } from 'soapbox/utils/rtl.ts';
|
||||
|
||||
import HashtagLink from './hashtag-link.tsx';
|
||||
import Markup from './markup.tsx';
|
||||
|
@ -90,27 +90,7 @@ const StatusContent: React.FC<IStatusContent> = ({
|
|||
}
|
||||
|
||||
if (domNode instanceof DOMText) {
|
||||
const parts: Array<string | JSX.Element> = [];
|
||||
|
||||
const textNodes = domNode.data.split(/:\w+:/);
|
||||
const shortcodes = [...domNode.data.matchAll(/:(\w+):/g)];
|
||||
|
||||
for (let i = 0; i < textNodes.length; i++) {
|
||||
parts.push(textNodes[i]);
|
||||
|
||||
if (shortcodes[i]) {
|
||||
const [text, shortcode] = shortcodes[i];
|
||||
const customEmoji = status.emojis.find((e) => e.shortcode === shortcode);
|
||||
|
||||
if (customEmoji) {
|
||||
parts.push(<img key={i} src={customEmoji.url} alt={shortcode} className='inline-block h-[1em]' />);
|
||||
} else {
|
||||
parts.push(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <>{parts}</>;
|
||||
return emojifyText(domNode.data, status.emojis.toJS());
|
||||
}
|
||||
|
||||
if (domNode instanceof Element && domNode.name === 'a') {
|
||||
|
|
|
@ -20,6 +20,7 @@ import QuotedStatus from 'soapbox/features/status/containers/quoted-status-conta
|
|||
import { HotKeys } from 'soapbox/features/ui/components/hotkeys.tsx';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
import { useSettings } from 'soapbox/hooks/useSettings.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { defaultMediaVisibility, textForScreenReader, getActualStatus } from 'soapbox/utils/status.ts';
|
||||
|
||||
import EventPreview from './event-preview.tsx';
|
||||
|
@ -232,7 +233,7 @@ const Status: React.FC<IStatus> = (props) => {
|
|||
>
|
||||
<bdi className='truncate'>
|
||||
<strong className='text-gray-800 dark:text-gray-200'>
|
||||
{status.account.display_name}
|
||||
{emojifyText(status.account.display_name, status.account.emojis)}
|
||||
</strong>
|
||||
</bdi>
|
||||
</Link>
|
||||
|
@ -263,7 +264,7 @@ const Status: React.FC<IStatus> = (props) => {
|
|||
<Link to={`/@${status.account.acct}`} className='hover:underline'>
|
||||
<bdi className='truncate'>
|
||||
<strong className='text-gray-800 dark:text-gray-200'>
|
||||
{status.account.display_name}
|
||||
{emojifyText(status.account.display_name, status.account.emojis)}
|
||||
</strong>
|
||||
</bdi>
|
||||
</Link>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
interface ICustomEmoji {
|
||||
/** Custom emoji URL. */
|
||||
url: string;
|
||||
/** Image alt text, usually the shortcode. */
|
||||
alt?: string;
|
||||
/** `img` tag className. Default: `h-[1em]` */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** A single custom emoji image. */
|
||||
const CustomEmoji: React.FC<ICustomEmoji> = (props): JSX.Element | null => {
|
||||
const { url, alt, className = 'h-[1em]' } = props;
|
||||
|
||||
return (
|
||||
<img src={url} alt={alt} className={className} />
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomEmoji;
|
|
@ -8,6 +8,7 @@ import Stack from 'soapbox/components/ui/stack.tsx';
|
|||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import VerificationBadge from 'soapbox/components/verification-badge.tsx';
|
||||
import useAccountSearch from 'soapbox/queries/search.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities.ts';
|
||||
|
||||
|
@ -41,7 +42,10 @@ const Results = ({ accountSearchResult, onSelect }: IResults) => {
|
|||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex grow items-center space-x-1'>
|
||||
<Text weight='bold' size='sm' truncate>{account.display_name}</Text>
|
||||
<Text weight='bold' size='sm' truncate>
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{account.verified && <VerificationBadge />}
|
||||
</div>
|
||||
<Text size='sm' weight='medium' theme='muted' direction='ltr' truncate>@{account.acct}</Text> {/* eslint-disable-line formatjs/no-literal-string-in-jsx */}
|
||||
|
|
|
@ -8,6 +8,7 @@ import Stack from 'soapbox/components/ui/stack.tsx';
|
|||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import VerificationBadge from 'soapbox/components/verification-badge.tsx';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import ActionButton from '../ui/components/action-button.tsx';
|
||||
import { HotKeys } from '../ui/components/hotkeys.tsx';
|
||||
|
@ -47,7 +48,7 @@ const SuggestionItem: React.FC<ISuggestionItem> = ({ accountId }) => {
|
|||
size='sm'
|
||||
className='max-w-[95%]'
|
||||
>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{account.verified && <VerificationBadge />}
|
||||
|
|
|
@ -37,6 +37,7 @@ import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
|||
import { useInstance } from 'soapbox/hooks/useInstance.ts';
|
||||
import { makeGetNotification } from 'soapbox/selectors/index.ts';
|
||||
import toast from 'soapbox/toast.tsx';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { NotificationType, validType } from 'soapbox/utils/notification.ts';
|
||||
|
||||
import type { ScrollPosition } from 'soapbox/components/status.tsx';
|
||||
|
@ -57,7 +58,7 @@ const buildLink = (account: AccountEntity): JSX.Element => (
|
|||
title={account.acct}
|
||||
to={`/@${account.acct}`}
|
||||
>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Link>
|
||||
</bdi>
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@ import Spinner from 'soapbox/components/ui/spinner.tsx';
|
|||
import AccountContainer from 'soapbox/containers/account-container.tsx';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { makeGetAccount } from 'soapbox/selectors/index.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
|
@ -32,7 +33,7 @@ const FamiliarFollowersModal = ({ accountId, onClose }: IFamiliarFollowersModal)
|
|||
<FormattedMessage
|
||||
id='account.familiar_followers.empty'
|
||||
defaultMessage='No one you know follows {name}.'
|
||||
values={{ name: account.display_name }}
|
||||
values={{ name: emojifyText(account.display_name, account.emojis) }}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -57,7 +58,7 @@ const FamiliarFollowersModal = ({ accountId, onClose }: IFamiliarFollowersModal)
|
|||
<FormattedMessage
|
||||
id='column.familiar_followers'
|
||||
defaultMessage='People you know following {name}'
|
||||
values={{ name: account?.display_name ?? '' }}
|
||||
values={{ name: account ? emojifyText(account.display_name, account.emojis) : '' }}
|
||||
/>
|
||||
)}
|
||||
onClose={onClickClose}
|
||||
|
|
|
@ -15,6 +15,7 @@ import Modal from 'soapbox/components/ui/modal.tsx';
|
|||
import Stack from 'soapbox/components/ui/stack.tsx';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
import { ZapSplitData } from 'soapbox/schemas/zap-split.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import type { Account as AccountEntity } from 'soapbox/types/entities.ts';
|
||||
|
||||
|
@ -48,7 +49,13 @@ const ZapInvoiceModal: React.FC<IZapInvoice> = ({ account, invoice, splitData, o
|
|||
};
|
||||
|
||||
const renderTitle = () => {
|
||||
return <FormattedMessage id='zap.send_to' defaultMessage='Send zaps to {target}' values={{ target: account.display_name }} />;
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='zap.send_to'
|
||||
defaultMessage='Send zaps to {target}'
|
||||
values={{ target: emojifyText(account.display_name, account.emojis) }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import Button from 'soapbox/components/ui/button.tsx';
|
|||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import Stack from 'soapbox/components/ui/stack.tsx';
|
||||
import { ZapSplitData } from 'soapbox/schemas/zap-split.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
const messages = defineMessages({
|
||||
zap_open_wallet: { id: 'zap.open_wallet', defaultMessage: 'Open Wallet' },
|
||||
|
@ -31,7 +32,11 @@ const ZapSplit = ({ zapData, zapAmount, invoice, onNext, isLastStep, onFinish }:
|
|||
const renderTitleQr = () => {
|
||||
return (
|
||||
<div className='max-w-[280px] truncate'>
|
||||
<FormattedMessage id='zap.send_to' defaultMessage='Send zaps to {target}' values={{ target: account.display_name }} />
|
||||
<FormattedMessage
|
||||
id='zap.send_to'
|
||||
defaultMessage='Send zaps to {target}'
|
||||
values={{ target: emojifyText(account.display_name, account.emojis) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
|||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { useFeatures } from 'soapbox/hooks/useFeatures.ts';
|
||||
import { makeGetAccount } from 'soapbox/selectors/index.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import type { Account } from 'soapbox/schemas/index.ts';
|
||||
|
||||
|
@ -51,7 +52,7 @@ const ProfileFamiliarFollowers: React.FC<IProfileFamiliarFollowers> = ({ account
|
|||
<Link className='inline-block text-primary-600 hover:underline dark:text-accent-blue' to={`/@${account.acct}`}>
|
||||
<HStack space={1} alignItems='center' grow>
|
||||
<Text size='sm' theme='primary' truncate>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{account.verified && <VerificationBadge />}
|
||||
|
|
|
@ -15,6 +15,7 @@ import Stack from 'soapbox/components/ui/stack.tsx';
|
|||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { capitalize } from 'soapbox/utils/strings.ts';
|
||||
|
||||
import ProfileFamiliarFollowers from './profile-familiar-followers.tsx';
|
||||
|
@ -151,7 +152,7 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
|||
<Stack>
|
||||
<HStack space={1} alignItems='center'>
|
||||
<Text size='lg' weight='bold' truncate>
|
||||
{deactivated ? intl.formatMessage(messages.deactivated) : account.display_name}
|
||||
{deactivated ? intl.formatMessage(messages.deactivated) : emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{account.bot && <Badge slug='bot' title={intl.formatMessage(messages.bot)} />}
|
||||
|
|
|
@ -10,6 +10,7 @@ import Text from 'soapbox/components/ui/text.tsx';
|
|||
import VerificationBadge from 'soapbox/components/verification-badge.tsx';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { getAcct } from 'soapbox/utils/accounts.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers.tsx';
|
||||
import { displayFqn } from 'soapbox/utils/state.ts';
|
||||
|
||||
|
@ -59,7 +60,7 @@ const UserPanel: React.FC<IUserPanel> = ({ accountId, action, badges, domain })
|
|||
<Link to={`/@${account.acct}`}>
|
||||
<HStack space={1} alignItems='center'>
|
||||
<Text size='lg' weight='bold' truncate>
|
||||
{account.display_name}
|
||||
{emojifyText(account.display_name, account.emojis)}
|
||||
</Text>
|
||||
|
||||
{verified && <VerificationBadge />}
|
||||
|
|
|
@ -22,6 +22,7 @@ import Stack from 'soapbox/components/ui/stack.tsx';
|
|||
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
import { emojifyText } from 'soapbox/utils/emojify.tsx';
|
||||
|
||||
import ZapButton from './zap-button/zap-button.tsx';
|
||||
|
||||
|
@ -113,7 +114,11 @@ const ZapPayRequestForm = ({ account, status, onClose }: IZapPayRequestForm) =>
|
|||
/>
|
||||
|
||||
<Text weight='semibold'>
|
||||
<FormattedMessage id='zap.send_to' defaultMessage='Send zaps to {target}' values={{ target: account.display_name }} />
|
||||
<FormattedMessage
|
||||
id='zap.send_to'
|
||||
defaultMessage='Send zaps to {target}'
|
||||
values={{ target: emojifyText(account.display_name, account.emojis) }}
|
||||
/>
|
||||
</Text>
|
||||
<Avatar src={account.avatar} size={50} />
|
||||
<DisplayNameInline account={account} />
|
||||
|
@ -141,12 +146,15 @@ const ZapPayRequestForm = ({ account, status, onClose }: IZapPayRequestForm) =>
|
|||
{hasZapSplit && <p className='absolute right-0 font-bold sm:-right-6 sm:text-xl'>sats</p>}
|
||||
</div>
|
||||
|
||||
{hasZapSplit && <span className='flex justify-center text-xs'>
|
||||
<FormattedMessage
|
||||
id='zap.split_message.receiver'
|
||||
defaultMessage='{receiver} will receive {amountReceiver} sats*' values={{ receiver: account.display_name, amountReceiver: zapSplitData.receiveAmount }}
|
||||
/>
|
||||
</span>}
|
||||
{hasZapSplit && (
|
||||
<span className='flex justify-center text-xs'>
|
||||
<FormattedMessage
|
||||
id='zap.split_message.receiver'
|
||||
defaultMessage='{receiver} will receive {amountReceiver} sats*'
|
||||
values={{ receiver: emojifyText(account.display_name, account.emojis), amountReceiver: zapSplitData.receiveAmount }}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
|
||||
</Stack>
|
||||
|
||||
|
@ -162,7 +170,8 @@ const ZapPayRequestForm = ({ account, status, onClose }: IZapPayRequestForm) =>
|
|||
<span className='text-[10px] sm:text-xs'>
|
||||
<FormattedMessage
|
||||
id='zap.split_message.deducted'
|
||||
defaultMessage='{amountDeducted} sats will deducted*' values={{ instance: account.display_name, amountDeducted: zapSplitData.splitAmount }}
|
||||
defaultMessage='{amountDeducted} sats will deducted*'
|
||||
values={{ instance: emojifyText(account.display_name, account.emojis), amountDeducted: zapSplitData.splitAmount }}
|
||||
/>
|
||||
</span>
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { CustomEmoji } from 'soapbox/schemas/custom-emoji.ts';
|
||||
|
||||
/** Given text and a list of custom emojis, return JSX with the emojis rendered as `<img>` elements. */
|
||||
export function emojifyText(text: string, emojis: CustomEmoji[]): JSX.Element {
|
||||
const parts: Array<string | JSX.Element> = [];
|
||||
|
||||
const textNodes = text.split(/:\w+:/);
|
||||
const shortcodes = [...text.matchAll(/:(\w+):/g)];
|
||||
|
||||
for (let i = 0; i < textNodes.length; i++) {
|
||||
parts.push(textNodes[i]);
|
||||
|
||||
if (shortcodes[i]) {
|
||||
const [match, shortcode] = shortcodes[i];
|
||||
const customEmoji = emojis.find((e) => e.shortcode === shortcode);
|
||||
|
||||
if (customEmoji) {
|
||||
parts.push(<img key={i} src={customEmoji.url} alt={shortcode} className='inline h-[1em] align-text-bottom' />);
|
||||
} else {
|
||||
parts.push(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <>{parts}</>;
|
||||
}
|
Loading…
Reference in New Issue