From ab317f2a9c96fe390675fb4fed781155e3eba7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Sun, 15 Mar 2026 10:56:54 +0100 Subject: [PATCH] nicolium: nyaize post-emojified text only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../components/statuses/parsed-content.tsx | 7 +- .../nicolium/src/features/emoji/emojify.tsx | 161 +++++++++--------- 2 files changed, 85 insertions(+), 83 deletions(-) diff --git a/packages/nicolium/src/components/statuses/parsed-content.tsx b/packages/nicolium/src/components/statuses/parsed-content.tsx index d0a29eddc..07443fc73 100644 --- a/packages/nicolium/src/components/statuses/parsed-content.tsx +++ b/packages/nicolium/src/components/statuses/parsed-content.tsx @@ -15,7 +15,6 @@ import { Link } from '@/components/link'; import Emojify from '@/features/emoji/emojify'; import { useSettings } from '@/stores/settings'; import { makeEmojiMap } from '@/utils/normalizers'; -import nyaize from '@/utils/nyaize'; import Purify from '@/utils/url-purify'; import HoverAccountWrapper from '../accounts/hover-account-wrapper'; @@ -197,10 +196,8 @@ function parseContent( let hasSuspiciousUrl = false; - const transformText = (data: string, key?: React.Key) => { - const text = speakAsCat ? nyaize(data) : data; - - return ; + const transformText = (text: string, key?: React.Key) => { + return ; }; const options: HTMLReactParserOptions = { diff --git a/packages/nicolium/src/features/emoji/emojify.tsx b/packages/nicolium/src/features/emoji/emojify.tsx index c0c160c35..9bb8a4365 100644 --- a/packages/nicolium/src/features/emoji/emojify.tsx +++ b/packages/nicolium/src/features/emoji/emojify.tsx @@ -4,6 +4,7 @@ import React from 'react'; import Emoji from '@/components/ui/emoji'; import { useSettings } from '@/stores/settings'; import { makeEmojiMap } from '@/utils/normalizers'; +import nyaize from '@/utils/nyaize'; import { joinPublicPath } from '@/utils/static'; import unicodeMapping from './mapping'; @@ -15,9 +16,10 @@ import type { CustomEmoji } from 'pl-api'; interface IMaybeEmoji { text: string; emojis: Record; + nyaize: boolean; } -const MaybeEmoji: React.FC = ({ text, emojis }) => { +const MaybeEmoji: React.FC = ({ text, emojis, nyaize: shouldNyaize }) => { if (text.length < 3) return text; if (text in emojis) { const emoji = emojis[text]; @@ -28,100 +30,103 @@ const MaybeEmoji: React.FC = ({ text, emojis }) => { } } - return text; + return shouldNyaize ? nyaize(text) : text; }; interface IEmojify { text: string; emojis?: Array | Record; + nyaize?: boolean; } -const Emojify: React.FC = React.memo(({ text, emojis = {} }) => { - const { disableUserProvidedMedia, systemEmojiFont } = useSettings(); +const Emojify: React.FC = React.memo( + ({ text, emojis = {}, nyaize: shouldNyaize = false }) => { + const { disableUserProvidedMedia, systemEmojiFont } = useSettings(); - if (Array.isArray(emojis)) emojis = makeEmojiMap(emojis); + if (Array.isArray(emojis)) emojis = makeEmojiMap(emojis); - const nodes = []; + const nodes = []; - let stack = ''; - let open = false; + let stack = ''; + let open = false; - const clearStack = () => { - if (stack.length) nodes.push(stack); - open = false; - stack = ''; - }; + const clearStack = () => { + if (stack.length) nodes.push(shouldNyaize ? nyaize(stack) : stack); + open = false; + stack = ''; + }; - const splitText = split(text); + const splitText = split(text); - for (const index in splitText) { - let c = splitText[index]; + for (const index in splitText) { + let c = splitText[index]; - // convert FE0E selector to FE0F so it can be found in unimap - if (c.codePointAt(c.length - 1) === 65038) { - c = c.slice(0, -1) + String.fromCodePoint(65039); + // convert FE0E selector to FE0F so it can be found in unimap + if (c.codePointAt(c.length - 1) === 65038) { + c = c.slice(0, -1) + String.fromCodePoint(65039); + } + + // unqualified emojis aren't in emoji-mart's mappings so we just add FEOF + const unqualified = c + String.fromCodePoint(65039); + + if (!systemEmojiFont && c in unicodeMapping) { + clearStack(); + + const { unified, shortcode } = unicodeMapping[c]; + + nodes.push( + {c}, + ); + } else if (!systemEmojiFont && unqualified in unicodeMapping) { + clearStack(); + + const { unified, shortcode } = unicodeMapping[unqualified]; + + nodes.push( + {unqualified}, + ); + } else if (!disableUserProvidedMedia && c === ':') { + if (!open) { + clearStack(); + } + + stack += ':'; + + // we see another : we convert it and clear the stack buffer + if (open) { + nodes.push(); + stack = ''; + } + + open = !open; + } else { + stack += c; + + if (open && !validEmojiChar(c)) { + clearStack(); + } + } } - // unqualified emojis aren't in emoji-mart's mappings so we just add FEOF - const unqualified = c + String.fromCodePoint(65039); + if (stack.length) nodes.push(shouldNyaize ? nyaize(stack) : stack); - if (!systemEmojiFont && c in unicodeMapping) { - clearStack(); - - const { unified, shortcode } = unicodeMapping[c]; - - nodes.push( - {c}, - ); - } else if (!systemEmojiFont && unqualified in unicodeMapping) { - clearStack(); - - const { unified, shortcode } = unicodeMapping[unqualified]; - - nodes.push( - {unqualified}, - ); - } else if (!disableUserProvidedMedia && c === ':') { - if (!open) { - clearStack(); - } - - stack += ':'; - - // we see another : we convert it and clear the stack buffer - if (open) { - nodes.push(); - stack = ''; - } - - open = !open; - } else { - stack += c; - - if (open && !validEmojiChar(c)) { - clearStack(); - } - } - } - - if (stack.length) nodes.push(stack); - - return nodes; -}); + return nodes; + }, +); Emojify.displayName = 'Emojify';