kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
StatusContent: replace custom emojis on render
rodzic
afac59dc3d
commit
f335249104
|
@ -1,10 +1,11 @@
|
|||
import chevronRightIcon from '@tabler/icons/outline/chevron-right.svg';
|
||||
import clsx from 'clsx';
|
||||
import graphemesplit from 'graphemesplit';
|
||||
import parse, { Element, type HTMLReactParserOptions, domToReact, type DOMNode } from 'html-react-parser';
|
||||
import parse, { Element, type HTMLReactParserOptions, domToReact, type DOMNode, Text as DOMText } from 'html-react-parser';
|
||||
import { useState, useRef, useLayoutEffect, useMemo, memo } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { useCustomEmojis } from 'soapbox/api/hooks/useCustomEmojis.ts';
|
||||
import Icon from 'soapbox/components/icon.tsx';
|
||||
|
||||
import { getTextDirection } from '../utils/rtl.ts';
|
||||
|
@ -51,11 +52,12 @@ const StatusContent: React.FC<IStatusContent> = ({
|
|||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const node = useRef<HTMLDivElement>(null);
|
||||
const { customEmojis } = useCustomEmojis();
|
||||
|
||||
const isOnlyEmoji = useMemo(() => {
|
||||
const textContent = new DOMParser().parseFromString(status.contentHtml, 'text/html').body.firstChild?.textContent;
|
||||
return Boolean(textContent && /^\p{Extended_Pictographic}+$/u.test(textContent) && (graphemesplit(textContent).length <= BIG_EMOJI_LIMIT));
|
||||
}, [status.contentHtml]);
|
||||
const textContent = new DOMParser().parseFromString(status.content, 'text/html').body.firstChild?.textContent ?? '';
|
||||
return Boolean(/^\p{Extended_Pictographic}+$/u.test(textContent) && (graphemesplit(textContent).length <= BIG_EMOJI_LIMIT));
|
||||
}, [status.content]);
|
||||
|
||||
const maybeSetCollapsed = (): void => {
|
||||
if (!node.current) return;
|
||||
|
@ -72,8 +74,8 @@ const StatusContent: React.FC<IStatusContent> = ({
|
|||
});
|
||||
|
||||
const parsedHtml = useMemo((): string => {
|
||||
return translatable && status.translation ? status.translation.get('content')! : status.contentHtml;
|
||||
}, [status.contentHtml, status.translation]);
|
||||
return translatable && status.translation ? status.translation.get('content')! : status.content;
|
||||
}, [status.content, status.translation]);
|
||||
|
||||
if (status.content.length === 0) {
|
||||
return null;
|
||||
|
@ -89,6 +91,22 @@ const StatusContent: React.FC<IStatusContent> = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
if (domNode instanceof DOMText) {
|
||||
const parts = domNode.data.split(' ').map((part) => {
|
||||
const match = part.match(/^:(\w+):$/);
|
||||
if (!match) return part;
|
||||
|
||||
const [, shortcode] = match;
|
||||
const customEmoji = customEmojis.find((e) => e.shortcode === shortcode);
|
||||
|
||||
if (!customEmoji) return part;
|
||||
|
||||
return <img key={part} src={customEmoji.url} alt={part} className='inline-block h-[1em]' />;
|
||||
});
|
||||
|
||||
return <>{parts}</>;
|
||||
}
|
||||
|
||||
if (domNode instanceof Element && domNode.name === 'a') {
|
||||
const classes = domNode.attribs.class?.split(' ');
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue