mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-02-25 09:18:51 +01:00
EmojiText component replacing dangerouslySetInnerHTML
This commit is contained in:
parent
d2826085e1
commit
3b3e0e6fde
8 changed files with 69 additions and 46 deletions
|
@ -2,11 +2,11 @@ import './account-block.css';
|
||||||
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import niceDateTime from '../utils/nice-date-time';
|
import niceDateTime from '../utils/nice-date-time';
|
||||||
import states from '../utils/states';
|
import states from '../utils/states';
|
||||||
|
|
||||||
import Avatar from './avatar';
|
import Avatar from './avatar';
|
||||||
|
import EmojiText from './emoji-text';
|
||||||
|
|
||||||
function AccountBlock({
|
function AccountBlock({
|
||||||
skeleton,
|
skeleton,
|
||||||
|
@ -46,7 +46,6 @@ function AccountBlock({
|
||||||
lastStatusAt,
|
lastStatusAt,
|
||||||
bot,
|
bot,
|
||||||
} = account;
|
} = account;
|
||||||
const displayNameWithEmoji = emojifyText(displayName, emojis);
|
|
||||||
const [_, acct1, acct2] = acct.match(/([^@]+)(@.+)/i) || [, acct];
|
const [_, acct1, acct2] = acct.match(/([^@]+)(@.+)/i) || [, acct];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -72,11 +71,9 @@ function AccountBlock({
|
||||||
<Avatar url={avatar} size={avatarSize} squircle={bot} />
|
<Avatar url={avatar} size={avatarSize} squircle={bot} />
|
||||||
<span>
|
<span>
|
||||||
{displayName ? (
|
{displayName ? (
|
||||||
<b
|
<b>
|
||||||
dangerouslySetInnerHTML={{
|
<EmojiText text={displayName} emojis={emojis} />
|
||||||
__html: displayNameWithEmoji,
|
</b>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<b>{username}</b>
|
<b>{username}</b>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Menu, MenuDivider, MenuItem, SubMenu } from '@szhsin/react-menu';
|
||||||
import { useEffect, useReducer, useRef, useState } from 'preact/hooks';
|
import { useEffect, useReducer, useRef, useState } from 'preact/hooks';
|
||||||
|
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import enhanceContent from '../utils/enhance-content';
|
import enhanceContent from '../utils/enhance-content';
|
||||||
import getHTMLText from '../utils/getHTMLText';
|
import getHTMLText from '../utils/getHTMLText';
|
||||||
import handleContentLinks from '../utils/handle-content-links';
|
import handleContentLinks from '../utils/handle-content-links';
|
||||||
|
@ -16,6 +15,7 @@ import store from '../utils/store';
|
||||||
|
|
||||||
import AccountBlock from './account-block';
|
import AccountBlock from './account-block';
|
||||||
import Avatar from './avatar';
|
import Avatar from './avatar';
|
||||||
|
import EmojiText from './emoji-text';
|
||||||
import Icon from './icon';
|
import Icon from './icon';
|
||||||
import Link from './link';
|
import Link from './link';
|
||||||
import ListAddEdit from './list-add-edit';
|
import ListAddEdit from './list-add-edit';
|
||||||
|
@ -301,11 +301,7 @@ function AccountInfo({
|
||||||
key={name}
|
key={name}
|
||||||
>
|
>
|
||||||
<b>
|
<b>
|
||||||
<span
|
<EmojiText text={name} emojis={emojis} />{' '}
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: emojifyText(name, emojis),
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
{!!verifiedAt && <Icon icon="check-circle" size="s" />}
|
{!!verifiedAt && <Icon icon="check-circle" size="s" />}
|
||||||
</b>
|
</b>
|
||||||
<p
|
<p
|
||||||
|
|
42
src/components/emoji-text.jsx
Normal file
42
src/components/emoji-text.jsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
function EmojiText({ text, emojis }) {
|
||||||
|
if (!text) return '';
|
||||||
|
if (!emojis?.length) return text;
|
||||||
|
if (text.indexOf(':') === -1) return text;
|
||||||
|
|
||||||
|
const components = [];
|
||||||
|
let lastIndex = 0;
|
||||||
|
|
||||||
|
emojis.forEach((shortcodeObj) => {
|
||||||
|
const { shortcode, staticUrl, url } = shortcodeObj;
|
||||||
|
const regex = new RegExp(`:${shortcode}:`, 'g');
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = regex.exec(text))) {
|
||||||
|
const beforeText = text.substring(lastIndex, match.index);
|
||||||
|
if (beforeText) {
|
||||||
|
components.push(beforeText);
|
||||||
|
}
|
||||||
|
components.push(
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
alt={shortcode}
|
||||||
|
class="shortcode-emoji emoji"
|
||||||
|
width="12"
|
||||||
|
height="12"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
lastIndex = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const afterText = text.substring(lastIndex);
|
||||||
|
if (afterText) {
|
||||||
|
components.push(afterText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmojiText;
|
|
@ -1,9 +1,9 @@
|
||||||
import './name-text.css';
|
import './name-text.css';
|
||||||
|
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import states from '../utils/states';
|
import states from '../utils/states';
|
||||||
|
|
||||||
import Avatar from './avatar';
|
import Avatar from './avatar';
|
||||||
|
import EmojiText from './emoji-text';
|
||||||
|
|
||||||
function NameText({
|
function NameText({
|
||||||
account,
|
account,
|
||||||
|
@ -18,8 +18,6 @@ function NameText({
|
||||||
account;
|
account;
|
||||||
let { username } = account;
|
let { username } = account;
|
||||||
|
|
||||||
const displayNameWithEmoji = emojifyText(displayName, emojis);
|
|
||||||
|
|
||||||
const trimmedUsername = username.toLowerCase().trim();
|
const trimmedUsername = username.toLowerCase().trim();
|
||||||
const trimmedDisplayName = (displayName || '').toLowerCase().trim();
|
const trimmedDisplayName = (displayName || '').toLowerCase().trim();
|
||||||
const shortenedDisplayName = trimmedDisplayName
|
const shortenedDisplayName = trimmedDisplayName
|
||||||
|
@ -58,11 +56,9 @@ function NameText({
|
||||||
)}
|
)}
|
||||||
{displayName && !short ? (
|
{displayName && !short ? (
|
||||||
<>
|
<>
|
||||||
<b
|
<b>
|
||||||
dangerouslySetInnerHTML={{
|
<EmojiText text={displayName} emojis={emojis} />
|
||||||
__html: displayNameWithEmoji,
|
</b>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{!showAcct && username && (
|
{!showAcct && username && (
|
||||||
<>
|
<>
|
||||||
{' '}
|
{' '}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||||
|
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import shortenNumber from '../utils/shorten-number';
|
import shortenNumber from '../utils/shorten-number';
|
||||||
|
|
||||||
|
import EmojiText from './emoji-text';
|
||||||
import Icon from './icon';
|
import Icon from './icon';
|
||||||
import RelativeTime from './relative-time';
|
import RelativeTime from './relative-time';
|
||||||
|
|
||||||
|
@ -112,11 +112,9 @@ export default function Poll({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="poll-option-title">
|
<div class="poll-option-title">
|
||||||
<span
|
<span>
|
||||||
dangerouslySetInnerHTML={{
|
<EmojiText text={title} emojis={emojis} />
|
||||||
__html: emojifyText(title, emojis),
|
</span>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{voted && ownVotes.includes(i) && (
|
{voted && ownVotes.includes(i) && (
|
||||||
<>
|
<>
|
||||||
{' '}
|
{' '}
|
||||||
|
@ -179,12 +177,9 @@ export default function Poll({
|
||||||
disabled={uiState === 'loading'}
|
disabled={uiState === 'loading'}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
<span
|
<span class="poll-option-title">
|
||||||
class="poll-option-title"
|
<EmojiText text={title} emojis={emojis} />
|
||||||
dangerouslySetInnerHTML={{
|
</span>
|
||||||
__html: emojifyText(title, emojis),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,12 +26,12 @@ import { useSnapshot } from 'valtio';
|
||||||
import { snapshot } from 'valtio/vanilla';
|
import { snapshot } from 'valtio/vanilla';
|
||||||
|
|
||||||
import AccountBlock from '../components/account-block';
|
import AccountBlock from '../components/account-block';
|
||||||
|
import EmojiText from '../components/emoji-text';
|
||||||
import Loader from '../components/loader';
|
import Loader from '../components/loader';
|
||||||
import Modal from '../components/modal';
|
import Modal from '../components/modal';
|
||||||
import NameText from '../components/name-text';
|
import NameText from '../components/name-text';
|
||||||
import Poll from '../components/poll';
|
import Poll from '../components/poll';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import enhanceContent from '../utils/enhance-content';
|
import enhanceContent from '../utils/enhance-content';
|
||||||
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
|
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
|
||||||
import getHTMLText from '../utils/getHTMLText';
|
import getHTMLText from '../utils/getHTMLText';
|
||||||
|
@ -926,11 +926,9 @@ function Status({
|
||||||
ref={spoilerContentRef}
|
ref={spoilerContentRef}
|
||||||
data-read-more={readMoreText}
|
data-read-more={readMoreText}
|
||||||
>
|
>
|
||||||
<p
|
<p>
|
||||||
dangerouslySetInnerHTML={{
|
<EmojiText text={spoilerText} emojis={emojis} />
|
||||||
__html: emojifyText(spoilerText, emojis),
|
</p>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class={`light spoiler ${showSpoiler ? 'spoiling' : ''}`}
|
class={`light spoiler ${showSpoiler ? 'spoiling' : ''}`}
|
||||||
|
|
|
@ -4,12 +4,12 @@ import { useParams, useSearchParams } from 'react-router-dom';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
import AccountInfo from '../components/account-info';
|
import AccountInfo from '../components/account-info';
|
||||||
|
import EmojiText from '../components/emoji-text';
|
||||||
import Icon from '../components/icon';
|
import Icon from '../components/icon';
|
||||||
import Link from '../components/link';
|
import Link from '../components/link';
|
||||||
import Menu2 from '../components/menu2';
|
import Menu2 from '../components/menu2';
|
||||||
import Timeline from '../components/timeline';
|
import Timeline from '../components/timeline';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import emojifyText from '../utils/emojify-text';
|
|
||||||
import showToast from '../utils/show-toast';
|
import showToast from '../utils/show-toast';
|
||||||
import states from '../utils/states';
|
import states from '../utils/states';
|
||||||
import { saveStatus } from '../utils/states';
|
import { saveStatus } from '../utils/states';
|
||||||
|
@ -236,11 +236,9 @@ function AccountStatuses() {
|
||||||
// };
|
// };
|
||||||
// }}
|
// }}
|
||||||
>
|
>
|
||||||
<b
|
<b>
|
||||||
dangerouslySetInnerHTML={{
|
<EmojiText text={displayName} emojis={emojis} />
|
||||||
__html: emojifyText(displayName, emojis),
|
</b>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<span>@{acct}</span>
|
<span>@{acct}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
function emojifyText(text, emojis = []) {
|
function emojifyText(text, emojis = []) {
|
||||||
if (!text) return '';
|
if (!text) return '';
|
||||||
if (!emojis.length) return text;
|
if (!emojis.length) return text;
|
||||||
|
if (text.indexOf(':') === -1) return text;
|
||||||
// Replace shortcodes in text with emoji
|
// Replace shortcodes in text with emoji
|
||||||
// emojis = [{ shortcode: 'smile', url: 'https://example.com/emoji.png' }]
|
// emojis = [{ shortcode: 'smile', url: 'https://example.com/emoji.png' }]
|
||||||
emojis.forEach((emoji) => {
|
emojis.forEach((emoji) => {
|
||||||
const { shortcode, staticUrl, url } = emoji;
|
const { shortcode, staticUrl, url } = emoji;
|
||||||
text = text.replace(
|
text = text.replace(
|
||||||
new RegExp(`:${shortcode}:`, 'g'),
|
new RegExp(`:${shortcode}:`, 'g'),
|
||||||
`<img class="shortcode-emoji emoji" src="${url}" alt=":${shortcode}:" width="12" height="12" loading="lazy" />`,
|
`<img class="shortcode-emoji emoji" src="${url}" alt=":${shortcode}:" width="12" height="12" loading="lazy" decoding="async" />`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
// console.log(text, emojis);
|
// console.log(text, emojis);
|
||||||
|
|
Loading…
Reference in a new issue