SHA256
Очистить репозиторий перед переносом продукта
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
TELEGRAM_EMOJI_GROUPS,
|
||||
getTelegramEmojiAssetUrl,
|
||||
getTelegramEmojiPreviewUrl,
|
||||
} from './telegram-emoji-catalog.js?v=202607151545';
|
||||
TWEMOJI_GROUPS,
|
||||
getTwemojiAssetUrl,
|
||||
getTwemojiPreviewUrl,
|
||||
} from './twemoji-catalog.js?v=202607151545';
|
||||
|
||||
const RECENT_STORAGE_KEY = 'shine-ui-recent-emojis-v1';
|
||||
const MAX_RECENT = 28;
|
||||
const ALL_EMOJI_ITEMS = TELEGRAM_EMOJI_GROUPS.flatMap((group) => group.items);
|
||||
const ALL_EMOJI_ITEMS = TWEMOJI_GROUPS.flatMap((group) => group.items);
|
||||
const EMOJI_ASSET_BY_CHAR = new Map(ALL_EMOJI_ITEMS.map((item) => [item.emoji, item]));
|
||||
const TELEGRAM_EMOJI_MATCHER = new RegExp(
|
||||
const TWEMOJI_MATCHER = new RegExp(
|
||||
[...EMOJI_ASSET_BY_CHAR.keys()]
|
||||
.sort((left, right) => right.length - left.length)
|
||||
.map((emoji) => emoji.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'))
|
||||
@@ -38,11 +38,11 @@ function saveRecent(items) {
|
||||
}
|
||||
|
||||
function appendAnimatedAsset(root, item) {
|
||||
const previewUrl = item.previewUrl || getTelegramEmojiPreviewUrl(item.file);
|
||||
const animatedUrl = item.animatedUrl || getTelegramEmojiAssetUrl(item.file);
|
||||
const previewUrl = item.previewUrl || getTwemojiPreviewUrl(item.emoji);
|
||||
const animatedUrl = item.animatedUrl || getTwemojiAssetUrl(item.emoji);
|
||||
const hasAnimation = animatedUrl && animatedUrl !== previewUrl;
|
||||
const image = document.createElement('img');
|
||||
image.className = 'telegram-emoji-image';
|
||||
image.className = 'twemoji-image';
|
||||
image.alt = '';
|
||||
image.decoding = 'async';
|
||||
image.setAttribute('aria-hidden', 'true');
|
||||
@@ -134,7 +134,7 @@ function appendAnimatedAsset(root, item) {
|
||||
root.append(image);
|
||||
}
|
||||
|
||||
export function stopAllTelegramEmojiAnimations() {
|
||||
export function stopAllTwemojiAnimations() {
|
||||
activeAnimation?.deactivate();
|
||||
activeAnimation = null;
|
||||
}
|
||||
@@ -155,14 +155,14 @@ function createEmojiButton(item, onSelect) {
|
||||
return button;
|
||||
}
|
||||
|
||||
export function isTelegramAnimatedEmoji(emoji) {
|
||||
export function hasTwemojiAsset(emoji) {
|
||||
return EMOJI_ASSET_BY_CHAR.has(emoji);
|
||||
}
|
||||
|
||||
export function createTelegramAnimatedEmoji(emoji, { className = '' } = {}) {
|
||||
export function createTwemojiAsset(emoji, { className = '' } = {}) {
|
||||
const item = EMOJI_ASSET_BY_CHAR.get(emoji);
|
||||
const root = document.createElement('span');
|
||||
root.className = `telegram-emoji ${className}`.trim();
|
||||
root.className = `twemoji ${className}`.trim();
|
||||
root.setAttribute('aria-label', emoji);
|
||||
root.setAttribute('role', 'img');
|
||||
|
||||
@@ -175,16 +175,16 @@ export function createTelegramAnimatedEmoji(emoji, { className = '' } = {}) {
|
||||
return root;
|
||||
}
|
||||
|
||||
export function appendTelegramAnimatedText(root, text, { className = '' } = {}) {
|
||||
export function appendTwemojiText(root, text, { className = '' } = {}) {
|
||||
const source = String(text || '');
|
||||
let cursor = 0;
|
||||
let found = false;
|
||||
|
||||
TELEGRAM_EMOJI_MATCHER.lastIndex = 0;
|
||||
for (const match of source.matchAll(TELEGRAM_EMOJI_MATCHER)) {
|
||||
TWEMOJI_MATCHER.lastIndex = 0;
|
||||
for (const match of source.matchAll(TWEMOJI_MATCHER)) {
|
||||
const index = Number(match.index || 0);
|
||||
if (index > cursor) root.append(document.createTextNode(source.slice(cursor, index)));
|
||||
root.append(createTelegramAnimatedEmoji(match[0], { className }));
|
||||
root.append(createTwemojiAsset(match[0], { className }));
|
||||
cursor = index + match[0].length;
|
||||
found = true;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ export function createEmojiPicker({ onSelect }) {
|
||||
categoryGrid.className = 'emoji-picker-grid';
|
||||
categorySection.append(categoryTitle, categoryGrid);
|
||||
|
||||
let activeGroup = TELEGRAM_EMOJI_GROUPS[0];
|
||||
let activeGroup = TWEMOJI_GROUPS[0];
|
||||
const tabs = new Map();
|
||||
|
||||
const rememberAndSelect = (emoji) => {
|
||||
@@ -238,13 +238,13 @@ export function createEmojiPicker({ onSelect }) {
|
||||
const recentItems = (loadRecent().length ? loadRecent() : DEFAULT_RECENT)
|
||||
.map((emoji) => EMOJI_ASSET_BY_CHAR.get(emoji))
|
||||
.filter(Boolean);
|
||||
stopAllTelegramEmojiAnimations();
|
||||
stopAllTwemojiAnimations();
|
||||
recentGrid.replaceChildren(...recentItems.map((item) => createEmojiButton(item, rememberAndSelect)));
|
||||
};
|
||||
|
||||
const renderGroup = () => {
|
||||
categoryTitle.textContent = activeGroup.label;
|
||||
stopAllTelegramEmojiAnimations();
|
||||
stopAllTwemojiAnimations();
|
||||
categoryGrid.replaceChildren(...activeGroup.items.map((item) => createEmojiButton(item, rememberAndSelect)));
|
||||
tabs.forEach((tab, groupId) => {
|
||||
const active = groupId === activeGroup.id;
|
||||
@@ -253,7 +253,7 @@ export function createEmojiPicker({ onSelect }) {
|
||||
});
|
||||
};
|
||||
|
||||
TELEGRAM_EMOJI_GROUPS.forEach((group) => {
|
||||
TWEMOJI_GROUPS.forEach((group) => {
|
||||
const tab = document.createElement('button');
|
||||
tab.type = 'button';
|
||||
tab.className = 'emoji-picker-tab';
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { TELEGRAM_EMOJI_GROUP_ACTIVITY } from './telegram-emoji-activity.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_ANIMALS_NATURE } from './telegram-emoji-animals_nature.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_FLAGS } from './telegram-emoji-flags.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_FOOD_DRINK } from './telegram-emoji-food_drink.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_OBJECTS } from './telegram-emoji-objects.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_PEOPLE } from './telegram-emoji-people.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_SMILEYS } from './telegram-emoji-smileys.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_SYMBOLS } from './telegram-emoji-symbols.js?v=202607151545';
|
||||
import { TELEGRAM_EMOJI_GROUP_TRAVEL_PLACES } from './telegram-emoji-travel_places.js?v=202607151545';
|
||||
|
||||
const TELEGRAM_EMOJI_PREVIEW_BASE_URL = '/assets/emoji/telegram-previews/';
|
||||
|
||||
function getTelegramEmojiName(file) {
|
||||
return String(file || '').split('/').pop()?.replace(/\.webp$/i, '') || '';
|
||||
}
|
||||
|
||||
function withPreviewUrls(group) {
|
||||
return {
|
||||
...group,
|
||||
items: group.items.map((item) => ({
|
||||
...item,
|
||||
name: item.name || getTelegramEmojiName(item.file),
|
||||
previewUrl: getTelegramEmojiPreviewUrl(item.file),
|
||||
animatedUrl: getTelegramEmojiAssetUrl(item.file),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export const TELEGRAM_EMOJI_GROUPS = [
|
||||
TELEGRAM_EMOJI_GROUP_SMILEYS,
|
||||
TELEGRAM_EMOJI_GROUP_PEOPLE,
|
||||
TELEGRAM_EMOJI_GROUP_ANIMALS_NATURE,
|
||||
TELEGRAM_EMOJI_GROUP_FOOD_DRINK,
|
||||
TELEGRAM_EMOJI_GROUP_TRAVEL_PLACES,
|
||||
TELEGRAM_EMOJI_GROUP_ACTIVITY,
|
||||
TELEGRAM_EMOJI_GROUP_OBJECTS,
|
||||
TELEGRAM_EMOJI_GROUP_SYMBOLS,
|
||||
TELEGRAM_EMOJI_GROUP_FLAGS,
|
||||
].map(withPreviewUrls);
|
||||
|
||||
export function getTelegramEmojiAssetUrl(file) {
|
||||
// Анимированные webp с raw.githubusercontent.com отключены: внешний хост
|
||||
// блокируется у части пользователей (VPN/операторы) — тап по эмодзи вызывал
|
||||
// сетевую ошибку и «моргание» картинки. Пока отдаём локальное статичное превью;
|
||||
// возврат анимаций — только локальным паком в assets.
|
||||
return getTelegramEmojiPreviewUrl(file);
|
||||
}
|
||||
|
||||
export function getTelegramEmojiPreviewUrl(file) {
|
||||
return `${TELEGRAM_EMOJI_PREVIEW_BASE_URL}${String(file || '').replace(/\.webp$/i, '.png').split('/').map((part) => encodeURIComponent(part)).join('/')}`;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_ACTIVITY = {
|
||||
export const TWEMOJI_GROUP_ACTIVITY = {
|
||||
"id": "activity",
|
||||
"label": "Активности",
|
||||
"icon": "🎉",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_ANIMALS_NATURE = {
|
||||
export const TWEMOJI_GROUP_ANIMALS_NATURE = {
|
||||
"id": "animals-and-nature",
|
||||
"label": "Природа и животные",
|
||||
"icon": "🌿",
|
||||
@@ -0,0 +1,52 @@
|
||||
import { TWEMOJI_GROUP_ACTIVITY } from './twemoji-activity.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_ANIMALS_NATURE } from './twemoji-animals_nature.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_FLAGS } from './twemoji-flags.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_FOOD_DRINK } from './twemoji-food_drink.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_OBJECTS } from './twemoji-objects.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_PEOPLE } from './twemoji-people.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_SMILEYS } from './twemoji-smileys.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_SYMBOLS } from './twemoji-symbols.js?v=202607151545';
|
||||
import { TWEMOJI_GROUP_TRAVEL_PLACES } from './twemoji-travel_places.js?v=202607151545';
|
||||
|
||||
const TWEMOJI_SVG_BASE_URL = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/';
|
||||
|
||||
function getTwemojiCodepoint(emoji) {
|
||||
return Array.from(String(emoji || ''))
|
||||
.map((char) => char.codePointAt(0))
|
||||
.filter((codepoint) => codepoint && codepoint !== 0xfe0f)
|
||||
.map((codepoint) => codepoint.toString(16))
|
||||
.join('-');
|
||||
}
|
||||
|
||||
function withPreviewUrls(group) {
|
||||
return {
|
||||
...group,
|
||||
items: group.items.map((item) => ({
|
||||
...item,
|
||||
name: item.name || String(item.emoji || ''),
|
||||
previewUrl: getTwemojiPreviewUrl(item.emoji),
|
||||
animatedUrl: getTwemojiAssetUrl(item.emoji),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export const TWEMOJI_GROUPS = [
|
||||
TWEMOJI_GROUP_SMILEYS,
|
||||
TWEMOJI_GROUP_PEOPLE,
|
||||
TWEMOJI_GROUP_ANIMALS_NATURE,
|
||||
TWEMOJI_GROUP_FOOD_DRINK,
|
||||
TWEMOJI_GROUP_TRAVEL_PLACES,
|
||||
TWEMOJI_GROUP_ACTIVITY,
|
||||
TWEMOJI_GROUP_OBJECTS,
|
||||
TWEMOJI_GROUP_SYMBOLS,
|
||||
TWEMOJI_GROUP_FLAGS,
|
||||
].map(withPreviewUrls);
|
||||
|
||||
export function getTwemojiAssetUrl(emoji) {
|
||||
return getTwemojiPreviewUrl(emoji);
|
||||
}
|
||||
|
||||
export function getTwemojiPreviewUrl(emoji) {
|
||||
const codepoint = getTwemojiCodepoint(emoji);
|
||||
return codepoint ? `${TWEMOJI_SVG_BASE_URL}${codepoint}.svg` : '';
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_FLAGS = {
|
||||
export const TWEMOJI_GROUP_FLAGS = {
|
||||
"id": "flags",
|
||||
"label": "Флаги",
|
||||
"icon": "🏳️",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_FOOD_DRINK = {
|
||||
export const TWEMOJI_GROUP_FOOD_DRINK = {
|
||||
"id": "food-and-drink",
|
||||
"label": "Еда и напитки",
|
||||
"icon": "🍓",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_OBJECTS = {
|
||||
export const TWEMOJI_GROUP_OBJECTS = {
|
||||
"id": "objects",
|
||||
"label": "Предметы",
|
||||
"icon": "💡",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_PEOPLE = {
|
||||
export const TWEMOJI_GROUP_PEOPLE = {
|
||||
"id": "people",
|
||||
"label": "Люди",
|
||||
"icon": "🧑",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_SMILEYS = {
|
||||
export const TWEMOJI_GROUP_SMILEYS = {
|
||||
"id": "smileys",
|
||||
"label": "Смайлы",
|
||||
"icon": "🙂",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_SYMBOLS = {
|
||||
export const TWEMOJI_GROUP_SYMBOLS = {
|
||||
"id": "symbols",
|
||||
"label": "Символы",
|
||||
"icon": "❤️",
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export const TELEGRAM_EMOJI_GROUP_TRAVEL_PLACES = {
|
||||
export const TWEMOJI_GROUP_TRAVEL_PLACES = {
|
||||
"id": "travel-and-places",
|
||||
"label": "Путешествия",
|
||||
"icon": "✈️",
|
||||
Reference in New Issue
Block a user