Switch from EmojiOne to Twemoji, different emoji picker (#5046)

* Switch from EmojiOne to Twemoji, different emoji picker

* Make emoji-mart use a local spritesheet

* Fix emojify test

* yarn manage:translations
This commit is contained in:
Eugen Rochko 2017-09-23 01:41:00 +02:00 committed by GitHub
parent 0de82dd316
commit 846cd4e838
4595 changed files with 3324 additions and 2196 deletions

View file

@ -3,6 +3,8 @@ import Trie from 'substring-trie';
const trie = new Trie(Object.keys(unicodeMapping));
const assetHost = process.env.CDN_HOST || '';
const emojify = (str, customEmojis = {}) => {
let rtn = '';
for (;;) {
@ -37,7 +39,7 @@ const emojify = (str, customEmojis = {}) => {
str = str.slice(i + 1);
} else {
const [filename, shortCode] = unicodeMapping[match];
rtn += str.slice(0, i) + `<img draggable="false" class="emojione" alt="${match}" title=":${shortCode}:" src="/emoji/${filename}.svg" />`;
rtn += str.slice(0, i) + `<img draggable="false" class="emojione" alt="${match}" title=":${shortCode}:" src="${assetHost}/emoji/${filename}.svg" />`;
str = str.slice(i + match.length);
}
}

View file

@ -9,5 +9,5 @@ const excluded = ['®', '©', '™'];
module.exports.unicodeMapping = Object.keys(emojione.jsEscapeMap)
.filter(c => !excluded.includes(c))
.map(unicodeStr => [unicodeStr, mappedUnicode[emojione.jsEscapeMap[unicodeStr]]])
.map(([unicodeStr, shortCode]) => ({ [unicodeStr]: [emojione.emojioneList[shortCode].fname, shortCode.slice(1, shortCode.length - 1)] }))
.map(([unicodeStr, shortCode]) => ({ [unicodeStr]: [emojione.emojioneList[shortCode].fname.replace(/^0+/g, ''), shortCode.slice(1, shortCode.length - 1)] }))
.reduce((x, y) => Object.assign(x, y), { });

View file

@ -138,7 +138,7 @@ export default class ComposeForm extends ImmutablePureComponent {
handleEmojiPick = (data) => {
const position = this.autosuggestTextarea.textarea.selectionStart;
const emojiChar = data.unicode.split('-').map(code => String.fromCodePoint(parseInt(code, 16))).join('');
const emojiChar = data.native;
this._restoreCaret = position + emojiChar.length + 1;
this.props.onPickEmoji(position, data);
}

View file

@ -1,12 +1,17 @@
import React from 'react';
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
import { Overlay } from 'react-overlays';
import classNames from 'classnames';
const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },
emoji_not_found: { id: 'emoji_button.not_found', defaultMessage: 'No emojos!! (╯°□°)╯︵ ┻━┻' },
custom: { id: 'emoji_button.custom', defaultMessage: 'Custom' },
recent: { id: 'emoji_button.recent', defaultMessage: 'Frequently used' },
search_results: { id: 'emoji_button.search_results', defaultMessage: 'Search results' },
people: { id: 'emoji_button.people', defaultMessage: 'People' },
nature: { id: 'emoji_button.nature', defaultMessage: 'Nature' },
food: { id: 'emoji_button.food', defaultMessage: 'Food & Drink' },
@ -17,13 +22,234 @@ const messages = defineMessages({
flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },
});
const settings = {
imageType: 'png',
sprites: false,
imagePathPNG: '/emoji/',
};
const assetHost = process.env.CDN_HOST || '';
let EmojiPicker; // load asynchronously
let EmojiPicker, Emoji; // load asynchronously
const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`;
class ModifierPickerMenu extends React.PureComponent {
static propTypes = {
active: PropTypes.bool,
onSelect: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
};
handleClick = (e) => {
const modifier = [].slice.call(e.currentTarget.parentNode.children).indexOf(e.target) + 1;
this.props.onSelect(modifier);
}
componentWillReceiveProps (nextProps) {
if (nextProps.active) {
this.attachListeners();
} else {
this.removeListeners();
}
}
componentWillUnmount () {
this.removeListeners();
}
handleDocumentClick = e => {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
}
}
attachListeners () {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, false);
}
removeListeners () {
document.removeEventListener('click', this.handleDocumentClick, false);
document.removeEventListener('touchend', this.handleDocumentClick, false);
}
setRef = c => {
this.node = c;
}
render () {
const { active } = this.props;
return (
<div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button>
<button onClick={this.handleClick}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button>
</div>
);
}
}
class ModifierPicker extends React.PureComponent {
static propTypes = {
active: PropTypes.bool,
modifier: PropTypes.number,
onChange: PropTypes.func,
onClose: PropTypes.func,
onOpen: PropTypes.func,
};
handleClick = () => {
if (this.props.active) {
this.props.onClose();
} else {
this.props.onOpen();
}
}
handleSelect = modifier => {
this.props.onChange(modifier);
this.props.onClose();
}
render () {
const { active, modifier } = this.props;
return (
<div className='emoji-picker-dropdown__modifiers'>
<Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={modifier} onClick={this.handleClick} backgroundImageFn={backgroundImageFn} />
<ModifierPickerMenu active={active} onSelect={this.handleSelect} onClose={this.props.onClose} />
</div>
);
}
}
@injectIntl
class EmojiPickerMenu extends React.PureComponent {
static propTypes = {
loading: PropTypes.bool,
onClose: PropTypes.func.isRequired,
onPick: PropTypes.func.isRequired,
style: PropTypes.object,
placement: PropTypes.string,
arrowOffsetLeft: PropTypes.string,
arrowOffsetTop: PropTypes.string,
intl: PropTypes.object.isRequired,
};
static defaultProps = {
style: {},
loading: true,
placement: 'bottom',
};
state = {
modifierOpen: false,
modifier: 1,
};
handleDocumentClick = e => {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
}
}
componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, false);
}
componentWillUnmount () {
document.removeEventListener('click', this.handleDocumentClick, false);
document.removeEventListener('touchend', this.handleDocumentClick, false);
}
setRef = c => {
this.node = c;
}
getI18n = () => {
const { intl } = this.props;
return {
search: intl.formatMessage(messages.emoji_search),
notfound: intl.formatMessage(messages.emoji_not_found),
categories: {
search: intl.formatMessage(messages.search_results),
recent: 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),
},
};
}
handleClick = emoji => {
this.props.onClose();
this.props.onPick(emoji);
}
handleModifierOpen = () => {
this.setState({ modifierOpen: true });
}
handleModifierClose = () => {
this.setState({ modifierOpen: false });
}
handleModifierChange = modifier => {
if (modifier !== this.state.modifier) {
this.setState({ modifier });
}
}
render () {
const { loading, style, intl } = this.props;
if (loading) {
return <div style={{ width: 299 }} />;
}
const title = intl.formatMessage(messages.emoji);
const { modifierOpen, modifier } = this.state;
return (
<div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>
<EmojiPicker
perLine={8}
emojiSize={22}
sheetSize={32}
color=''
emoji=''
set='twitter'
title={title}
i18n={this.getI18n()}
onClick={this.handleClick}
skin={modifier}
backgroundImageFn={backgroundImageFn}
/>
<ModifierPicker
active={modifierOpen}
modifier={modifier}
onOpen={this.handleModifierOpen}
onClose={this.handleModifierClose}
onChange={this.handleModifierChange}
/>
</div>
);
}
}
@injectIntl
export default class EmojiPickerDropdown extends React.PureComponent {
@ -42,20 +268,17 @@ export default class EmojiPickerDropdown extends React.PureComponent {
this.dropdown = c;
}
handleChange = (data) => {
this.dropdown.hide();
this.props.onPickEmoji(data);
}
onShowDropdown = () => {
this.setState({ active: true });
if (!EmojiPicker) {
this.setState({ loading: true });
EmojiPickerAsync().then(TheEmojiPicker => {
EmojiPicker = TheEmojiPicker.default;
EmojiPickerAsync().then(EmojiMart => {
EmojiPicker = EmojiMart.Picker;
Emoji = EmojiMart.Emoji;
this.setState({ loading: false });
}).catch(() => {
// TODO: show the user an error?
this.setState({ loading: false });
});
}
@ -75,70 +298,39 @@ export default class EmojiPickerDropdown extends React.PureComponent {
}
}
onEmojiPickerKeyDown = (e) => {
handleKeyDown = e => {
if (e.key === 'Escape') {
this.onHideDropdown();
}
}
setTargetRef = c => {
this.target = c;
}
findTarget = () => {
return this.target;
}
render () {
const { intl } = this.props;
const categories = {
people: {
title: intl.formatMessage(messages.people),
emoji: 'smile',
},
nature: {
title: intl.formatMessage(messages.nature),
emoji: 'hamster',
},
food: {
title: intl.formatMessage(messages.food),
emoji: 'pizza',
},
activity: {
title: intl.formatMessage(messages.activity),
emoji: 'soccer',
},
travel: {
title: intl.formatMessage(messages.travel),
emoji: 'earth_americas',
},
objects: {
title: intl.formatMessage(messages.objects),
emoji: 'bulb',
},
symbols: {
title: intl.formatMessage(messages.symbols),
emoji: 'clock9',
},
flags: {
title: intl.formatMessage(messages.flags),
emoji: 'flag_gb',
},
};
const { active, loading } = this.state;
const { intl, onPickEmoji } = this.props;
const title = intl.formatMessage(messages.emoji);
const { active, loading } = this.state;
return (
<Dropdown ref={this.setRef} className='emoji-picker__dropdown' active={active && !loading} onShow={this.onShowDropdown} onHide={this.onHideDropdown}>
<DropdownTrigger className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onKeyDown={this.onToggle} tabIndex={0} >
<div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
<img
className={`emojione ${active && loading ? 'pulse-loading' : ''}`}
className={classNames('emojione', { 'pulse-loading': active && loading })}
alt='🙂'
src='/emoji/1f602.svg'
src={`${assetHost}/emoji/1f602.svg`}
/>
</DropdownTrigger>
</div>
<DropdownContent className='dropdown__left'>
{
this.state.active && !this.state.loading &&
(<EmojiPicker emojione={settings} onChange={this.handleChange} searchPlaceholder={intl.formatMessage(messages.emoji_search)} onKeyDown={this.onEmojiPickerKeyDown} categories={categories} search />)
}
</DropdownContent>
</Dropdown>
<Overlay show={active} placement='bottom' target={this.findTarget}>
<EmojiPickerMenu loading={loading} onClose={this.onHideDropdown} onPick={onPickEmoji} />
</Overlay>
</div>
);
}

View file

@ -1,5 +1,5 @@
export function EmojiPicker () {
return import(/* webpackChunkName: "emojione_picker" */'emojione-picker');
return import(/* webpackChunkName: "emoji_picker" */'emoji-mart');
}
export function Compose () {

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "الأنشطة",
"emoji_button.custom": "Custom",
"emoji_button.flags": "الأعلام",
"emoji_button.food": "الطعام والشراب",
"emoji_button.label": "أدرج إيموجي",
"emoji_button.nature": "الطبيعة",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "أشياء",
"emoji_button.people": "الناس",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "ابحث...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "رموز",
"emoji_button.travel": "أماكن و أسفار",
"empty_column.community": "الخط الزمني المحلي فارغ. اكتب شيئا ما للعامة كبداية.",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activitat",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Menjar i Beure",
"emoji_button.label": "Inserir emoji",
"emoji_button.nature": "Natura",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objectes",
"emoji_button.people": "Gent",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Cercar...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Símbols",
"emoji_button.travel": "Viatges i Llocs",
"empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Du kannst diesen Beitrag auf deiner Webseite einbetten, in dem du den folgenden Code einfügst.",
"embed.preview": "So wird es aussehen:",
"emoji_button.activity": "Aktivitäten",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flaggen",
"emoji_button.food": "Essen und Trinken",
"emoji_button.label": "Emoji einfügen",
"emoji_button.nature": "Natur",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Dinge",
"emoji_button.people": "Leute",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Suche…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbole",
"emoji_button.travel": "Reise und Orte",
"empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe etwas öffentlich, um den Ball ins Rollen zu bringen!",

View file

@ -516,6 +516,22 @@
"defaultMessage": "Search...",
"id": "emoji_button.search"
},
{
"defaultMessage": "No emojos!! (╯°□°)╯︵ ┻━┻",
"id": "emoji_button.not_found"
},
{
"defaultMessage": "Custom",
"id": "emoji_button.custom"
},
{
"defaultMessage": "Frequently used",
"id": "emoji_button.recent"
},
{
"defaultMessage": "Search results",
"id": "emoji_button.search_results"
},
{
"defaultMessage": "People",
"id": "emoji_button.people"
@ -1331,15 +1347,6 @@
],
"path": "app/javascript/mastodon/features/ui/components/upload_area.json"
},
{
"descriptors": [
{
"defaultMessage": "Close",
"id": "lightbox.close"
}
],
"path": "app/javascript/mastodon/features/ui/components/video_modal.json"
},
{
"descriptors": [
{

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Añade este toot a tu sitio web con el siguiente código.",
"embed.preview": "Así es como se verá:",
"emoji_button.activity": "Actividad",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Marcas",
"emoji_button.food": "Comida y bebida",
"emoji_button.label": "Insertar emoji",
"emoji_button.nature": "Naturaleza",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objetos",
"emoji_button.people": "Gente",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Buscar…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Símbolos",
"emoji_button.travel": "Viajes y lugares",
"empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.",
"embed.preview": "نوشتهٔ جاگذاری‌شده این گونه به نظر خواهد رسید:",
"emoji_button.activity": "فعالیت",
"emoji_button.custom": "Custom",
"emoji_button.flags": "پرچم‌ها",
"emoji_button.food": "غذا و نوشیدنی",
"emoji_button.label": "افزودن شکلک",
"emoji_button.nature": "طبیعت",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "اشیا",
"emoji_button.people": "مردم",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "جستجو...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "نمادها",
"emoji_button.travel": "سفر و مکان",
"empty_column.community": "فهرست نوشته‌های محلی خالی است. چیزی بنویسید تا چرخش بچرخد!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Intégrez ce statut à votre site en copiant ce code ci-dessous.",
"embed.preview": "Il apparaîtra comme cela:",
"emoji_button.activity": "Activités",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Drapeaux",
"emoji_button.food": "Boire et manger",
"emoji_button.label": "Insérer un emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objets",
"emoji_button.people": "Personnages",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Recherche…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symboles",
"emoji_button.travel": "Lieux et voyages",
"empty_column.community": "Le fil public local est vide. Écrivez-donc quelque chose pour le remplir!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "פעילות",
"emoji_button.custom": "Custom",
"emoji_button.flags": "דגלים",
"emoji_button.food": "אוכל ושתיה",
"emoji_button.label": "הוספת אמוג'י",
"emoji_button.nature": "טבע",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "חפצים",
"emoji_button.people": "אנשים",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "חיפוש...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "סמלים",
"emoji_button.travel": "טיולים ואתרים",
"empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Aktivnost",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Zastave",
"emoji_button.food": "Hrana & Piće",
"emoji_button.label": "Umetni smajlije",
"emoji_button.nature": "Priroda",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objekti",
"emoji_button.people": "Ljudi",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Traži...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Simboli",
"emoji_button.travel": "Putovanja & Mjesta",
"empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Aktivitas",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Bendera",
"emoji_button.food": "Makanan & Minuman",
"emoji_button.label": "Tambahkan emoji",
"emoji_button.nature": "Alam",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Benda-benda",
"emoji_button.people": "Orang",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Cari...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Simbol",
"emoji_button.travel": "Tempat Wisata",
"empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insertar emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "La lokala tempolineo esas vakua. Skribez ulo publike por iniciar la agiveso!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Inserisci emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "下記のコードをコピーしてウェブサイトに埋め込みます。",
"embed.preview": "表示例:",
"emoji_button.activity": "活動",
"emoji_button.custom": "Custom",
"emoji_button.flags": "国旗",
"emoji_button.food": "食べ物",
"emoji_button.label": "絵文字を追加",
"emoji_button.nature": "自然",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物",
"emoji_button.people": "人々",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "検索...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "記号",
"emoji_button.travel": "旅行と場所",
"empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "활동",
"emoji_button.custom": "Custom",
"emoji_button.flags": "국기",
"emoji_button.food": "음식",
"emoji_button.label": "emoji를 추가",
"emoji_button.nature": "자연",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "물건",
"emoji_button.people": "사람들",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "검색...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "기호",
"emoji_button.travel": "여행과 장소",
"empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!",

View file

@ -33,9 +33,8 @@
"column.home": "Start",
"column.mutes": "Genegeerde gebruikers",
"column.notifications": "Meldingen",
"column.pins": "Pinned toot",
"column.public": "Globale tijdlijn",
"column.pins": "Vastgezette toots",
"column.public": "Globale tijdlijn",
"column_back_button.label": "terug",
"column_header.hide_settings": "Instellingen verbergen",
"column_header.moveLeft_settings": "Kolom naar links verplaatsen",
@ -68,13 +67,17 @@
"embed.instructions": "Embed deze toot op jouw website, door de onderstaande code te kopiëren.",
"embed.preview": "Zo komt het eruit te zien:",
"emoji_button.activity": "Activiteiten",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Vlaggen",
"emoji_button.food": "Eten en drinken",
"emoji_button.label": "Emoji toevoegen",
"emoji_button.nature": "Natuur",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Voorwerpen",
"emoji_button.people": "Mensen",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Zoeken...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbolen",
"emoji_button.travel": "Reizen en plekken",
"empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!",
@ -87,7 +90,6 @@
"follow_request.authorize": "Goedkeuren",
"follow_request.reject": "Afkeuren",
"getting_started.appsshort": "Apps",
"getting_started.donate": "Doneren",
"getting_started.faq": "FAQ",
"getting_started.heading": "Beginnen",
"getting_started.open_source_notice": "Mastodon is open-sourcesoftware. Je kunt bijdragen of problemen melden op GitHub via {github}.",
@ -112,10 +114,9 @@
"navigation_bar.info": "Uitgebreide informatie",
"navigation_bar.logout": "Afmelden",
"navigation_bar.mutes": "Genegeerde gebruikers",
"navigation_bar.pins": "Pinned toots",
"navigation_bar.pins": "Vastgezette toots",
"navigation_bar.preferences": "Instellingen",
"navigation_bar.public_timeline": "Globale tijdlijn",
"navigation_bar.pins": "Vastgezette toots",
"notification.favourite": "{name} markeerde jouw toot als favoriet",
"notification.follow": "{name} volgt jou nu",
"notification.mention": "{name} vermeldde jou",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Aktivitet",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flagg",
"emoji_button.food": "Mat og drikke",
"emoji_button.label": "Sett inn emoji",
"emoji_button.nature": "Natur",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objekter",
"emoji_button.people": "Mennesker",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Søk...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symboler",
"emoji_button.travel": "Reise & steder",
"empty_column.community": "Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embarcar aqueste estatut per lo far veire sus un site Internet en copiar lo còdi çai-jos.",
"embed.preview": "Semblarà aquò:",
"emoji_button.activity": "Activitats",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Drapèus",
"emoji_button.food": "Beure e manjar",
"emoji_button.label": "Inserir un emoji",
"emoji_button.nature": "Natura",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objèctes",
"emoji_button.people": "Gents",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Cercar…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Simbòls",
"emoji_button.travel": "Viatges & lòcs",
"empty_column.community": "Lo flux public local es void. Escrivètz quicòm per lo garnir!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Osadź ten status na swojej stronie wklejając poniższy kod.",
"embed.preview": "Tak będzie to wyglądać:",
"emoji_button.activity": "Aktywność",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flagi",
"emoji_button.food": "Żywność i napoje",
"emoji_button.label": "Wstaw emoji",
"emoji_button.nature": "Natura",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objekty",
"emoji_button.people": "Ludzie",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Szukaj…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbole",
"emoji_button.travel": "Podróże i miejsca",
"empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!",

View file

@ -35,7 +35,6 @@
"column.notifications": "Notificações",
"column.pins": "Postagens fixadas",
"column.public": "Global",
"column.pins": "Postagens fixadas",
"column_back_button.label": "Voltar",
"column_header.hide_settings": "Esconder configurações",
"column_header.moveLeft_settings": "Mover coluna para a esquerda",
@ -68,13 +67,17 @@
"embed.instructions": "Incorpore esta postagem em seu site copiando o código abaixo:",
"embed.preview": "Aqui está uma previsão de como ficará:",
"emoji_button.activity": "Atividades",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Bandeiras",
"emoji_button.food": "Comidas & Bebidas",
"emoji_button.label": "Inserir Emoji",
"emoji_button.nature": "Natureza",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objetos",
"emoji_button.people": "Pessoas",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Buscar...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Símbolos",
"emoji_button.travel": "Viagens & Lugares",
"empty_column.community": "A timeline local está vazia. Escreva algo publicamente para começar!",
@ -114,9 +117,6 @@
"navigation_bar.pins": "Postagens fixadas",
"navigation_bar.preferences": "Preferências",
"navigation_bar.public_timeline": "Global",
"navigation_bar.preferences": "Preferências",
"navigation_bar.public_timeline": "Global",
"navigation_bar.pins": "Postagens fixadas",
"notification.favourite": "{name} adicionou a sua postagem aos favoritos",
"notification.follow": "{name} te seguiu",
"notification.mention": "{name} te mencionou",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Inserir Emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "Ainda não existem conteúdo local para mostrar!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Занятия",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Флаги",
"emoji_button.food": "Еда и напитки",
"emoji_button.label": "Вставить эмодзи",
"emoji_button.nature": "Природа",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Предметы",
"emoji_button.people": "Люди",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Найти...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Символы",
"emoji_button.travel": "Путешествия",
"empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Activity",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Flags",
"emoji_button.food": "Food & Drink",
"emoji_button.label": "Insert emoji",
"emoji_button.nature": "Nature",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects",
"emoji_button.people": "People",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Search...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Aktivite",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Bayraklar",
"emoji_button.food": "Yiyecek ve İçecek",
"emoji_button.label": "Emoji ekle",
"emoji_button.nature": "Doğa",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Nesneler",
"emoji_button.people": "İnsanlar",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Emoji ara...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Semboller",
"emoji_button.travel": "Seyahat ve Yerler",
"empty_column.community": "Yerel zaman tüneliniz boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın.",

View file

@ -67,13 +67,17 @@
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"emoji_button.activity": "Заняття",
"emoji_button.custom": "Custom",
"emoji_button.flags": "Прапори",
"emoji_button.food": "Їжа та напої",
"emoji_button.label": "Вставити емодзі",
"emoji_button.nature": "Природа",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Предмети",
"emoji_button.people": "Люди",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "Знайти...",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Символи",
"emoji_button.travel": "Подорожі",
"empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "要内嵌此嘟文,请将以下代码贴进你的网站。",
"embed.preview": "到时大概长这样:",
"emoji_button.activity": "活动",
"emoji_button.custom": "Custom",
"emoji_button.flags": "旗帜",
"emoji_button.food": "食物和饮料",
"emoji_button.label": "加入表情符号",
"emoji_button.nature": "自然",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物体",
"emoji_button.people": "人物",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "搜索…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "符号",
"emoji_button.travel": "旅途和地点",
"empty_column.community": "本站时间轴暂时未有内容,快嘟几个来抢头香啊!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。",
"embed.preview": "看上去會是這樣:",
"emoji_button.activity": "活動",
"emoji_button.custom": "Custom",
"emoji_button.flags": "旗幟",
"emoji_button.food": "飲飲食食",
"emoji_button.label": "加入表情符號",
"emoji_button.nature": "自然",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物品",
"emoji_button.people": "人物",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "搜尋…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "符號",
"emoji_button.travel": "旅遊景物",
"empty_column.community": "本站時間軸暫時未有內容,快文章來搶頭香啊!",

View file

@ -67,13 +67,17 @@
"embed.instructions": "要內嵌此貼文,請將以下代碼貼進你的網站。",
"embed.preview": "看上去會變成這樣:",
"emoji_button.activity": "活動",
"emoji_button.custom": "Custom",
"emoji_button.flags": "旗幟",
"emoji_button.food": "食物與飲料",
"emoji_button.label": "插入表情符號",
"emoji_button.nature": "自然",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物件",
"emoji_button.people": "人",
"emoji_button.recent": "Frequently used",
"emoji_button.search": "搜尋…",
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "符號",
"emoji_button.travel": "旅遊與地點",
"empty_column.community": "本地時間軸是空的。公開寫點什麼吧!",

View file

@ -120,7 +120,7 @@ const insertSuggestion = (state, position, token, completion) => {
};
const insertEmoji = (state, position, emojiData) => {
const emoji = emojiData.unicode.split('-').map(code => String.fromCodePoint(parseInt(code, 16))).join('');
const emoji = emojiData.native;
return state.withMutations(map => {
map.update('text', oldText => `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`);

View file

@ -15,6 +15,7 @@
@import 'accounts';
@import 'stream_entries';
@import 'components';
@import 'emoji_picker';
@import 'about';
@import 'tables';
@import 'admin';

View file

@ -390,17 +390,11 @@
.compose-form__autosuggest-wrapper {
position: relative;
.emoji-picker__dropdown {
.emoji-picker-dropdown {
position: absolute;
right: 5px;