Compare commits
14 commits
main
...
archived-s
Author | SHA1 | Date | |
---|---|---|---|
373e87184b | |||
2fb4c8887a | |||
3c4b7e5c33 | |||
6c5b8a1d14 | |||
466ec03fb3 | |||
384ab7e737 | |||
db4ac6a2c2 | |||
027bfdadeb | |||
0684ba645e | |||
8b24d8813f | |||
a754fd02c9 | |||
36fae9bb1e | |||
5a096f9442 | |||
61082a38cd |
13 changed files with 131 additions and 44 deletions
.gitmodulespackage-lock.jsontwemojivite.config.js
src
app
components
features/room
pages/client
plugins
util
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "twemoji"]
|
||||
path = twemoji
|
||||
url = https://github.com/jdecked/twemoji
|
56
package-lock.json
generated
56
package-lock.json
generated
|
@ -491,23 +491,25 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
|
||||
"integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
|
||||
"integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.25.9",
|
||||
"@babel/types": "^7.26.0"
|
||||
"@babel/template": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz",
|
||||
"integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
|
||||
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.26.5"
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
|
@ -1591,9 +1593,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
|
@ -1602,10 +1605,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/runtime-corejs3": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz",
|
||||
"integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.0.tgz",
|
||||
"integrity": "sha512-UWjX6t+v+0ckwZ50Y5ShZLnlk95pP5MyW/pon9tiYzl3+18pkTHTFNTKr7rQbfRXPkowt2QAn30o1b6oswszew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-js-pure": "^3.30.2",
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
|
@ -1615,13 +1619,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
|
||||
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
|
||||
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.25.9",
|
||||
"@babel/parser": "^7.25.9",
|
||||
"@babel/types": "^7.25.9"
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/parser": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
|
@ -1645,9 +1650,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz",
|
||||
"integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
|
||||
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.9",
|
||||
"@babel/helper-validator-identifier": "^7.25.9"
|
||||
|
@ -6254,6 +6260,7 @@
|
|||
"version": "15.3.1",
|
||||
"resolved": "https://registry.npmjs.org/emojibase/-/emojibase-15.3.1.tgz",
|
||||
"integrity": "sha512-GNsjHnG2J3Ktg684Fs/vZR/6XpOSkZPMAv85EHrr6br2RN2cJNwdS4am/3YSK3y+/gOv2kmoK3GGdahXdMxg2g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "ko-fi",
|
||||
"url": "https://ko-fi.com/milesjohnson"
|
||||
|
@ -6263,6 +6270,7 @@
|
|||
"version": "15.3.2",
|
||||
"resolved": "https://registry.npmjs.org/emojibase-data/-/emojibase-data-15.3.2.tgz",
|
||||
"integrity": "sha512-TpDyTDDTdqWIJixV5sTA6OQ0P0JfIIeK2tFRR3q56G9LK65ylAZ7z3KyBXokpvTTJ+mLUXQXbLNyVkjvnTLE+A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "ko-fi",
|
||||
"url": "https://ko-fi.com/milesjohnson"
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
import * as css from '../../styles/CustomHtml.css';
|
||||
import { CommandElement, EmoticonElement, LinkElement, MentionElement } from './slate';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { getEmojiUrl, isUsingTwemoji } from '../../plugins/emoji';
|
||||
import { getBeginCommand } from './utils';
|
||||
import { BlockType } from './types';
|
||||
import { mxcUrlToHttp } from '../../utils/matrix';
|
||||
|
@ -97,7 +98,12 @@ function RenderEmoticonElement({
|
|||
alt={element.shortcode}
|
||||
/>
|
||||
) : (
|
||||
element.key
|
||||
isUsingTwemoji() ? <img
|
||||
className={css.EmoticonImg}
|
||||
src={getEmojiUrl(element.key)}
|
||||
alt={element.key}
|
||||
title={element.shortcode}
|
||||
/> : element.key
|
||||
)}
|
||||
{children}
|
||||
</span>
|
||||
|
|
|
@ -126,6 +126,15 @@ export const CustomEmojiImg = style([
|
|||
},
|
||||
]);
|
||||
|
||||
export const EmoticonImg = style([
|
||||
DefaultReset,
|
||||
{
|
||||
width: toRem(32),
|
||||
height: toRem(32),
|
||||
objectFit: 'contain',
|
||||
},
|
||||
]);
|
||||
|
||||
export const StickerImg = style([
|
||||
DefaultReset,
|
||||
{
|
||||
|
|
|
@ -34,7 +34,15 @@ import { MatrixClient, Room } from 'matrix-js-sdk';
|
|||
import { atom, useAtomValue, useSetAtom } from 'jotai';
|
||||
|
||||
import * as css from './EmojiBoard.css';
|
||||
import { EmojiGroupId, IEmoji, IEmojiGroup, emojiGroups, emojis } from '../../plugins/emoji';
|
||||
import {
|
||||
EmojiGroupId,
|
||||
IEmoji,
|
||||
IEmojiGroup,
|
||||
emojiGroups,
|
||||
emojis,
|
||||
getEmojiUrl,
|
||||
isUsingTwemoji,
|
||||
} from '../../plugins/emoji';
|
||||
import { IEmojiGroupLabels, useEmojiGroupLabels } from './useEmojiGroupLabels';
|
||||
import { IEmojiGroupIcons, useEmojiGroupIcons } from './useEmojiGroupIcons';
|
||||
import { preventScrollWithArrowKey, stopPropagation } from '../../utils/keyboard';
|
||||
|
@ -272,6 +280,15 @@ export const EmojiGroup = as<
|
|||
</Box>
|
||||
));
|
||||
|
||||
const NativeEmoji = (emoji: IEmoji) =>
|
||||
isUsingTwemoji() ? <img
|
||||
loading="lazy"
|
||||
className={css.EmoticonImg}
|
||||
src={getEmojiUrl(emoji.unicode)}
|
||||
alt={emoji.unicode}
|
||||
title={emoji.shortcode}
|
||||
/> : emoji.unicode;
|
||||
|
||||
export function EmojiItem({
|
||||
label,
|
||||
type,
|
||||
|
@ -447,7 +464,7 @@ export function RecentEmojiGroup({
|
|||
data={emoji.unicode}
|
||||
shortcode={emoji.shortcode}
|
||||
>
|
||||
{emoji.unicode}
|
||||
{NativeEmoji(emoji)}
|
||||
</EmojiItem>
|
||||
))}
|
||||
</EmojiGroup>
|
||||
|
@ -481,7 +498,7 @@ export function SearchEmojiGroup({
|
|||
data={emoji.unicode}
|
||||
shortcode={emoji.shortcode}
|
||||
>
|
||||
{emoji.unicode}
|
||||
{NativeEmoji(emoji)}
|
||||
</EmojiItem>
|
||||
) : (
|
||||
<EmojiItem
|
||||
|
@ -628,7 +645,7 @@ export const NativeEmojiGroups = memo(
|
|||
data={emoji.unicode}
|
||||
shortcode={emoji.shortcode}
|
||||
>
|
||||
{emoji.unicode}
|
||||
{NativeEmoji(emoji)}
|
||||
</EmojiItem>
|
||||
))}
|
||||
</EmojiGroup>
|
||||
|
@ -758,7 +775,16 @@ export function EmojiBoard({
|
|||
const emojiInfo = getEmojiItemInfo(element);
|
||||
if (!emojiInfo || !emojiPreviewTextRef.current) return;
|
||||
if (emojiInfo.type === EmojiType.Emoji && emojiPreviewRef.current) {
|
||||
emojiPreviewRef.current.textContent = emojiInfo.data;
|
||||
if (isUsingTwemoji()) {
|
||||
const img = document.createElement('img');
|
||||
img.className = css.CustomEmojiImg;
|
||||
img.setAttribute('src', getEmojiUrl(emojiInfo.data));
|
||||
img.setAttribute('alt', emojiInfo.shortcode);
|
||||
emojiPreviewRef.current.textContent = '';
|
||||
emojiPreviewRef.current.appendChild(img);
|
||||
} else {
|
||||
emojiPreviewRef.current.textContent = emojiInfo.data;
|
||||
}
|
||||
} else if (emojiInfo.type === EmojiType.CustomEmoji && emojiPreviewRef.current) {
|
||||
const img = document.createElement('img');
|
||||
img.className = css.CustomEmojiImg;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Box, Text, as } from 'folds';
|
|||
import classNames from 'classnames';
|
||||
import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk';
|
||||
import * as css from './Reaction.css';
|
||||
import { getHexcodeForEmoji, getShortcodeFor } from '../../plugins/emoji';
|
||||
import { getHexcodeForEmoji, getShortcodeFor, getEmojiUrl, isUsingTwemoji } from '../../plugins/emoji';
|
||||
import { getMemberDisplayName } from '../../utils/room';
|
||||
import { eventWithShortcode, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
|
||||
|
||||
|
@ -33,6 +33,13 @@ export const Reaction = as<
|
|||
}
|
||||
alt={reaction}
|
||||
/>
|
||||
) : isUsingTwemoji() ? (
|
||||
<img
|
||||
className={css.ReactionImg}
|
||||
src={getEmojiUrl(reaction)}
|
||||
alt={reaction}
|
||||
title={getShortcodeFor(getHexcodeForEmoji(reaction))}
|
||||
/>
|
||||
) : (
|
||||
<Text as="span" size="Inherit" truncate>
|
||||
{reaction}
|
||||
|
|
|
@ -277,10 +277,12 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
});
|
||||
handleCancelUpload(uploads);
|
||||
const contents = fulfilledPromiseSettledResult(await Promise.allSettled(contentsPromises));
|
||||
contents.forEach((content) => mx.sendMessage(roomId, content));
|
||||
for (const content of contents) {
|
||||
await mx.sendMessage(roomId, content);
|
||||
}
|
||||
};
|
||||
|
||||
const submit = useCallback(() => {
|
||||
const submit = useCallback(async () => {
|
||||
uploadBoardHandlers.current?.handleSend();
|
||||
|
||||
const commandName = getBeginCommand(editor);
|
||||
|
@ -356,7 +358,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
content['m.relates_to'].is_falling_back = false;
|
||||
}
|
||||
}
|
||||
mx.sendMessage(roomId, content);
|
||||
await mx.sendMessage(roomId, content);
|
||||
resetEditor(editor);
|
||||
resetEditorHistory(editor);
|
||||
setReplyDraft(undefined);
|
||||
|
|
|
@ -33,7 +33,7 @@ export function WelcomePage() {
|
|||
<Box grow="Yes" style={{ maxWidth: toRem(300) }} direction="Column" gap="300">
|
||||
<Button
|
||||
as="a"
|
||||
href="https://github.com/cinnyapp/cinny"
|
||||
href="https://forgejo.sup39.dev/supnas/cinny"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
before={<Icon size="200" src={Icons.Code} />}
|
||||
|
|
|
@ -112,3 +112,13 @@ emojisData.forEach((emoji) => {
|
|||
emojis.push(em);
|
||||
}
|
||||
});
|
||||
|
||||
export const isUsingTwemoji = () =>
|
||||
document.documentElement.style.getPropertyValue('--font-emoji') !== 'Twemoji_DISABLED';
|
||||
|
||||
const TWEMOJI_BASE_URL = '/twemoji'; // TODO
|
||||
export function getEmojiUrl(char: string): string {
|
||||
let codes = Array.from(char).flatMap(x => x.codePointAt(0)?.toString(16) ?? []);
|
||||
if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f');
|
||||
return `${TWEMOJI_BASE_URL}/${codes.join('-')}.svg`;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
} from '../utils/matrix';
|
||||
import { getMemberDisplayName } from '../utils/room';
|
||||
import { EMOJI_PATTERN, sanitizeForRegex, URL_NEG_LB } from '../utils/regex';
|
||||
import { getHexcodeForEmoji, getShortcodeFor } from './emoji';
|
||||
import { getHexcodeForEmoji, getShortcodeFor, getEmojiUrl, isUsingTwemoji } from './emoji';
|
||||
import { findAndReplace } from '../utils/findAndReplace';
|
||||
import {
|
||||
parseMatrixToRoom,
|
||||
|
@ -160,13 +160,22 @@ export const scaleSystemEmoji = (text: string): (string | JSX.Element)[] =>
|
|||
findAndReplace(
|
||||
text,
|
||||
EMOJI_REG_G,
|
||||
(match, pushIndex) => (
|
||||
<span key={`scaleSystemEmoji-${pushIndex}`} className={css.EmoticonBase}>
|
||||
<span className={css.Emoticon()} title={getShortcodeFor(getHexcodeForEmoji(match[0]))}>
|
||||
{match[0]}
|
||||
</span>
|
||||
</span>
|
||||
),
|
||||
(match, pushIndex) => {
|
||||
const char = match[0];
|
||||
const className = css.Emoticon();
|
||||
const title = getShortcodeFor(getHexcodeForEmoji(char));
|
||||
return <span key={`scaleSystemEmoji-${pushIndex}`} className={css.EmoticonBase}>{
|
||||
isUsingTwemoji() ? <img
|
||||
className={className}
|
||||
alt={char}
|
||||
title={title}
|
||||
src={getEmojiUrl(char)}
|
||||
/> : <span
|
||||
className={className}
|
||||
title={title}
|
||||
>{match[0]}</span>
|
||||
}</span>;
|
||||
},
|
||||
(txt) => txt
|
||||
);
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ function hashCode(str) {
|
|||
|
||||
export function cssColorMXID(userId) {
|
||||
const colorNumber = hashCode(userId) % 8;
|
||||
return `--mx-uc-${colorNumber + 1}`;
|
||||
// @user:a.b.c => -user-a_b_c
|
||||
const escapedUserId = userId.replace(/[@:]/g, '-').replace(/[^\w-]/g, '_');
|
||||
return `--mx-uc-${escapedUserId}, var(--mx-uc-${colorNumber + 1})`;
|
||||
}
|
||||
|
||||
export default function colorMXID(userId) {
|
||||
|
|
1
twemoji
Submodule
1
twemoji
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 310184baaae6f797e9ef2650bea35187242ffafb
|
|
@ -36,6 +36,10 @@ const copyFiles = {
|
|||
src: 'public/locales',
|
||||
dest: 'public/',
|
||||
},
|
||||
{
|
||||
src: 'twemoji/assets/svg/*',
|
||||
dest: 'twemoji/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue