Add support for suggesting emojis

This commit is contained in:
Rafael 2021-12-06 17:38:13 -03:00 committed by Thomas Zarebczan
parent db5f24ae28
commit 1695312833
2 changed files with 25 additions and 8 deletions

View file

@ -12,11 +12,11 @@ export default function TextareaSuggestionsItem(props: Props) {
const { claim, emote, uri, ...autocompleteProps } = props; const { claim, emote, uri, ...autocompleteProps } = props;
if (emote) { if (emote) {
const { name: value, url } = emote; const { name: value, url, unicode } = emote;
return ( return (
<div {...autocompleteProps}> <div {...autocompleteProps}>
<img className="emote" src={url} /> {unicode ? <div className="emote">{unicode}</div> : <img className="emote" src={url} />}
<div className="textareaSuggestion__label"> <div className="textareaSuggestion__label">
<span className="textareaSuggestion__title textareaSuggestion__value textareaSuggestion__value--emote"> <span className="textareaSuggestion__title textareaSuggestion__value textareaSuggestion__value--emote">

View file

@ -4,6 +4,7 @@ import { matchSorter } from 'match-sorter';
import { SEARCH_OPTIONS } from 'constants/search'; import { SEARCH_OPTIONS } from 'constants/search';
import * as KEYCODES from 'constants/keycodes'; import * as KEYCODES from 'constants/keycodes';
import Autocomplete from '@mui/material/Autocomplete'; import Autocomplete from '@mui/material/Autocomplete';
import EMOJIS from 'emoji-dictionary';
import React from 'react'; import React from 'react';
import TextareaSuggestionsItem from 'component/textareaSuggestionsItem'; import TextareaSuggestionsItem from 'component/textareaSuggestionsItem';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
@ -11,7 +12,7 @@ import useLighthouse from 'effects/use-lighthouse';
import useThrottle from 'effects/use-throttle'; import useThrottle from 'effects/use-throttle';
const SUGGESTION_REGEX = new RegExp( const SUGGESTION_REGEX = new RegExp(
'(?<Mention>(?:^| |\n)@[^\\s=&#$@%?:;/\\"<>%{}|^~[]*(?::[\\w]+)?)|(?<Emote>(?:^| |\n):[\\w]*:?)', '(?<Mention>(?:^| |\n)@[^\\s=&#$@%?:;/\\"<>%{}|^~[]*(?::[\\w]+)?)|(?<Emote>(?:^| |\n):[\\w+-]*:?)',
'gm' 'gm'
); );
@ -30,6 +31,8 @@ const SEARCH_SIZE = 10;
const LIGHTHOUSE_MIN_CHARACTERS = 3; const LIGHTHOUSE_MIN_CHARACTERS = 3;
const INPUT_DEBOUNCE_MS = 1000; const INPUT_DEBOUNCE_MS = 1000;
const EMOJI_MIN_CHARACTERS = 2;
type Props = { type Props = {
canonicalCommentors?: Array<string>, canonicalCommentors?: Array<string>,
canonicalCreatorUri?: string, canonicalCreatorUri?: string,
@ -106,10 +109,16 @@ export default function TextareaWithSuggestions(props: Props) {
canonicalSearch && canonicalSearch &&
canonicalSearch.filter((uri) => shouldFilter(uri, filteredSubs) && shouldFilter(uri, filteredCommentors)); canonicalSearch.filter((uri) => shouldFilter(uri, filteredSubs) && shouldFilter(uri, filteredCommentors));
let emoteNames;
let emojiNames;
const allOptions = []; const allOptions = [];
if (isEmote) { if (isEmote) {
const emoteNames = EMOTES.map(({ name }) => name.toLowerCase()); emoteNames = EMOTES.map(({ name }) => name.toLowerCase());
allOptions.push(...emoteNames); const hasMinEmojiLength = suggestionTerm && suggestionTerm.length > EMOJI_MIN_CHARACTERS;
emojiNames = hasMinEmojiLength ? EMOJIS.names : [];
const emotesAndEmojis = [...emoteNames, ...emojiNames];
allOptions.push(...emotesAndEmojis);
} else { } else {
if (canonicalCreatorUri) allOptions.push(canonicalCreatorUri); if (canonicalCreatorUri) allOptions.push(canonicalCreatorUri);
if (filteredSubs) allOptions.push(...filteredSubs); if (filteredSubs) allOptions.push(...filteredSubs);
@ -121,14 +130,20 @@ export default function TextareaWithSuggestions(props: Props) {
allOptions.length > 0 allOptions.length > 0
? allOptions.map((option) => { ? allOptions.map((option) => {
const groupName = isEmote const groupName = isEmote
? __('Emotes') ? (emoteNames.includes(option) && __('Emotes')) || (emojiNames.includes(option) && __('Emojis'))
: (canonicalCreatorUri === option && __('Creator')) || : (canonicalCreatorUri === option && __('Creator')) ||
(filteredSubs && filteredSubs.includes(option) && __('Following')) || (filteredSubs && filteredSubs.includes(option) && __('Following')) ||
(filteredCommentors && filteredCommentors.includes(option) && __('From Comments')) || (filteredCommentors && filteredCommentors.includes(option) && __('From Comments')) ||
(filteredSearch && filteredSearch.includes(option) && __('From Search')); (filteredSearch && filteredSearch.includes(option) && __('From Search'));
let emoteLabel;
if (isEmote) {
// $FlowFixMe
emoteLabel = `:${option.replaceAll(':', '')}:`;
}
return { return {
label: isEmote ? option : option.replace('lbry://', '').replace('#', ':'), label: emoteLabel || option.replace('lbry://', '').replace('#', ':'),
group: groupName, group: groupName,
}; };
}) })
@ -321,8 +336,10 @@ export default function TextareaWithSuggestions(props: Props) {
const renderOption = (optionProps: any, label: string) => { const renderOption = (optionProps: any, label: string) => {
const emoteFound = isEmote && EMOTES.find(({ name }) => name.toLowerCase() === label); const emoteFound = isEmote && EMOTES.find(({ name }) => name.toLowerCase() === label);
const emoteValue = emoteFound ? { name: label, url: emoteFound.url } : undefined; const emoteValue = emoteFound ? { name: label, url: emoteFound.url } : undefined;
const emojiFound = isEmote && EMOJIS.getUnicode(label);
const emojiValue = emojiFound ? { name: label, unicode: emojiFound } : undefined;
return <TextareaSuggestionsItem uri={label} emote={emoteValue} {...optionProps} />; return <TextareaSuggestionsItem uri={label} emote={emoteValue || emojiValue} {...optionProps} />;
}; };
return ( return (