[Glitch] Emoji: Add back to state
Port 963a54664804e60ea8e30795090a0f20de7a48dc to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
61237253dc
commit
4b67d8e34f
@ -22,10 +22,6 @@ export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) {
|
|||||||
await clearCache('custom');
|
await clearCache('custom');
|
||||||
await loadCustomEmoji();
|
await loadCustomEmoji();
|
||||||
|
|
||||||
const { reloadCustomEmojis } =
|
|
||||||
await import('@/flavours/glitch/features/emoji/picker');
|
|
||||||
await reloadCustomEmojis();
|
|
||||||
|
|
||||||
log('Custom emojis updated, reloaded cache and picker data.');
|
log('Custom emojis updated, reloaded cache and picker data.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,7 +140,7 @@ export const EditFieldModal = forwardRef<
|
|||||||
|
|
||||||
const customEmojis = useCustomEmojis();
|
const customEmojis = useCustomEmojis();
|
||||||
const customEmojiCodes = useMemo(
|
const customEmojiCodes = useMemo(
|
||||||
() => Object.keys(customEmojis ?? {}),
|
() => Object.keys(customEmojis),
|
||||||
[customEmojis],
|
[customEmojis],
|
||||||
);
|
);
|
||||||
const checkField = useCallback(
|
const checkField = useCallback(
|
||||||
|
|||||||
@ -323,10 +323,7 @@ class EmojiPickerDropdown extends PureComponent {
|
|||||||
EmojiPickerAsync().then(EmojiMart => {
|
EmojiPickerAsync().then(EmojiMart => {
|
||||||
EmojiPicker = EmojiMart.Picker;
|
EmojiPicker = EmojiMart.Picker;
|
||||||
Emoji = EmojiMart.Emoji;
|
Emoji = EmojiMart.Emoji;
|
||||||
|
this.setState({ loading: false });
|
||||||
void EmojiMart.loadCustomEmojiData().then(() => {
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.setState({ loading: false, active: false });
|
this.setState({ loading: false, active: false });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,8 +13,6 @@ import { usePickerEmojis } from './picker';
|
|||||||
|
|
||||||
const backgroundImageFnDefault = () => `${assetHost}/emoji/sheet_16_0.png`;
|
const backgroundImageFnDefault = () => `${assetHost}/emoji/sheet_16_0.png`;
|
||||||
|
|
||||||
export { fetchCustomEmojiData as loadCustomEmojiData } from './picker';
|
|
||||||
|
|
||||||
export const Picker: FC<PickerProps> = ({
|
export const Picker: FC<PickerProps> = ({
|
||||||
set = 'twitter',
|
set = 'twitter',
|
||||||
sheetSize = 32,
|
sheetSize = 32,
|
||||||
@ -24,17 +22,13 @@ export const Picker: FC<PickerProps> = ({
|
|||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const { mode } = useEmojiAppState();
|
const { mode } = useEmojiAppState();
|
||||||
const { customCategories, customEmojis } = usePickerEmojis();
|
const { categories, emojis } = usePickerEmojis();
|
||||||
|
|
||||||
if (!customEmojis) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PickerRaw
|
<PickerRaw
|
||||||
data={EmojiData}
|
data={EmojiData}
|
||||||
custom={customEmojis}
|
custom={emojis}
|
||||||
include={customCategories}
|
include={categories}
|
||||||
set={set}
|
set={set}
|
||||||
sheetSize={sheetSize}
|
sheetSize={sheetSize}
|
||||||
sheetColumns={sheetColumns}
|
sheetColumns={sheetColumns}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { initialState } from '@/flavours/glitch/initial_state';
|
import { initialState } from '@/flavours/glitch/initial_state';
|
||||||
|
|
||||||
import { toSupportedLocale } from './locale';
|
import { toSupportedLocale } from './locale';
|
||||||
import { reloadCustomEmojis } from './picker';
|
|
||||||
import type { EmojiWorkerMessage } from './types';
|
import type { EmojiWorkerMessage } from './types';
|
||||||
import { emojiLogger } from './utils';
|
import { emojiLogger } from './utils';
|
||||||
|
|
||||||
@ -39,27 +38,37 @@ export async function initializeEmoji() {
|
|||||||
void fallbackLoad();
|
void fallbackLoad();
|
||||||
}, WORKER_TIMEOUT);
|
}, WORKER_TIMEOUT);
|
||||||
|
|
||||||
tempWorker.addEventListener('message', (event: MessageEvent<string>) => {
|
tempWorker.addEventListener(
|
||||||
const { data: message } = event;
|
'message',
|
||||||
|
(event: MessageEvent<EmojiWorkerMessage>) => {
|
||||||
|
const { data: message } = event;
|
||||||
|
|
||||||
worker ??= tempWorker;
|
worker ??= tempWorker;
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
if (message !== 'ready') {
|
const { type } = message;
|
||||||
workerLog(message);
|
if (type === 'log') {
|
||||||
return;
|
workerLog(message.message);
|
||||||
}
|
} else if (type === 'done' && message.storeName === 'custom') {
|
||||||
|
void loadEmojisToStore();
|
||||||
|
}
|
||||||
|
|
||||||
const debugValue = localStorage.getItem('debug');
|
if (type !== 'ready') {
|
||||||
if (debugValue) {
|
return; // Exit for other messages.
|
||||||
messageWorker({ type: 'debug', debugValue });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
workerLog('loading data');
|
const debugValue = localStorage.getItem('debug');
|
||||||
messageWorker(userLocale);
|
if (debugValue) {
|
||||||
messageWorker('custom');
|
messageWorker({ type: 'debug', debugValue });
|
||||||
messageWorker('shortcodes');
|
}
|
||||||
});
|
|
||||||
|
workerLog('loading data');
|
||||||
|
messageWorker(userLocale);
|
||||||
|
messageWorker('custom');
|
||||||
|
messageWorker('shortcodes');
|
||||||
|
void loadEmojisToStore();
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fallbackLoad() {
|
async function fallbackLoad() {
|
||||||
@ -71,8 +80,8 @@ async function fallbackLoad() {
|
|||||||
const customEmojis = await importCustomEmojiData();
|
const customEmojis = await importCustomEmojiData();
|
||||||
if (customEmojis && customEmojis.length > 0) {
|
if (customEmojis && customEmojis.length > 0) {
|
||||||
log('loaded %d custom emojis', customEmojis.length);
|
log('loaded %d custom emojis', customEmojis.length);
|
||||||
await reloadCustomEmojis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortcodes = await importLegacyShortcodes();
|
const shortcodes = await importLegacyShortcodes();
|
||||||
if (shortcodes?.length) {
|
if (shortcodes?.length) {
|
||||||
log('loaded %d legacy shortcodes', shortcodes.length);
|
log('loaded %d legacy shortcodes', shortcodes.length);
|
||||||
@ -82,6 +91,7 @@ async function fallbackLoad() {
|
|||||||
if (emojis) {
|
if (emojis) {
|
||||||
log('loaded %d emojis to locale %s', emojis.length, userLocale);
|
log('loaded %d emojis to locale %s', emojis.length, userLocale);
|
||||||
}
|
}
|
||||||
|
await loadEmojisToStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadCustomEmoji() {
|
export async function loadCustomEmoji() {
|
||||||
@ -92,9 +102,9 @@ export async function loadCustomEmoji() {
|
|||||||
const emojis = await importCustomEmojiData();
|
const emojis = await importCustomEmojiData();
|
||||||
if (emojis && emojis.length > 0) {
|
if (emojis && emojis.length > 0) {
|
||||||
log('loaded %d custom emojis', emojis.length);
|
log('loaded %d custom emojis', emojis.length);
|
||||||
await reloadCustomEmojis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await loadEmojisToStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
function messageWorker(data: EmojiWorkerMessage | string) {
|
function messageWorker(data: EmojiWorkerMessage | string) {
|
||||||
@ -110,3 +120,14 @@ function messageWorker(data: EmojiWorkerMessage | string) {
|
|||||||
worker.postMessage(data);
|
worker.postMessage(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadEmojisToStore() {
|
||||||
|
const { store } = await import('@/flavours/glitch/store');
|
||||||
|
const { loadCustomEmojis, loadLocale } =
|
||||||
|
await import('@/flavours/glitch/reducers/slices/emojis');
|
||||||
|
|
||||||
|
loadLocale(userLocale);
|
||||||
|
await store.dispatch(loadCustomEmojis());
|
||||||
|
|
||||||
|
log('loaded emoji data into store');
|
||||||
|
}
|
||||||
|
|||||||
@ -27,7 +27,6 @@ export function useEmojiAppState(): EmojiAppState {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
currentLocale: locale,
|
currentLocale: locale,
|
||||||
locales: [locale],
|
|
||||||
mode,
|
mode,
|
||||||
darkTheme: isDarkMode(),
|
darkTheme: isDarkMode(),
|
||||||
assetHost,
|
assetHost,
|
||||||
@ -64,7 +63,6 @@ export function getEmojiAppState(): EmojiAppState {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
currentLocale,
|
currentLocale,
|
||||||
locales: [currentLocale],
|
|
||||||
mode: determineEmojiMode(emojiStyle),
|
mode: determineEmojiMode(emojiStyle),
|
||||||
darkTheme: isDarkMode(),
|
darkTheme: isDarkMode(),
|
||||||
assetHost,
|
assetHost,
|
||||||
|
|||||||
@ -1,83 +1,18 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import type { CategoryName, CustomEmoji } from 'emoji-mart';
|
import type { CategoryName, CustomEmoji } from 'emoji-mart';
|
||||||
|
|
||||||
import { autoPlayGif } from '@/flavours/glitch/initial_state';
|
import { autoPlayGif } from '@/flavours/glitch/initial_state';
|
||||||
|
import {
|
||||||
|
createAppSelector,
|
||||||
|
useAppSelector,
|
||||||
|
} from '@/flavours/glitch/store/typed_functions';
|
||||||
import { createLimitedCache } from '@/flavours/glitch/utils/cache';
|
import { createLimitedCache } from '@/flavours/glitch/utils/cache';
|
||||||
|
|
||||||
import { emojiLogger } from './utils';
|
import { emojiLogger } from './utils';
|
||||||
|
|
||||||
const log = emojiLogger('picker');
|
const log = emojiLogger('picker');
|
||||||
|
|
||||||
let customEmojis: CustomEmoji[] | null = null;
|
|
||||||
let customCategories = [
|
|
||||||
'recent',
|
|
||||||
'people',
|
|
||||||
'nature',
|
|
||||||
'foods',
|
|
||||||
'activity',
|
|
||||||
'places',
|
|
||||||
'objects',
|
|
||||||
'symbols',
|
|
||||||
'flags',
|
|
||||||
] as CategoryName[];
|
|
||||||
|
|
||||||
const searchCache = createLimitedCache<LegacyEmoji[]>({ maxSize: 10, log });
|
const searchCache = createLimitedCache<LegacyEmoji[]>({ maxSize: 10, log });
|
||||||
|
|
||||||
export async function fetchCustomEmojiData() {
|
|
||||||
if (customEmojis !== null) {
|
|
||||||
return customEmojis;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { loadAllCustomEmoji } = await import('./database');
|
|
||||||
const emojisRaw = await loadAllCustomEmoji();
|
|
||||||
|
|
||||||
// If it returns null then custom emojis aren't even loaded yet.
|
|
||||||
if (emojisRaw === null) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's empty, then they are loaded but there aren't any.
|
|
||||||
if (emojisRaw.length === 0) {
|
|
||||||
customEmojis = [];
|
|
||||||
return customEmojis;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
type LegacyEmoji =
|
type LegacyEmoji =
|
||||||
| { id: string; custom?: false; native: string }
|
| { id: string; custom?: false; native: string }
|
||||||
| {
|
| {
|
||||||
@ -85,16 +20,6 @@ type LegacyEmoji =
|
|||||||
custom: true;
|
custom: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function reloadCustomEmojis() {
|
|
||||||
customEmojis = null;
|
|
||||||
|
|
||||||
const { loadEmojisIntoCache } =
|
|
||||||
await import('@/flavours/glitch/hooks/useCustomEmojis');
|
|
||||||
|
|
||||||
await Promise.all([fetchCustomEmojiData(), loadEmojisIntoCache()]);
|
|
||||||
searchCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replicates the old legacy search function.
|
// Replicates the old legacy search function.
|
||||||
export async function emojiMartSearch(
|
export async function emojiMartSearch(
|
||||||
token: string,
|
token: string,
|
||||||
@ -127,19 +52,64 @@ export async function emojiMartSearch(
|
|||||||
return legacyResults;
|
return legacyResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePickerEmojis() {
|
const defaultCategories = [
|
||||||
const [, setLoaded] = useState(customEmojis !== null);
|
'people',
|
||||||
|
'nature',
|
||||||
|
'foods',
|
||||||
|
'activity',
|
||||||
|
'places',
|
||||||
|
'objects',
|
||||||
|
'symbols',
|
||||||
|
'flags',
|
||||||
|
] as CategoryName[];
|
||||||
|
|
||||||
useEffect(() => {
|
const selectPickerData = createAppSelector(
|
||||||
if (customEmojis === null) {
|
[(state) => state.emojis.custom, (state) => state.emojis.customCategories],
|
||||||
void fetchCustomEmojiData().then(() => {
|
(emojis, categories) => {
|
||||||
setLoaded(true);
|
// Create a map of shortcode to category name.
|
||||||
});
|
const categoryMap = new Map<string, string>();
|
||||||
|
for (const category in categories) {
|
||||||
|
const catEmojis = categories[category];
|
||||||
|
if (!catEmojis?.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const shortcode of catEmojis) {
|
||||||
|
categoryMap.set(shortcode, category);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
const customEmojis: CustomEmoji[] = [];
|
||||||
customEmojis,
|
for (const shortcode in emojis) {
|
||||||
customCategories,
|
const emoji = emojis[shortcode];
|
||||||
};
|
if (!emoji) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
customEmojis.push({
|
||||||
|
name: shortcode,
|
||||||
|
id: shortcode,
|
||||||
|
custom: true,
|
||||||
|
short_names: [shortcode],
|
||||||
|
imageUrl: autoPlayGif ? emoji.url : emoji.static_url,
|
||||||
|
customCategory: categoryMap.get(shortcode),
|
||||||
|
} as CustomEmoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchCache.clear();
|
||||||
|
log('regenerated the picker data');
|
||||||
|
|
||||||
|
return {
|
||||||
|
emojis: customEmojis,
|
||||||
|
categories: [
|
||||||
|
'recent',
|
||||||
|
'custom',
|
||||||
|
...Object.keys(categories).toSorted(),
|
||||||
|
...defaultCategories,
|
||||||
|
] as CategoryName[],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export function usePickerEmojis() {
|
||||||
|
return useAppSelector(selectPickerData);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,7 @@ export async function updateHtmlWithEmoji({
|
|||||||
}: {
|
}: {
|
||||||
element: Element;
|
element: Element;
|
||||||
locale: string;
|
locale: string;
|
||||||
} & Omit<EmojiAppState, 'currentLocale' | 'locales'>) {
|
} & Omit<EmojiAppState, 'currentLocale'>) {
|
||||||
if (mode === EMOJI_MODE_NATIVE) {
|
if (mode === EMOJI_MODE_NATIVE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,6 @@ export type CacheKey =
|
|||||||
| LocaleWithShortcodes;
|
| LocaleWithShortcodes;
|
||||||
|
|
||||||
export interface EmojiAppState {
|
export interface EmojiAppState {
|
||||||
locales: Locale[];
|
|
||||||
currentLocale: Locale;
|
currentLocale: Locale;
|
||||||
mode: EmojiMode;
|
mode: EmojiMode;
|
||||||
darkTheme: boolean;
|
darkTheme: boolean;
|
||||||
@ -82,10 +81,20 @@ export type ExtraCustomEmojiMap = Record<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export type EmojiWorkerMessage =
|
export type EmojiWorkerMessage =
|
||||||
|
| { type: 'ready' }
|
||||||
| {
|
| {
|
||||||
type: 'load';
|
type: 'load';
|
||||||
storeName: string;
|
storeName: string;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'done';
|
||||||
|
storeName: string;
|
||||||
|
importCount: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'log';
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'debug';
|
type: 'debug';
|
||||||
debugValue: string;
|
debugValue: string;
|
||||||
|
|||||||
@ -9,13 +9,13 @@ import {
|
|||||||
import type { EmojiWorkerMessage } from './types';
|
import type { EmojiWorkerMessage } from './types';
|
||||||
|
|
||||||
addEventListener('message', handleMessage);
|
addEventListener('message', handleMessage);
|
||||||
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
self.postMessage({ type: 'ready' } satisfies EmojiWorkerMessage); // After the worker is ready, notify the main thread
|
||||||
|
|
||||||
function handleMessage(event: MessageEvent<EmojiWorkerMessage>) {
|
function handleMessage(event: MessageEvent<EmojiWorkerMessage>) {
|
||||||
const { data } = event;
|
const { data } = event;
|
||||||
if (data.type === 'debug') {
|
if (data.type === 'debug') {
|
||||||
debug.enable(data.debugValue);
|
debug.enable(data.debugValue);
|
||||||
} else {
|
} else if (data.type === 'load') {
|
||||||
void loadData(data.storeName);
|
void loadData(data.storeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +31,10 @@ async function loadData(storeName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (importCount) {
|
if (importCount) {
|
||||||
self.postMessage(`loaded ${importCount} emojis into ${storeName}`);
|
self.postMessage({
|
||||||
|
type: 'done',
|
||||||
|
storeName,
|
||||||
|
importCount,
|
||||||
|
} satisfies EmojiWorkerMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +1,25 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { createAppSelector, useAppSelector } from '@/flavours/glitch/store';
|
||||||
|
|
||||||
import type { ExtraCustomEmojiMap } from '../features/emoji/types';
|
import type { ExtraCustomEmojiMap } from '../features/emoji/types';
|
||||||
import { emojiLogger } from '../features/emoji/utils';
|
|
||||||
|
|
||||||
let emojis: ExtraCustomEmojiMap | null = null;
|
const selectCustomEmojis = createAppSelector(
|
||||||
|
[(state) => state.emojis.custom],
|
||||||
const log = emojiLogger('useCustomEmojis');
|
(custom) => {
|
||||||
|
const emojis: ExtraCustomEmojiMap = {};
|
||||||
|
for (const shortcode in custom) {
|
||||||
|
const emoji = custom[shortcode];
|
||||||
|
if (!emoji) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
emojis[shortcode] = {
|
||||||
|
shortcode,
|
||||||
|
...emoji,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return emojis;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export function useCustomEmojis() {
|
export function useCustomEmojis() {
|
||||||
const [, setLoaded] = useState(emojis !== null);
|
return useAppSelector(selectCustomEmojis);
|
||||||
useEffect(() => {
|
|
||||||
if (!emojis) {
|
|
||||||
void loadEmojisIntoCache().then(() => {
|
|
||||||
setLoaded(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return emojis;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadEmojisIntoCache() {
|
|
||||||
const { loadAllCustomEmoji } = await import('../features/emoji/database');
|
|
||||||
const emojisRaw = await loadAllCustomEmoji();
|
|
||||||
if (emojisRaw === null) {
|
|
||||||
log('Custom emojis not loaded yet');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emojis = {};
|
|
||||||
for (const emoji of emojisRaw) {
|
|
||||||
emojis[emoji.shortcode] = {
|
|
||||||
url: emoji.url,
|
|
||||||
shortcode: emoji.shortcode,
|
|
||||||
static_url: emoji.static_url,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
log('Loaded %d custom emojis into cache', Object.keys(emojis).length);
|
|
||||||
}
|
}
|
||||||
|
|||||||
71
app/javascript/flavours/glitch/reducers/slices/emojis.ts
Normal file
71
app/javascript/flavours/glitch/reducers/slices/emojis.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
import type { Locale } from 'emojibase';
|
||||||
|
|
||||||
|
import type { ApiCustomEmojiJSON } from '@/flavours/glitch/api_types/custom_emoji';
|
||||||
|
import { toSupportedLocale } from '@/flavours/glitch/features/emoji/locale';
|
||||||
|
import { createAsyncThunk } from '@/flavours/glitch/store/typed_functions';
|
||||||
|
|
||||||
|
interface EmojisState {
|
||||||
|
custom: Record<string, Pick<ApiCustomEmojiJSON, 'url' | 'static_url'>>;
|
||||||
|
customCategories: Record<string, string[]>; // { name: shortcodes[] }
|
||||||
|
customLoaded: boolean;
|
||||||
|
localesLoaded: Locale[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojisSlice = createSlice({
|
||||||
|
name: 'emojis',
|
||||||
|
initialState: {
|
||||||
|
custom: {},
|
||||||
|
customCategories: {},
|
||||||
|
customLoaded: false,
|
||||||
|
localesLoaded: [],
|
||||||
|
} as EmojisState,
|
||||||
|
reducers: {
|
||||||
|
loadLocale(state, action: PayloadAction<string>) {
|
||||||
|
const locale = toSupportedLocale(action.payload);
|
||||||
|
if (!state.localesLoaded.includes(locale)) {
|
||||||
|
state.localesLoaded.push(locale);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extraReducers(builder) {
|
||||||
|
builder.addAsyncThunk(loadCustomEmojis, {
|
||||||
|
fulfilled(state, action) {
|
||||||
|
if (!action.payload?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const emoji of action.payload) {
|
||||||
|
const { shortcode, category, url, static_url } = emoji;
|
||||||
|
state.custom[shortcode] = {
|
||||||
|
url,
|
||||||
|
static_url,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
state.customCategories[category] ??= [];
|
||||||
|
if (!state.customCategories[category].includes(shortcode)) {
|
||||||
|
state.customCategories[category].push(shortcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.customLoaded = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emojis = emojisSlice.reducer;
|
||||||
|
export const { loadLocale } = emojisSlice.actions;
|
||||||
|
|
||||||
|
export const loadCustomEmojis = createAsyncThunk(
|
||||||
|
`${emojisSlice.name}/loadCustomEmojis`,
|
||||||
|
async () => {
|
||||||
|
const { loadAllCustomEmoji } =
|
||||||
|
await import('@/flavours/glitch/features/emoji/database');
|
||||||
|
return loadAllCustomEmoji();
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -1,9 +1,11 @@
|
|||||||
import { annualReport } from './annual_report';
|
import { annualReport } from './annual_report';
|
||||||
import { collections } from './collections';
|
import { collections } from './collections';
|
||||||
|
import { emojis } from './emojis';
|
||||||
import { profileEdit } from './profile_edit';
|
import { profileEdit } from './profile_edit';
|
||||||
|
|
||||||
export const sliceReducers = {
|
export const sliceReducers = {
|
||||||
annualReport,
|
annualReport,
|
||||||
collections,
|
collections,
|
||||||
|
emojis,
|
||||||
profileEdit,
|
profileEdit,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user