Files
glchat/web/src/lib/emoji.ts
T
grendervill a126f50468 feat(web): виды сообщений, автокомплиты композера и ссылки на комнаты
- лента оформляет виды сообщений от сервера: action (/me) — имя акцентом и
  курсив, whisper — приглушённый блок с бейджем, scream — крупнее и жирнее,
  private (/ls) — рамка, замок и бейдж «лично», system — центрированная строка
  без аватара и панели действий; реакции, ответы, правка и удаление работают
  как раньше, группировка не сливает нестандартные виды с обычными;
- автокомплиты в поле ввода с навигацией ↑/↓, Enter/Tab, Escape и мышью:
  @ — участники сервера (в DM собеседник), # — видимые текстовые комнаты,
  : — словарь на 113 эмодзи, / — команды с описанием; подсказки не появляются
  внутри слова и в блоках кода, вставка восстанавливает каретку и не расходится
  со слоем подсветки;
- `<#id>` рендерится как #имя комнаты из снапшота (иначе #id);
- 287 тестов Vitest (было 262), check/lint/test/build зелёные.
2026-09-20 12:06:22 +03:00

156 lines
5.8 KiB
TypeScript

/**
* Словарь эмодзи для автокомплита в композере: короткий код (`:fire:`) и сам
* символ. Отдельный модуль, а не внешняя зависимость: инстанс автономен, а
* набор кодов должен совпадать с тем, что видит пользователь в подсказке.
*
* Коды намеренно «классические» (как в Slack/GitHub), чтобы привычные
* сокращения работали и в нашем клиенте.
*/
/** Эмодзи с коротким кодом. */
export interface EmojiEntry {
/** Короткий код без двоеточий (`smile`, `thumbsup`). */
code: string;
/** Сам символ, который вставляется в сообщение. */
emoji: string;
}
/** Популярные эмодзи: словарь подсказок `:код:`. */
export const EMOJI: readonly EmojiEntry[] = [
{ code: 'smile', emoji: '😄' },
{ code: 'grin', emoji: '😁' },
{ code: 'joy', emoji: '😂' },
{ code: 'rofl', emoji: '🤣' },
{ code: 'wink', emoji: '😉' },
{ code: 'blush', emoji: '😊' },
{ code: 'heart_eyes', emoji: '😍' },
{ code: 'thinking', emoji: '🤔' },
{ code: 'neutral', emoji: '😐' },
{ code: 'cry', emoji: '😢' },
{ code: 'sob', emoji: '😭' },
{ code: 'angry', emoji: '😠' },
{ code: 'rage', emoji: '😡' },
{ code: 'scream', emoji: '😱' },
{ code: 'sunglasses', emoji: '😎' },
{ code: 'sleeping', emoji: '😴' },
{ code: 'sick', emoji: '🤒' },
{ code: 'ghost', emoji: '👻' },
{ code: 'robot', emoji: '🤖' },
{ code: 'clown', emoji: '🤡' },
{ code: 'skull', emoji: '💀' },
{ code: 'poop', emoji: '💩' },
{ code: 'heart', emoji: '❤️' },
{ code: 'broken_heart', emoji: '💔' },
{ code: 'sparkles', emoji: '✨' },
{ code: 'star', emoji: '⭐' },
{ code: 'star2', emoji: '🌟' },
{ code: 'fire', emoji: '🔥' },
{ code: 'zap', emoji: '⚡' },
{ code: 'boom', emoji: '💥' },
{ code: 'rainbow', emoji: '🌈' },
{ code: 'sun', emoji: '☀️' },
{ code: 'moon', emoji: '🌙' },
{ code: 'cloud', emoji: '☁️' },
{ code: 'snowflake', emoji: '❄️' },
{ code: 'droplet', emoji: '💧' },
{ code: 'ocean', emoji: '🌊' },
{ code: 'earth', emoji: '🌍' },
{ code: 'rocket', emoji: '🚀' },
{ code: 'airplane', emoji: '✈️' },
{ code: 'car', emoji: '🚗' },
{ code: 'bulb', emoji: '💡' },
{ code: 'warning', emoji: '⚠️' },
{ code: 'check', emoji: '✅' },
{ code: 'x', emoji: '❌' },
{ code: 'question', emoji: '❓' },
{ code: 'exclamation', emoji: '❗' },
{ code: '100', emoji: '💯' },
{ code: 'ok', emoji: '👌' },
{ code: 'thumbsup', emoji: '👍' },
{ code: 'thumbsdown', emoji: '👎' },
{ code: 'clap', emoji: '👏' },
{ code: 'pray', emoji: '🙏' },
{ code: 'muscle', emoji: '💪' },
{ code: 'wave', emoji: '👋' },
{ code: 'point_up', emoji: '☝️' },
{ code: 'point_right', emoji: '👉' },
{ code: 'eyes', emoji: '👀' },
{ code: 'handshake', emoji: '🤝' },
{ code: 'salute', emoji: '🫡' },
{ code: 'brain', emoji: '🧠' },
{ code: 'coffee', emoji: '☕' },
{ code: 'beer', emoji: '🍺' },
{ code: 'pizza', emoji: '🍕' },
{ code: 'cake', emoji: '🍰' },
{ code: 'gift', emoji: '🎁' },
{ code: 'tada', emoji: '🎉' },
{ code: 'party', emoji: '🥳' },
{ code: 'balloon', emoji: '🎈' },
{ code: 'soccer', emoji: '⚽' },
{ code: 'basketball', emoji: '🏀' },
{ code: 'game', emoji: '🎮' },
{ code: 'trophy', emoji: '🏆' },
{ code: 'medal', emoji: '🏅' },
{ code: 'dice', emoji: '🎲' },
{ code: 'book', emoji: '📖' },
{ code: 'memo', emoji: '📝' },
{ code: 'pushpin', emoji: '📌' },
{ code: 'paperclip', emoji: '📎' },
{ code: 'bell', emoji: '🔔' },
{ code: 'hourglass', emoji: '⏳' },
{ code: 'alarm', emoji: '⏰' },
{ code: 'lock', emoji: '🔒' },
{ code: 'key', emoji: '🔑' },
{ code: 'mag', emoji: '🔍' },
{ code: 'hammer', emoji: '🔨' },
{ code: 'wrench', emoji: '🔧' },
{ code: 'bug', emoji: '🐛' },
{ code: 'cat', emoji: '🐱' },
{ code: 'dog', emoji: '🐶' },
{ code: 'fox', emoji: '🦊' },
{ code: 'unicorn', emoji: '🦄' },
{ code: 'panda', emoji: '🐼' },
{ code: 'sunflower', emoji: '🌻' },
{ code: 'rose', emoji: '🌹' },
{ code: 'tree', emoji: '🌳' },
{ code: 'apple', emoji: '🍎' },
{ code: 'watermelon', emoji: '🍉' },
{ code: 'burger', emoji: '🍔' },
{ code: 'fries', emoji: '🍟' },
{ code: 'sushi', emoji: '🍣' },
{ code: 'icecream', emoji: '🍦' },
{ code: 'popcorn', emoji: '🍿' },
{ code: 'music', emoji: '🎵' },
{ code: 'guitar', emoji: '🎸' },
{ code: 'mic', emoji: '🎤' },
{ code: 'camera', emoji: '📷' },
{ code: 'movie', emoji: '🎬' },
{ code: 'computer', emoji: '💻' },
{ code: 'phone', emoji: '📱' },
{ code: 'battery', emoji: '🔋' },
{ code: 'gear', emoji: '⚙️' },
{ code: 'shield', emoji: '🛡️' },
{ code: 'crown', emoji: '👑' },
{ code: 'gem', emoji: '💎' },
{ code: 'money', emoji: '💰' },
{ code: 'chart', emoji: '📈' },
];
/**
* Эмодзи по префиксу кода: `fir` → 🔥. Регистр не важен, порядок словаря
* сохраняется — популярные эмодзи стоят в начале и попадают в список первыми.
*/
export function searchEmoji(query: string, limit: number): EmojiEntry[] {
const prefix = query.toLowerCase();
const found: EmojiEntry[] = [];
for (const entry of EMOJI) {
if (entry.code.startsWith(prefix)) {
found.push(entry);
if (found.length >= limit) {
break;
}
}
}
return found;
}