From 9abf26203906f293c87cb88598fc6c4840462706 Mon Sep 17 00:00:00 2001 From: Samuel Newman <10959775+mozzius@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:30:07 +0200 Subject: [PATCH] add twemoji --- bskyweb/templates/base.html | 8 +++++++ package.json | 1 + src/components/RichText.tsx | 13 ++++++----- src/components/Twemoji.tsx | 6 +++++ src/components/Twemoji.web.tsx | 40 ++++++++++++++++++++++++++++++++++ web/index.html | 8 +++++++ yarn.lock | 28 ++++++++++++++++++++++-- 7 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 src/components/Twemoji.tsx create mode 100644 src/components/Twemoji.web.tsx diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html index cb2caed443..fb8451c38e 100644 --- a/bskyweb/templates/base.html +++ b/bskyweb/templates/base.html @@ -253,6 +253,14 @@ from { opacity: 1; } to { opacity: 0; } } + + /* Twemoji */ + img.twemoji { + height: 1em; + width: 1em; + margin: 0 .05em 0 .1em; + vertical-align: -0.1em; + } {% include "scripts.html" %} diff --git a/package.json b/package.json index 91b427ae91..972cc4b77a 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", + "@discordapp/twemoji": "^15.0.3", "@emoji-mart/react": "^1.1.1", "@expo/html-elements": "^0.4.2", "@expo/webpack-config": "^19.0.0", diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx index 7511775978..d250707820 100644 --- a/src/components/RichText.tsx +++ b/src/components/RichText.tsx @@ -14,6 +14,7 @@ import {InlineLinkText, LinkProps} from '#/components/Link' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {TagMenu, useTagMenuControl} from '#/components/TagMenu' import {Text, TextProps} from '#/components/Typography' +import {Twemoji} from './Twemoji' const WORD_WRAP = {wordWrap: 1} @@ -71,7 +72,7 @@ export function RichText({ style={[plainStyles, {fontSize}]} // @ts-ignore web only -prf dataSet={WORD_WRAP}> - {text} + {text} ) } @@ -83,7 +84,7 @@ export function RichText({ numberOfLines={numberOfLines} // @ts-ignore web only -prf dataSet={WORD_WRAP}> - {text} + {text} ) } @@ -109,7 +110,7 @@ export function RichText({ // @ts-ignore TODO dataSet={WORD_WRAP} onPress={onLinkPress}> - {segment.text} + {segment.text} , ) @@ -127,7 +128,7 @@ export function RichText({ dataSet={WORD_WRAP} shareOnLongPress onPress={onLinkPress}> - {toShortUrl(segment.text)} + {toShortUrl(segment.text)} , ) } @@ -148,7 +149,7 @@ export function RichText({ />, ) } else { - els.push(segment.text) + els.push({segment.text}) } key++ } @@ -242,7 +243,7 @@ function RichTextTag({ }, style, ]}> - {text} + {text} diff --git a/src/components/Twemoji.tsx b/src/components/Twemoji.tsx new file mode 100644 index 0000000000..2844221954 --- /dev/null +++ b/src/components/Twemoji.tsx @@ -0,0 +1,6 @@ +import React from 'react' + +let Twemoji = ({children}: {children: string}): React.ReactNode => children + +Twemoji = React.memo(Twemoji) +export {Twemoji} diff --git a/src/components/Twemoji.web.tsx b/src/components/Twemoji.web.tsx new file mode 100644 index 0000000000..027eec7d31 --- /dev/null +++ b/src/components/Twemoji.web.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import twemoji from '@discordapp/twemoji' +import Graphemer from 'graphemer' + +// Thanks to https://gist.github.com/chibicode/fe195d792270910226c928b69a468206?permalink_comment_id=4241184#gistcomment-4241184 +// for figuring this out +const U200D = String.fromCharCode(0x200d) +const UFE0Fg = /\uFE0F/g + +let Twemoji = ({children}: {children: string}): React.ReactNode => { + if (!/\p{Extended_Pictographic}/u.test(children)) { + return children + } + + const splitter = new Graphemer() + const graphemes = splitter.iterateGraphemes(children) + let result: React.ReactNode[] = [] + let i = 0 + for (const grapheme of graphemes) { + if (/\p{Extended_Pictographic}/u.test(grapheme)) { + const HexCodePoint = twemoji.convert.toCodePoint( + grapheme.indexOf(U200D) < 0 ? grapheme.replace(UFE0Fg, '') : grapheme, + ) + result.push( + {grapheme}, + ) + } else { + result.push(grapheme) + } + } + return result +} + +Twemoji = React.memo(Twemoji) +export {Twemoji} diff --git a/web/index.html b/web/index.html index 81cbc23329..9c3b698588 100644 --- a/web/index.html +++ b/web/index.html @@ -257,6 +257,14 @@ from { opacity: 1; } to { opacity: 0; } } + + /* Twemoji */ + img.twemoji { + height: 1em; + width: 1em; + margin: 0 .05em 0 .1em; + vertical-align: -0.1em; + } diff --git a/yarn.lock b/yarn.lock index 675fda4c2f..d96286dbc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3119,6 +3119,16 @@ "@gorhom/portal" "1.0.14" invariant "^2.2.4" +"@discordapp/twemoji@^15.0.3": + version "15.0.3" + resolved "https://registry.yarnpkg.com/@discordapp/twemoji/-/twemoji-15.0.3.tgz#71a428080c21df5c305121bc1f0fc42cf3a3cfcc" + integrity sha512-5t0LLrNaSqViG0cSaomWwfR0+3fWqok+xLq40M8hJHxNX7s8gIoyNZYybQJo+s5/rGMjgdldpt8Ox8MapGvBUA== + dependencies: + "@twemoji/parser" "15.0.0" + fs-extra "^8.0.1" + jsonfile "^5.0.0" + universalify "^0.1.2" + "@discoveryjs/json-ext@0.5.7", "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -7743,6 +7753,11 @@ resolved "https://registry.yarnpkg.com/@tsconfig/react-native/-/react-native-2.0.3.tgz#79ad8efc6d3729152da6cb23725b6c364a7349b2" integrity sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A== +"@twemoji/parser@15.0.0": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@twemoji/parser/-/parser-15.0.0.tgz#8ae9749659ef524b5f0e6ee1412d0e48865e77bf" + integrity sha512-lh9515BNsvKSNvyUqbj5yFu83iIDQ77SwVcsN/SnEGawczhsKU6qWuogewN1GweTi5Imo5ToQ9s+nNTf97IXvg== + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.20.1" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" @@ -12856,7 +12871,7 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^8.1.0, fs-extra@~8.1.0: +fs-extra@^8.0.1, fs-extra@^8.1.0, fs-extra@~8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== @@ -15564,6 +15579,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" + integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== + dependencies: + universalify "^0.1.2" + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -21498,7 +21522,7 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -universalify@^0.1.0: +universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==