Add useFrequentlyUsedEmojis hook, remove legacy code
This commit is contained in:
parent
8ad449cb13
commit
f342afde5c
|
@ -8,12 +8,12 @@ import { closeModal, openModal } from 'soapbox/actions/modals.ts';
|
|||
import EmojiComponent from 'soapbox/components/ui/emoji.tsx';
|
||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import IconButton from 'soapbox/components/ui/icon-button.tsx';
|
||||
import EmojiPickerDropdown, { getFrequentlyUsedEmojis } from 'soapbox/features/emoji/components/emoji-picker-dropdown.tsx';
|
||||
import EmojiPickerDropdown from 'soapbox/features/emoji/components/emoji-picker-dropdown.tsx';
|
||||
import emojiData from 'soapbox/features/emoji/data.ts';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { useClickOutside } from 'soapbox/hooks/useClickOutside.ts';
|
||||
import { useFeatures } from 'soapbox/hooks/useFeatures.ts';
|
||||
import { useFrequentlyUsedEmojis } from 'soapbox/hooks/useFrequentlyUsedEmojis.ts';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
|
||||
import { userTouching } from 'soapbox/is-mobile.ts';
|
||||
|
||||
|
@ -74,7 +74,7 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
|
|||
}): JSX.Element => {
|
||||
const { allowedEmoji } = useSoapboxConfig();
|
||||
const { customEmojiReacts } = useFeatures();
|
||||
const shortcodes = useAppSelector((state) => getFrequentlyUsedEmojis(state));
|
||||
const frequentlyUsedEmojis = useFrequentlyUsedEmojis();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
@ -138,7 +138,8 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
|
|||
onClose?.();
|
||||
});
|
||||
|
||||
const recentEmojis = shortcodes.reduce<string[]>((results, shortcode) => {
|
||||
/** Frequently used emojis converted from shortcodes to native. */
|
||||
const frequentNative = frequentlyUsedEmojis.reduce<string[]>((results, shortcode) => {
|
||||
const emoji = emojiData.emojis[shortcode]?.skins[0]?.native;
|
||||
if (emoji) {
|
||||
results.push(emoji);
|
||||
|
@ -146,7 +147,8 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
|
|||
return results;
|
||||
}, []);
|
||||
|
||||
const emojis = new Set([...recentEmojis, ...allowedEmoji]);
|
||||
/** Set of native emojis to display in the selector. */
|
||||
const emojis = new Set([...frequentNative, ...allowedEmoji]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { useEffect, useState, useLayoutEffect, Suspense } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { chooseEmoji } from 'soapbox/actions/emojis.ts';
|
||||
import { changeSetting } from 'soapbox/actions/settings.ts';
|
||||
|
@ -9,9 +7,8 @@ import { useCustomEmojis } from 'soapbox/api/hooks/useCustomEmojis.ts';
|
|||
import { buildCustomEmojis } from 'soapbox/features/emoji/index.ts';
|
||||
import { EmojiPicker } from 'soapbox/features/ui/util/async-components.ts';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { useFrequentlyUsedEmojis } from 'soapbox/hooks/useFrequentlyUsedEmojis.ts';
|
||||
import { useTheme } from 'soapbox/hooks/useTheme.ts';
|
||||
import { RootState } from 'soapbox/store.ts';
|
||||
|
||||
import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji/index.ts';
|
||||
import type { CustomEmoji as MastodonCustomEmoji } from 'soapbox/schemas/custom-emoji.ts';
|
||||
|
@ -52,20 +49,6 @@ export interface IEmojiPickerDropdown {
|
|||
update?: (() => any) | null;
|
||||
}
|
||||
|
||||
const perLine = 8;
|
||||
const lines = 2;
|
||||
|
||||
export const getFrequentlyUsedEmojis = createSelector([
|
||||
(state: RootState) => state.settings.get('frequentlyUsedEmojis', ImmutableMap()),
|
||||
], (emojiCounters: ImmutableMap<string, number>) => {
|
||||
return emojiCounters
|
||||
.keySeq()
|
||||
.sort((a, b) => emojiCounters.get(a)! - emojiCounters.get(b)!)
|
||||
.reverse()
|
||||
.slice(0, perLine * lines)
|
||||
.toArray();
|
||||
});
|
||||
|
||||
/** Filter custom emojis to only ones visible in the picker, and sort them alphabetically. */
|
||||
function filterCustomEmojis(customEmojis: MastodonCustomEmoji[]) {
|
||||
return customEmojis.filter(e => e.visible_in_picker).sort((a, b) => {
|
||||
|
@ -115,7 +98,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
const theme = useTheme();
|
||||
|
||||
const { customEmojis } = useCustomEmojis();
|
||||
const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state));
|
||||
const frequentlyUsedEmojis = useFrequentlyUsedEmojis();
|
||||
|
||||
const handlePick = (emoji: any) => {
|
||||
setVisible?.(false);
|
||||
|
@ -206,7 +189,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
custom={withCustom ? [{ emojis: buildCustomEmojis(filterCustomEmojis(customEmojis)) }] : undefined}
|
||||
title={title}
|
||||
onEmojiSelect={handlePick}
|
||||
recent={frequentlyUsedEmojis}
|
||||
recent={frequentlyUsedEmojis.slice(0, 16)}
|
||||
perLine={8}
|
||||
skin={handleSkinTone}
|
||||
emojiSize={22}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { useMemo } from 'react';
|
||||
|
||||
import { useSettings } from 'soapbox/hooks/useSettings.ts';
|
||||
|
||||
/** Return a sorted list of most used emoji **shortcodes** from settings. */
|
||||
export function useFrequentlyUsedEmojis(): string[] {
|
||||
const { frequentlyUsedEmojis } = useSettings();
|
||||
|
||||
return useMemo(() => {
|
||||
return Object.entries(frequentlyUsedEmojis)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([emoji]) => emoji);
|
||||
|
||||
}, [frequentlyUsedEmojis]);
|
||||
}
|
|
@ -75,6 +75,10 @@ const settingsSchema = z.object({
|
|||
}),
|
||||
/** Settings notifications that have been dismissed. See `useSettingsNotifications` hook. */
|
||||
dismissedSettingsNotifications: z.array(z.string()).catch([]),
|
||||
frequentlyUsedEmojis: z.record(
|
||||
z.string(),
|
||||
z.number().int().nonnegative(),
|
||||
).catch({}),
|
||||
});
|
||||
|
||||
type Settings = z.infer<typeof settingsSchema>;
|
||||
|
|
Loading…
Reference in New Issue