Refresh the emoji library (#7001)
* refresh the emoji library * fix img_trans.gif * compress sprite sheet * remove note on compression - webpack seems to handle compression decently * better emoji sheet preloading * requested changes
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: build test run clean stop check-style run-unit
|
.PHONY: build test run clean stop check-style run-unit emojis
|
||||||
|
|
||||||
BUILD_SERVER_DIR = ..
|
BUILD_SERVER_DIR = ..
|
||||||
|
|
||||||
@@ -54,3 +54,6 @@ clean:
|
|||||||
rm -rf dist
|
rm -rf dist
|
||||||
rm -rf node_modules
|
rm -rf node_modules
|
||||||
rm -f .yarninstall
|
rm -f .yarninstall
|
||||||
|
|
||||||
|
emojis:
|
||||||
|
./make-emojis
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import MsgTyping from './msg_typing.jsx';
|
|||||||
import FileUpload from './file_upload.jsx';
|
import FileUpload from './file_upload.jsx';
|
||||||
import FilePreview from './file_preview.jsx';
|
import FilePreview from './file_preview.jsx';
|
||||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||||
|
import * as EmojiPicker from 'components/emoji_picker/emoji_picker.jsx';
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import * as UserAgent from 'utils/user_agent.jsx';
|
import * as UserAgent from 'utils/user_agent.jsx';
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
@@ -588,6 +589,7 @@ export default class CreateComment extends React.Component {
|
|||||||
<span
|
<span
|
||||||
className={'fa fa-smile-o icon--emoji-picker emoji-rhs'}
|
className={'fa fa-smile-o icon--emoji-picker emoji-rhs'}
|
||||||
onClick={this.toggleEmojiPicker}
|
onClick={this.toggleEmojiPicker}
|
||||||
|
onMouseOver={EmojiPicker.beginPreloading}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import FilePreview from './file_preview.jsx';
|
|||||||
import PostDeletedModal from './post_deleted_modal.jsx';
|
import PostDeletedModal from './post_deleted_modal.jsx';
|
||||||
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
||||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||||
|
import * as EmojiPicker from 'components/emoji_picker/emoji_picker.jsx';
|
||||||
|
|
||||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
@@ -746,6 +747,7 @@ export default class CreatePost extends React.Component {
|
|||||||
<span
|
<span
|
||||||
className={'fa fa-smile-o icon--emoji-picker emoji-main'}
|
className={'fa fa-smile-o icon--emoji-picker emoji-main'}
|
||||||
onClick={this.toggleEmojiPicker}
|
onClick={this.toggleEmojiPicker}
|
||||||
|
onMouseOver={EmojiPicker.beginPreloading}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ export default class EmojiPickerItem extends React.Component {
|
|||||||
onItemOut: PropTypes.func.isRequired,
|
onItemOut: PropTypes.func.isRequired,
|
||||||
onItemClick: PropTypes.func.isRequired,
|
onItemClick: PropTypes.func.isRequired,
|
||||||
onItemUnmount: PropTypes.func.isRequired,
|
onItemUnmount: PropTypes.func.isRequired,
|
||||||
category: PropTypes.string.isRequired
|
category: PropTypes.string.isRequired,
|
||||||
|
isLoaded: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -61,8 +62,8 @@ export default class EmojiPickerItem extends React.Component {
|
|||||||
item =
|
item =
|
||||||
(<div >
|
(<div >
|
||||||
<img
|
<img
|
||||||
src='/static/emoji/img_trans.gif'
|
src='/static/images/img_trans.gif'
|
||||||
className={' emojisprite emoji-' + this.props.emoji.filename + ' '}
|
className={' emojisprite' + (this.props.isLoaded ? '' : '-loading') + ' emoji-' + this.props.emoji.filename + ' '}
|
||||||
onMouseOver={this.handleMouseOver}
|
onMouseOver={this.handleMouseOver}
|
||||||
onMouseOut={this.handleMouseOut}
|
onMouseOut={this.handleMouseOut}
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default class EmojiPickerPreview extends React.Component {
|
|||||||
name = emoji.aliases[0];
|
name = emoji.aliases[0];
|
||||||
aliases = emoji.aliases;
|
aliases = emoji.aliases;
|
||||||
previewImage = (<span className='sprite-preview'><img
|
previewImage = (<span className='sprite-preview'><img
|
||||||
src='/static/emoji/img_trans.gif'
|
src='/static/images/img_trans.gif'
|
||||||
className={' emojisprite-preview emoji-' + emoji.filename + ' '}
|
className={' emojisprite-preview emoji-' + emoji.filename + ' '}
|
||||||
/></span>);
|
/></span>);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -14,14 +14,23 @@ import EmojiPickerCategory from './components/emoji_picker_category.jsx';
|
|||||||
import EmojiPickerItem from './components/emoji_picker_item.jsx';
|
import EmojiPickerItem from './components/emoji_picker_item.jsx';
|
||||||
import EmojiPickerPreview from './components/emoji_picker_preview.jsx';
|
import EmojiPickerPreview from './components/emoji_picker_preview.jsx';
|
||||||
|
|
||||||
|
import PeopleSpriteSheet from 'images/emoji-sheets/people.png';
|
||||||
|
import NatureSpriteSheet from 'images/emoji-sheets/nature.png';
|
||||||
|
import FoodsSpriteSheet from 'images/emoji-sheets/foods.png';
|
||||||
|
import ActivitySpriteSheet from 'images/emoji-sheets/activity.png';
|
||||||
|
import PlacesSpriteSheet from 'images/emoji-sheets/places.png';
|
||||||
|
import ObjectsSpriteSheet from 'images/emoji-sheets/objects.png';
|
||||||
|
import SymbolsSpriteSheet from 'images/emoji-sheets/symbols.png';
|
||||||
|
import FlagsSpriteSheet from 'images/emoji-sheets/flags.png';
|
||||||
|
|
||||||
// This should include all the categories available in Emoji.CategoryNames
|
// This should include all the categories available in Emoji.CategoryNames
|
||||||
const CATEGORIES = [
|
const CATEGORIES = [
|
||||||
'recent',
|
'recent',
|
||||||
'people',
|
'people',
|
||||||
'nature',
|
'nature',
|
||||||
'food',
|
'foods',
|
||||||
'activity',
|
'activity',
|
||||||
'travel',
|
'places',
|
||||||
'objects',
|
'objects',
|
||||||
'symbols',
|
'symbols',
|
||||||
'flags',
|
'flags',
|
||||||
@@ -49,6 +58,7 @@ export default class EmojiPicker extends React.Component {
|
|||||||
// All props are primitives or treated as immutable
|
// All props are primitives or treated as immutable
|
||||||
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
|
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
|
||||||
|
|
||||||
|
this.handlePreload = this.handlePreload.bind(this);
|
||||||
this.handleCategoryClick = this.handleCategoryClick.bind(this);
|
this.handleCategoryClick = this.handleCategoryClick.bind(this);
|
||||||
this.handleFilterChange = this.handleFilterChange.bind(this);
|
this.handleFilterChange = this.handleFilterChange.bind(this);
|
||||||
this.handleItemOver = this.handleItemOver.bind(this);
|
this.handleItemOver = this.handleItemOver.bind(this);
|
||||||
@@ -61,7 +71,8 @@ export default class EmojiPicker extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
category: 'recent',
|
category: 'recent',
|
||||||
filter: '',
|
filter: '',
|
||||||
selected: null
|
selected: null,
|
||||||
|
preloaded: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +82,23 @@ export default class EmojiPicker extends React.Component {
|
|||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.searchInput.focus();
|
this.searchInput.focus();
|
||||||
});
|
});
|
||||||
|
beginPreloading();
|
||||||
|
subscribeToPreloads(this.handlePreload);
|
||||||
|
this.handlePreload();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
unsubscribeFromPreloads(this.handlePreload);
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePreload() {
|
||||||
|
const preloaded = [];
|
||||||
|
for (const category of CATEGORIES) {
|
||||||
|
if (didPreloadCategory(category)) {
|
||||||
|
preloaded.push(category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({preloaded});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCategoryClick(category) {
|
handleCategoryClick(category) {
|
||||||
@@ -139,7 +167,8 @@ export default class EmojiPicker extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderCategory(category, filter) {
|
|
||||||
|
renderCategory(category, isLoaded, filter) {
|
||||||
const items = [];
|
const items = [];
|
||||||
let indices = [];
|
let indices = [];
|
||||||
let recentEmojis = [];
|
let recentEmojis = [];
|
||||||
@@ -181,6 +210,7 @@ export default class EmojiPicker extends React.Component {
|
|||||||
key={'system_' + (category === 'recent' ? 'recent_' : '') + (emoji.name || emoji.aliases[0])}
|
key={'system_' + (category === 'recent' ? 'recent_' : '') + (emoji.name || emoji.aliases[0])}
|
||||||
emoji={emoji}
|
emoji={emoji}
|
||||||
category={category}
|
category={category}
|
||||||
|
isLoaded={isLoaded}
|
||||||
onItemOver={this.handleItemOver}
|
onItemOver={this.handleItemOver}
|
||||||
onItemOut={this.handleItemOut}
|
onItemOut={this.handleItemOut}
|
||||||
onItemClick={this.handleItemClick}
|
onItemClick={this.handleItemClick}
|
||||||
@@ -261,7 +291,7 @@ export default class EmojiPicker extends React.Component {
|
|||||||
previewImage = (
|
previewImage = (
|
||||||
<span>
|
<span>
|
||||||
<img
|
<img
|
||||||
src='/static/emoji/img_trans.gif'
|
src='/static/images/img_trans.gif'
|
||||||
className={' emojisprite-preview emoji-' + selected.filename + ' '}
|
className={' emojisprite-preview emoji-' + selected.filename + ' '}
|
||||||
align='absmiddle'
|
align='absmiddle'
|
||||||
/>
|
/>
|
||||||
@@ -293,9 +323,9 @@ export default class EmojiPicker extends React.Component {
|
|||||||
|
|
||||||
for (const category of CATEGORIES) {
|
for (const category of CATEGORIES) {
|
||||||
if (category === 'custom') {
|
if (category === 'custom') {
|
||||||
items.push(this.renderCategory('custom', this.state.filter, this.props.customEmojis));
|
items.push(this.renderCategory('custom', true, this.state.filter, this.props.customEmojis));
|
||||||
} else {
|
} else {
|
||||||
items.push(this.renderCategory(category, this.state.filter));
|
items.push(this.renderCategory(category, category === 'recent' || this.state.preloaded.indexOf(category) >= 0, this.state.filter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,15 +387,15 @@ export default class EmojiPicker extends React.Component {
|
|||||||
selected={this.state.category === 'nature'}
|
selected={this.state.category === 'nature'}
|
||||||
/>
|
/>
|
||||||
<EmojiPickerCategory
|
<EmojiPickerCategory
|
||||||
category='food'
|
category='foods'
|
||||||
icon={
|
icon={
|
||||||
<i
|
<i
|
||||||
className='fa fa-cutlery'
|
className='fa fa-cutlery'
|
||||||
title={Utils.localizeMessage('emoji_picker.food', 'Food')}
|
title={Utils.localizeMessage('emoji_picker.foods', 'Foods')}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onCategoryClick={this.handleCategoryClick}
|
onCategoryClick={this.handleCategoryClick}
|
||||||
selected={this.state.category === 'food'}
|
selected={this.state.category === 'foods'}
|
||||||
/>
|
/>
|
||||||
<EmojiPickerCategory
|
<EmojiPickerCategory
|
||||||
category='activity'
|
category='activity'
|
||||||
@@ -379,15 +409,15 @@ export default class EmojiPicker extends React.Component {
|
|||||||
selected={this.state.category === 'activity'}
|
selected={this.state.category === 'activity'}
|
||||||
/>
|
/>
|
||||||
<EmojiPickerCategory
|
<EmojiPickerCategory
|
||||||
category='travel'
|
category='places'
|
||||||
icon={
|
icon={
|
||||||
<i
|
<i
|
||||||
className='fa fa-plane'
|
className='fa fa-plane'
|
||||||
title={Utils.localizeMessage('emoji_picker.travel', 'Travel')}
|
title={Utils.localizeMessage('emoji_picker.places', 'Places')}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onCategoryClick={this.handleCategoryClick}
|
onCategoryClick={this.handleCategoryClick}
|
||||||
selected={this.state.category === 'travel'}
|
selected={this.state.category === 'places'}
|
||||||
/>
|
/>
|
||||||
<EmojiPickerCategory
|
<EmojiPickerCategory
|
||||||
category='objects'
|
category='objects'
|
||||||
@@ -459,3 +489,87 @@ export default class EmojiPicker extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var preloads = {
|
||||||
|
people: {
|
||||||
|
src: PeopleSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
nature: {
|
||||||
|
src: NatureSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
foods: {
|
||||||
|
src: FoodsSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
activity: {
|
||||||
|
src: ActivitySpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
places: {
|
||||||
|
src: PlacesSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
objects: {
|
||||||
|
src: ObjectsSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
symbols: {
|
||||||
|
src: SymbolsSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
},
|
||||||
|
flags: {
|
||||||
|
src: FlagsSpriteSheet,
|
||||||
|
didPreload: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var didBeginPreloading = false;
|
||||||
|
|
||||||
|
var preloadCallback = null;
|
||||||
|
|
||||||
|
export function beginPreloading() {
|
||||||
|
if (didBeginPreloading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
didBeginPreloading = true;
|
||||||
|
preloadNextCategory();
|
||||||
|
}
|
||||||
|
|
||||||
|
function preloadNextCategory() {
|
||||||
|
let sheet = null;
|
||||||
|
for (const category of CATEGORIES) {
|
||||||
|
const preload = preloads[category];
|
||||||
|
if (preload && !preload.didPreload) {
|
||||||
|
sheet = preload;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sheet) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
sheet.didPreload = true;
|
||||||
|
if (preloadCallback) {
|
||||||
|
preloadCallback();
|
||||||
|
}
|
||||||
|
preloadNextCategory();
|
||||||
|
};
|
||||||
|
img.src = sheet.src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function didPreloadCategory(category) {
|
||||||
|
const preload = preloads[category];
|
||||||
|
return preload && preload.didPreload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeToPreloads(callback) {
|
||||||
|
preloadCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsubscribeFromPreloads(callback) {
|
||||||
|
if (callback === preloadCallback) {
|
||||||
|
preloadCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1335,14 +1335,14 @@
|
|||||||
"emoji_picker.custom": "Custom",
|
"emoji_picker.custom": "Custom",
|
||||||
"emoji_picker.emojiPicker": "Emoji Picker",
|
"emoji_picker.emojiPicker": "Emoji Picker",
|
||||||
"emoji_picker.flags": "Flags",
|
"emoji_picker.flags": "Flags",
|
||||||
"emoji_picker.food": "Food",
|
"emoji_picker.foods": "Foods",
|
||||||
"emoji_picker.nature": "Nature",
|
"emoji_picker.nature": "Nature",
|
||||||
"emoji_picker.objects": "Objects",
|
"emoji_picker.objects": "Objects",
|
||||||
"emoji_picker.people": "People",
|
"emoji_picker.people": "People",
|
||||||
"emoji_picker.recent": "Recently Used",
|
"emoji_picker.recent": "Recently Used",
|
||||||
"emoji_picker.search": "Search",
|
"emoji_picker.search": "Search",
|
||||||
"emoji_picker.symbols": "Symbols",
|
"emoji_picker.symbols": "Symbols",
|
||||||
"emoji_picker.travel": "Travel",
|
"emoji_picker.places": "Places",
|
||||||
"error.local_storage.help1": "Enable cookies",
|
"error.local_storage.help1": "Enable cookies",
|
||||||
"error.local_storage.help2": "Turn off private browsing",
|
"error.local_storage.help2": "Turn off private browsing",
|
||||||
"error.local_storage.help3": "Use a supported browser (IE 11, Chrome 43+, Firefox 38+, Safari 9, Edge)",
|
"error.local_storage.help3": "Use a supported browser (IE 11, Chrome 43+, Firefox 38+, Safari 9, Edge)",
|
||||||
|
|||||||
Двоичные данные
webapp/images/emoji-sheets/activity.png
Обычный файл
|
После Ширина: | Высота: | Размер: 503 KiB |
Двоичные данные
webapp/images/emoji-sheets/custom.png
Обычный файл
|
После Ширина: | Высота: | Размер: 54 KiB |
Двоичные данные
webapp/images/emoji-sheets/flags.png
Обычный файл
|
После Ширина: | Высота: | Размер: 1.0 MiB |
Двоичные данные
webapp/images/emoji-sheets/foods.png
Обычный файл
|
После Ширина: | Высота: | Размер: 577 KiB |
Двоичные данные
webapp/images/emoji-sheets/nature.png
Обычный файл
|
После Ширина: | Высота: | Размер: 1.0 MiB |
Двоичные данные
webapp/images/emoji-sheets/objects.png
Обычный файл
|
После Ширина: | Высота: | Размер: 1.0 MiB |
Двоичные данные
webapp/images/emoji-sheets/people.png
Обычный файл
|
После Ширина: | Высота: | Размер: 1.8 MiB |
Двоичные данные
webapp/images/emoji-sheets/places.png
Обычный файл
|
После Ширина: | Высота: | Размер: 812 KiB |
Двоичные данные
webapp/images/emoji-sheets/symbols.png
Обычный файл
|
После Ширина: | Высота: | Размер: 960 KiB |
Двоичные данные
webapp/images/emoji/0023-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0023-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.3 KiB |
Двоичные данные
webapp/images/emoji/002a-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
webapp/images/emoji/0030-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0030-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичные данные
webapp/images/emoji/0031-20e3.png
|
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
webapp/images/emoji/0031-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0032-20e3.png
|
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/0032-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
webapp/images/emoji/0033-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0033-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.3 KiB |
Двоичные данные
webapp/images/emoji/0034-20e3.png
|
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/0034-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.7 KiB |
Двоичные данные
webapp/images/emoji/0035-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0035-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.1 KiB |
Двоичные данные
webapp/images/emoji/0036-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0036-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/0037-20e3.png
|
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
webapp/images/emoji/0037-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.5 KiB |
Двоичные данные
webapp/images/emoji/0038-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0038-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
webapp/images/emoji/0039-20e3.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/0039-fe0f-20e3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/00a9-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/00a9.png
|
До Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
webapp/images/emoji/00ae-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
webapp/images/emoji/00ae.png
|
До Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
webapp/images/emoji/1f004-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.9 KiB |
Двоичные данные
webapp/images/emoji/1f004.png
|
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/1f0cf.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 4.4 KiB |
Двоичные данные
webapp/images/emoji/1f170-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
webapp/images/emoji/1f170.png
|
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/1f171-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.9 KiB |
Двоичные данные
webapp/images/emoji/1f171.png
|
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
webapp/images/emoji/1f17e-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.6 KiB |
Двоичные данные
webapp/images/emoji/1f17e.png
|
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
webapp/images/emoji/1f17f-fe0f.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.4 KiB |
Двоичные данные
webapp/images/emoji/1f17f.png
|
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
webapp/images/emoji/1f18e.png
|
До Ширина: | Высота: | Размер: 2.5 KiB После Ширина: | Высота: | Размер: 3.7 KiB |
Двоичные данные
webapp/images/emoji/1f191.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 3.3 KiB |
Двоичные данные
webapp/images/emoji/1f192.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 3.8 KiB |
Двоичные данные
webapp/images/emoji/1f193.png
|
До Ширина: | Высота: | Размер: 2.2 KiB После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичные данные
webapp/images/emoji/1f194.png
|
До Ширина: | Высота: | Размер: 2.3 KiB После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичные данные
webapp/images/emoji/1f195.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
webapp/images/emoji/1f196.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
webapp/images/emoji/1f197.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
webapp/images/emoji/1f198.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 4.7 KiB |
Двоичные данные
webapp/images/emoji/1f199.png
|
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
webapp/images/emoji/1f19a.png
|
До Ширина: | Высота: | Размер: 2.3 KiB После Ширина: | Высота: | Размер: 3.3 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1e9.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1ea.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.1 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1eb.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1ec.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1ee.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f1.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f2.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.6 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f4.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.7 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f6.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f7.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.9 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f8.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.6 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1f9.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.6 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1fa.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.5 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1fc.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.1 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1fd.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.2 KiB |
Двоичные данные
webapp/images/emoji/1f1e6-1f1ff.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.1 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1e6.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1e7.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1e9.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1ea.png
Обычный файл
|
После Ширина: | Высота: | Размер: 2.5 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1eb.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1ec.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1ed.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1ee.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.2 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1ef.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f1.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.3 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f2.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.4 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f3.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.3 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f4.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f6.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.8 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f7.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.8 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f8.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.9 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1f9.png
Обычный файл
|
После Ширина: | Высота: | Размер: 5.0 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1fc.png
Обычный файл
|
После Ширина: | Высота: | Размер: 4.2 KiB |
Двоичные данные
webapp/images/emoji/1f1e7-1f1fe.png
Обычный файл
|
После Ширина: | Высота: | Размер: 3.3 KiB |