[Glitch] Fixes custom emoji not appearing in autocomplete

Port a47ed3104718ce6f69bca2c028b267988a28c26b to glitch-soc

Co-authored-by: Copilot <copilot@github.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Echo 2026-04-29 21:44:42 +02:00 committed by Claire
parent e4fba99ab5
commit 1f0fb21039
3 changed files with 101 additions and 82 deletions

View File

@ -8,6 +8,7 @@ import { browserHistory } from 'flavours/glitch/components/router';
import { countableText } from 'flavours/glitch/features/compose/util/counter';
import { search as emojiSearch } from 'flavours/glitch/features/emoji/emoji_mart_search_light';
import { tagHistory } from 'flavours/glitch/settings';
import { fetchCustomEmojiData } from '@/flavours/glitch/features/emoji/picker';
import { recoverHashtags } from 'flavours/glitch/utils/hashtag';
import { showAlert, showAlertForError } from './alerts';
@ -597,7 +598,7 @@ export function clearComposeSuggestions() {
};
}
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
const fetchComposeSuggestionsAccounts = throttle((dispatch, token) => {
if (fetchComposeSuggestionsAccountsController) {
fetchComposeSuggestionsAccountsController.abort();
}
@ -624,12 +625,13 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
});
}, 200, { leading: true, trailing: true });
const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => {
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 });
const fetchComposeSuggestionsEmojis = async (dispatch, token) => {
const custom = await fetchCustomEmojiData();
const results = emojiSearch(token.replace(':', ''), { maxResults: 5, custom });
dispatch(readyComposeSuggestionsEmojis(token, results));
};
const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => {
const fetchComposeSuggestionsTags = throttle((dispatch, token) => {
if (fetchComposeSuggestionsTagsController) {
fetchComposeSuggestionsTagsController.abort();
}
@ -662,14 +664,14 @@ export function fetchComposeSuggestions(token) {
return (dispatch, getState) => {
switch (token[0]) {
case ':':
fetchComposeSuggestionsEmojis(dispatch, getState, token);
void fetchComposeSuggestionsEmojis(dispatch, token);
break;
case '#':
case '':
fetchComposeSuggestionsTags(dispatch, getState, token);
fetchComposeSuggestionsTags(dispatch, token);
break;
default:
fetchComposeSuggestionsAccounts(dispatch, getState, token);
fetchComposeSuggestionsAccounts(dispatch, token);
break;
}
};

View File

@ -1,39 +1,19 @@
import type { FC } from 'react';
import { useEffect, useState } from 'react';
import type {
CategoryName,
CustomEmoji,
EmojiProps,
PickerProps,
} from 'emoji-mart';
import type { EmojiProps, PickerProps } from 'emoji-mart';
import EmojiRaw from 'emoji-mart/dist-es/components/emoji/nimble-emoji';
import PickerRaw from 'emoji-mart/dist-es/components/picker/nimble-picker';
import { autoPlayGif } from '@/flavours/glitch/initial_state';
import { assetHost } from 'flavours/glitch/utils/config';
import { assetHost } from '@/flavours/glitch/utils/config';
import { EMOJI_MODE_NATIVE } from './constants';
import EmojiData from './emoji_data.json';
import { useEmojiAppState } from './mode';
import { emojiLogger } from './utils';
import { usePickerEmojis } from './picker';
const backgroundImageFnDefault = () => `${assetHost}/emoji/sheet_16_0.png`;
let customEmojis: CustomEmoji[] | null = null;
let customCategories = [
'recent',
'people',
'nature',
'foods',
'activity',
'places',
'objects',
'symbols',
'flags',
] as CategoryName[];
const log = emojiLogger('picker');
export { fetchCustomEmojiData as loadCustomEmojiData } from './picker';
export const Picker: FC<PickerProps> = ({
set = 'twitter',
@ -44,24 +24,16 @@ export const Picker: FC<PickerProps> = ({
...props
}) => {
const { mode } = useEmojiAppState();
const [isLoaded, setLoaded] = useState(customEmojis !== null);
const { customCategories, customEmojis } = usePickerEmojis();
useEffect(() => {
if (customEmojis === null) {
void loadCustomEmojiData().then(() => {
setLoaded(true);
});
}
}, []);
if (!isLoaded) {
if (!customEmojis) {
return null;
}
return (
<PickerRaw
data={EmojiData}
custom={customEmojis ?? []}
custom={customEmojis}
include={customCategories}
set={set}
sheetSize={sheetSize}
@ -74,46 +46,6 @@ export const Picker: FC<PickerProps> = ({
);
};
export async function loadCustomEmojiData() {
const { loadAllCustomEmoji } = await import('./database');
const emojisRaw = await loadAllCustomEmoji();
if (emojisRaw.length === 0) {
return;
}
const categories = new Set(['custom']);
const emojis = [];
for (const emoji of emojisRaw) {
const name = emoji.shortcode.replaceAll(':', '');
emojis.push({
name,
id: name,
custom: true,
short_names: [name],
imageUrl: autoPlayGif ? emoji.url : emoji.static_url,
customCategory: emoji.category,
});
if (emoji.category) {
categories.add(`custom-${emoji.category}`);
}
}
customEmojis = emojis.toSorted((a, b) => {
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
});
customCategories = customCategories.toSpliced(
1,
0,
...(Array.from(categories).toSorted() as CategoryName[]),
);
log(
'loaded %d custom emojis in %d categories',
customEmojis.length,
categories.size,
);
}
export const Emoji: FC<EmojiProps> = ({
set = 'twitter',
sheetSize = 32,

View File

@ -0,0 +1,85 @@
import { useEffect, useState } from 'react';
import type { CategoryName, CustomEmoji } from 'emoji-mart';
import { autoPlayGif } from '@/flavours/glitch/initial_state';
import { emojiLogger } from './utils';
const log = emojiLogger('picker');
let customEmojis: CustomEmoji[] | null = null;
let customCategories = [
'recent',
'people',
'nature',
'foods',
'activity',
'places',
'objects',
'symbols',
'flags',
] as CategoryName[];
export async function fetchCustomEmojiData() {
if (customEmojis !== null) {
return customEmojis;
}
const { loadAllCustomEmoji } = await import('./database');
const emojisRaw = await loadAllCustomEmoji();
if (emojisRaw.length === 0) {
return [];
}
const categories = new Set(['custom']);
const emojis = [];
for (const emoji of emojisRaw) {
const name = emoji.shortcode.replaceAll(':', '');
emojis.push({
name,
id: name,
custom: true,
short_names: [name],
imageUrl: autoPlayGif ? emoji.url : emoji.static_url,
customCategory: emoji.category,
});
if (emoji.category) {
categories.add(`custom-${emoji.category}`);
}
}
customEmojis = emojis.toSorted((a, b) => {
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
});
customCategories = customCategories.toSpliced(
1,
0,
...(Array.from(categories).toSorted() as CategoryName[]),
);
log(
'loaded %d custom emojis in %d categories',
customEmojis.length,
categories.size,
);
return customEmojis;
}
export function usePickerEmojis() {
const [, setLoaded] = useState(customEmojis !== null);
useEffect(() => {
if (customEmojis === null) {
void fetchCustomEmojiData().then(() => {
setLoaded(true);
});
}
}, []);
return {
customEmojis,
customCategories,
};
}