pl-fe: Support custom emoji categories

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk
2025-03-06 13:20:25 +01:00
parent de5de07425
commit 635d1e36b2
3 changed files with 45 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState, useLayoutEffect, Suspense, useMemo } from 'react';
import React, { useEffect, useLayoutEffect, useMemo, useState, Suspense } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { changeSetting, saveSettings } from 'pl-fe/actions/settings';
@@ -8,7 +8,7 @@ import { useTheme } from 'pl-fe/hooks/use-theme';
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
import { useSettingsStore } from 'pl-fe/stores/settings';
import { buildCustomEmojis } from '../../emoji';
import { buildCustomEmojiCategories } from '../../emoji';
import { EmojiPicker } from '../../ui/util/async-components';
import type { CustomEmoji as BaseCustomEmoji } from 'pl-api';
@@ -209,12 +209,16 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
document.body.style.overflow = '';
}, []);
const customEmojiCategories = useMemo(() => {
return withCustom ? buildCustomEmojiCategories(customEmojis || [], intl) : undefined;
}, [withCustom, customEmojis]);
return (
visible ? (
<RenderAfter update={update}>
<Suspense>
<EmojiPicker
custom={withCustom ? [{ emojis: buildCustomEmojis(customEmojis || []) }] : undefined}
custom={customEmojiCategories}
title={title}
onEmojiSelect={handlePick}
recent={frequentlyUsedEmojis}

View File

@@ -1,3 +1,5 @@
import { IntlShape } from 'react-intl';
import type { Emoji as EmojiMart, CustomEmoji as EmojiMartCustom } from './data';
import type { CustomEmoji as BaseCustomEmoji } from 'pl-api';
@@ -56,7 +58,7 @@ const validEmojiChar = (c: string) =>
const buildCustomEmojis = (customEmojis: Array<BaseCustomEmoji>) => {
const emojis: EmojiMart<EmojiMartCustom>[] = [];
customEmojis.forEach((emoji: any) => {
customEmojis.forEach((emoji) => {
const shortcode = emoji.shortcode;
const url = emoji.static_url;
const name = shortcode.replace(':', '');
@@ -72,6 +74,39 @@ const buildCustomEmojis = (customEmojis: Array<BaseCustomEmoji>) => {
return emojis;
};
const buildCustomEmojiCategories = (customEmojis: Array<BaseCustomEmoji>, intl?: IntlShape) => {
const emojiCategories: Record<string, EmojiMart<EmojiMartCustom>[]> = {};
for (const emoji of customEmojis) {
const categoryName = emoji.category || 'uncategorized';
if (!emojiCategories[categoryName]) {
emojiCategories[categoryName] = [];
}
const category = emojiCategories[categoryName];
const shortcode = emoji.shortcode;
const url = emoji.static_url;
const name = shortcode.replace(':', '');
category.push({
id: name,
name,
keywords: [name],
skins: [{ src: url }],
});
}
return Object.entries(emojiCategories)
.toSorted((a, b) => a[0].localeCompare(b[0]))
.map(([categoryName, emojis]) => ({
id: categoryName,
name: categoryName === 'uncategorized' && intl
? intl.formatMessage({ id: 'emoji_button.uncategorized', defaultMessage: 'Uncategorized' })
: categoryName.replace(/^pack:/, ''),
emojis,
}));
};
export {
type CustomEmoji,
type NativeEmoji,
@@ -79,5 +114,6 @@ export {
isCustomEmoji,
isNativeEmoji,
buildCustomEmojis,
buildCustomEmojiCategories,
validEmojiChar,
};

View File

@@ -691,6 +691,7 @@
"emoji_button.skins_choose": "Choose default skin tone",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"emoji_button.uncategorized": "Uncategorized",
"empty_column.account_blocked": "You are blocked by @{accountUsername}.",
"empty_column.account_favourited_statuses": "This user doesn't have any liked posts yet.",
"empty_column.account_timeline": "No posts here!",