Update en.json

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
environments/review-update-emo-25jnc5/deployments/2714
marcin mikołajczak 2 years ago
parent dfa5d3ec8e
commit e6d6ac6d44

@ -1,16 +1,11 @@
import { Placement } from '@popperjs/core'; import { Placement } from '@popperjs/core';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import { usePopper } from 'react-popper'; import { usePopper } from 'react-popper';
import { changeSetting } from 'soapbox/actions/settings';
import { Emoji, HStack, IconButton } from 'soapbox/components/ui'; import { Emoji, HStack, IconButton } from 'soapbox/components/ui';
import { getFrequentlyUsedEmojis, messages } from 'soapbox/features/emoji/components/emoji-picker-dropdown'; import EmojiPickerDropdown from 'soapbox/features/emoji/components/emoji-picker-dropdown';
import { EmojiPicker as EmojiPickerAsync } from 'soapbox/features/ui/util/async-components'; import { useSoapboxConfig } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useSettings, useSoapboxConfig } from 'soapbox/hooks';
let EmojiPicker: any; // load asynchronously
interface IEmojiButton { interface IEmojiButton {
/** Unicode emoji character. */ /** Unicode emoji character. */
@ -64,28 +59,15 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
offset = [-10, 0], offset = [-10, 0],
all = true, all = true,
}): JSX.Element => { }): JSX.Element => {
const intl = useIntl();
const dispatch = useAppDispatch();
const frequentlyUsedEmojis = useAppSelector(state => getFrequentlyUsedEmojis(state));
const settings = useSettings();
const userTheme = settings.get('themeMode');
const theme = (userTheme === 'dark' || userTheme === 'light') ? userTheme : 'auto';
const soapboxConfig = useSoapboxConfig(); const soapboxConfig = useSoapboxConfig();
const title = intl.formatMessage(messages.emoji);
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const [loading, setLoading] = useState(false);
// `useRef` won't trigger a re-render, while `useState` does. // `useRef` won't trigger a re-render, while `useState` does.
// https://popper.js.org/react-popper/v2/ // https://popper.js.org/react-popper/v2/
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null); const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const onSkinTone = (skinTone: string) => {
dispatch(changeSetting(['skinTone'], skinTone));
};
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if ([referenceElement, popperElement].some(el => el?.contains(event.target as Node))) { if ([referenceElement, popperElement].some(el => el?.contains(event.target as Node))) {
return; return;
@ -116,38 +98,6 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
setExpanded(true); setExpanded(true);
}; };
const getI18n = () => {
return {
search: intl.formatMessage(messages.emoji_search),
pick: intl.formatMessage(messages.emoji_pick),
search_no_results_1: intl.formatMessage(messages.emoji_oh_no),
search_no_results_2: intl.formatMessage(messages.emoji_not_found),
add_custom: intl.formatMessage(messages.emoji_add_custom),
categories: {
search: intl.formatMessage(messages.search_results),
frequent: intl.formatMessage(messages.recent),
people: intl.formatMessage(messages.people),
nature: intl.formatMessage(messages.nature),
foods: intl.formatMessage(messages.food),
activity: intl.formatMessage(messages.activity),
places: intl.formatMessage(messages.travel),
objects: intl.formatMessage(messages.objects),
symbols: intl.formatMessage(messages.symbols),
flags: intl.formatMessage(messages.flags),
custom: intl.formatMessage(messages.custom),
},
skins: {
choose: intl.formatMessage(messages.skins_choose),
1: intl.formatMessage(messages.skins_1),
2: intl.formatMessage(messages.skins_2),
3: intl.formatMessage(messages.skins_3),
4: intl.formatMessage(messages.skins_4),
5: intl.formatMessage(messages.skins_5),
6: intl.formatMessage(messages.skins_6),
},
};
};
useEffect(() => () => { useEffect(() => () => {
document.body.style.overflow = ''; document.body.style.overflow = '';
}, []); }, []);
@ -176,26 +126,6 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
} }
}, [expanded, update]); }, [expanded, update]);
useEffect(() => {
// fix scrolling focus issue
if (visible && expanded) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
if (!EmojiPicker) {
setLoading(true);
EmojiPickerAsync().then(EmojiMart => {
EmojiPicker = EmojiMart.Picker;
setLoading(false);
}).catch(() => {
setLoading(false);
});
}
}, [visible, expanded]);
return ( return (
<div <div
@ -207,17 +137,10 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({
{...attributes.popper} {...attributes.popper}
> >
{expanded ? ( {expanded ? (
!loading && <EmojiPicker <EmojiPickerDropdown
title={title} visible={expanded}
onEmojiSelect={(emoji: any) => onReact(emoji.native)} setVisible={setExpanded}
recent={frequentlyUsedEmojis} update={update}
perLine={8}
skin={onSkinTone}
emojiSize={22}
emojiButtonSize={34}
set='twitter'
theme={theme}
i18n={getI18n()}
/> />
) : ( ) : (
<HStack <HStack

@ -1,20 +1,17 @@
import { supportsPassiveEvents } from 'detect-passive-events';
import { Map as ImmutableMap } from 'immutable'; import { Map as ImmutableMap } from 'immutable';
import React, { useEffect, useState, useLayoutEffect } from 'react'; import React, { useEffect, useState, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { usePopper } from 'react-popper';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { useEmoji } from 'soapbox/actions/emojis'; import { useEmoji } from 'soapbox/actions/emojis';
import { changeSetting } from 'soapbox/actions/settings'; import { changeSetting } from 'soapbox/actions/settings';
import { useAppDispatch, useAppSelector, useSettings } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useSettings } from 'soapbox/hooks';
import { isMobile } from 'soapbox/is-mobile';
import { RootState } from 'soapbox/store'; import { RootState } from 'soapbox/store';
import { buildCustomEmojis } from '../../emoji'; import { buildCustomEmojis } from '../../emoji';
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components'; import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
import type { State as PopperState } from '@popperjs/core';
import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji'; import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji';
let EmojiPicker: any; // load asynchronously let EmojiPicker: any; // load asynchronously
@ -49,13 +46,9 @@ export const messages = defineMessages({
export interface IEmojiPickerDropdown { export interface IEmojiPickerDropdown {
onPickEmoji?: (emoji: Emoji) => void onPickEmoji?: (emoji: Emoji) => void
condensed?: boolean condensed?: boolean
render: React.FC<{ visible: boolean
setPopperReference: React.Ref<HTMLButtonElement> setVisible: (value: boolean) => void
title?: string update: (() => Promise<Partial<PopperState>>) | null
visible?: boolean
loading?: boolean
handleToggle: (e: Event) => void
}>
} }
const perLine = 8; const perLine = 8;
@ -132,9 +125,9 @@ const RenderAfter = ({ children, update }: any) => {
return nextTick ? children : null; return nextTick ? children : null;
}; };
const listenerOptions = supportsPassiveEvents ? { passive: true } : false; const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
onPickEmoji, condensed, visible, setVisible, update,
const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({ onPickEmoji, condensed, render: Render }) => { }) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const settings = useSettings(); const settings = useSettings();
@ -145,29 +138,8 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({ onPickEmoji, cond
const customEmojis = useAppSelector((state) => getCustomEmojis(state)); const customEmojis = useAppSelector((state) => getCustomEmojis(state));
const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state)); const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state));
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const [popperReference, setPopperReference] = useState<HTMLButtonElement | null>(null);
const [containerElement, setContainerElement] = useState<HTMLDivElement | null>(null);
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const placement = condensed ? 'bottom-start' : 'top-start';
const { styles, attributes, update } = usePopper(popperReference, popperElement, {
placement: isMobile(window.innerWidth) ? 'auto' : placement,
});
const handleToggle = (e: Event) => {
e.stopPropagation();
setVisible(!visible);
};
const handleDocClick = (e: any) => {
if (!containerElement?.contains(e.target) && !popperElement?.contains(e.target)) {
setVisible(false);
}
};
const handlePick = (emoji: any) => { const handlePick = (emoji: any) => {
setVisible(false); setVisible(false);
@ -233,17 +205,6 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({ onPickEmoji, cond
}; };
}; };
useEffect(() => {
document.addEventListener('click', handleDocClick, false);
document.addEventListener('touchend', handleDocClick, listenerOptions);
return function cleanup() {
document.removeEventListener('click', handleDocClick, false);
// @ts-ignore
document.removeEventListener('touchend', handleDocClick, listenerOptions);
};
});
useEffect(() => { useEffect(() => {
// fix scrolling focus issue // fix scrolling focus issue
if (visible) { if (visible) {
@ -265,29 +226,8 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({ onPickEmoji, cond
} }
}, [visible]); }, [visible]);
// TODO: move to class
const style: React.CSSProperties = !isMobile(window.innerWidth) ? styles.popper : {
...styles.popper, width: '100%',
};
return ( return (
<div className='relative' ref={setContainerElement}> visible ? (
<Render
handleToggle={handleToggle}
visible={visible}
loading={loading}
title={title}
setPopperReference={setPopperReference}
/>
{createPortal(
<div
className='z-[101]'
ref={setPopperElement}
style={style}
{...attributes.popper}
>
{visible && (
<RenderAfter update={update}> <RenderAfter update={update}>
{!loading && ( {!loading && (
<EmojiPicker <EmojiPicker
@ -305,11 +245,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({ onPickEmoji, cond
/> />
)} )}
</RenderAfter> </RenderAfter>
)} ) : null
</div>,
document.body,
)}
</div>
); );
}; };

@ -1,19 +1,70 @@
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import { supportsPassiveEvents } from 'detect-passive-events';
import React, { KeyboardEvent, useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { defineMessages, useIntl } from 'react-intl';
import { usePopper } from 'react-popper';
import { IconButton } from 'soapbox/components/ui'; import { IconButton } from 'soapbox/components/ui';
import { isMobile } from 'soapbox/is-mobile';
import EmojiPickerDropdown, { IEmojiPickerDropdown } from '../components/emoji-picker-dropdown'; import EmojiPickerDropdown, { IEmojiPickerDropdown } from '../components/emoji-picker-dropdown';
const EmojiPickerDropdownWrapper = (props: Omit<IEmojiPickerDropdown, 'render'>) => { const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
export const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
});
const EmojiPickerDropdownWrapper = (
props: Pick<IEmojiPickerDropdown, 'onPickEmoji' | 'condensed'>,
) => {
const intl = useIntl();
const title = intl.formatMessage(messages.emoji);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const [popperReference, setPopperReference] = useState<HTMLButtonElement | null>(null);
const [containerElement, setContainerElement] = useState<HTMLDivElement | null>(null);
const [visible, setVisible] = useState(false);
const placement = props.condensed ? 'bottom-start' : 'top-start';
const { styles, attributes, update } = usePopper(popperReference, popperElement, {
placement: isMobile(window.innerWidth) ? 'auto' : placement,
});
const handleDocClick = (e: any) => {
if (!containerElement?.contains(e.target) && !popperElement?.contains(e.target)) {
setVisible(false);
}
};
const handleToggle = (e: MouseEvent | KeyboardEvent) => {
e.stopPropagation();
setVisible(!visible);
};
// TODO: move to class
const style: React.CSSProperties = !isMobile(window.innerWidth) ? styles.popper : {
...styles.popper, width: '100%',
};
useEffect(() => {
document.addEventListener('click', handleDocClick, false);
document.addEventListener('touchend', handleDocClick, listenerOptions);
return function cleanup() {
document.removeEventListener('click', handleDocClick, false);
// @ts-ignore
document.removeEventListener('touchend', handleDocClick, listenerOptions);
};
});
return ( return (
<EmojiPickerDropdown <div className='relative' ref={setContainerElement}>
render={
({ setPopperReference, title, visible, loading, handleToggle }: any) => (
<IconButton <IconButton
className={clsx({ className={clsx({
'text-gray-400 hover:text-gray-600': true, 'text-gray-400 hover:text-gray-600': true,
'pulse-loading': visible && loading,
})} })}
ref={setPopperReference} ref={setPopperReference}
src={require('@tabler/icons/mood-happy.svg')} src={require('@tabler/icons/mood-happy.svg')}
@ -21,15 +72,23 @@ const EmojiPickerDropdownWrapper = (props: Omit<IEmojiPickerDropdown, 'render'>)
aria-label={title} aria-label={title}
aria-expanded={visible} aria-expanded={visible}
role='button' role='button'
onClick={handleToggle} onClick={handleToggle as any}
onKeyDown={handleToggle} onKeyDown={handleToggle as React.KeyboardEventHandler<HTMLButtonElement>}
tabIndex={0} tabIndex={0}
/> />
)
}
{...props} {createPortal(
/> <div
className='z-[101]'
ref={setPopperElement}
style={style}
{...attributes.popper}
>
<EmojiPickerDropdown visible={visible} setVisible={setVisible} update={update} {...props} />
</div>,
document.body,
)}
</div>
); );
}; };

@ -620,6 +620,7 @@
"email_verifilcation.exists": "This email has already been taken.", "email_verifilcation.exists": "This email has already been taken.",
"embed.instructions": "Embed this post on your website by copying the code below.", "embed.instructions": "Embed this post on your website by copying the code below.",
"emoji_button.activity": "Activity", "emoji_button.activity": "Activity",
"emoji_button.add_custom": "Add custom emoji",
"emoji_button.custom": "Custom", "emoji_button.custom": "Custom",
"emoji_button.flags": "Flags", "emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink", "emoji_button.food": "Food & Drink",
@ -627,7 +628,16 @@
"emoji_button.nature": "Nature", "emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojis found.", "emoji_button.not_found": "No emojis found.",
"emoji_button.objects": "Objects", "emoji_button.objects": "Objects",
"emoji_button.oh_no": "Oh no!",
"emoji_button.people": "People", "emoji_button.people": "People",
"emoji_button.pick": "Pick an emoji…",
"emoji_button.skins_1": "Default",
"emoji_button.skins_2": "Light",
"emoji_button.skins_3": "Medium-Light",
"emoji_button.skins_4": "Medium",
"emoji_button.skins_5": "Medium-Dark",
"emoji_button.skins_6": "Dark",
"emoji_button.skins_choose": "Choose default skin tone",
"emoji_button.recent": "Frequently used", "emoji_button.recent": "Frequently used",
"emoji_button.search": "Search…", "emoji_button.search": "Search…",
"emoji_button.search_results": "Search results", "emoji_button.search_results": "Search results",

Loading…
Cancel
Save