diff --git a/.gitignore b/.gitignore index efe7735..2ddd675 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -unpackage \ No newline at end of file +node_modules +unpackage diff --git a/App.vue b/App.vue index 6b707a0..de1333d 100644 --- a/App.vue +++ b/App.vue @@ -1,4 +1,4 @@ - + diff --git a/TUIKit/components/TUIChat/config.ts b/TUIKit/components/TUIChat/config.ts new file mode 100644 index 0000000..a4ee9c4 --- /dev/null +++ b/TUIKit/components/TUIChat/config.ts @@ -0,0 +1,130 @@ +const defaultFeatures = { + DownloadFile: true, + CopyMessage: true, + DeleteMessage: true, + RevokeMessage: true, + QuoteMessage: true, + ForwardMessage: true, + TranslateMessage: true, + VoiceToText: true, + MultiSelection: true, + EmojiReaction: true, + InputEmoji: true, + InputStickers: true, + InputImage: true, + InputVoice: true, + InputVideo: true, + InputFile: true, + InputAlbum: true, + InputCamera: true, + InputEvaluation: true, + InputQuickReplies: true, + InputMention: true, + MessageSearch: true, + ReadStatus: true, + ClearHistory: false, +}; + +enum FeaturesType { + DownloadFile = 'DownloadFile', + CopyMessage = 'CopyMessage', + DeleteMessage = 'DeleteMessage', + RevokeMessage = 'RevokeMessage', + QuoteMessage = 'QuoteMessage', + ForwardMessage = 'ForwardMessage', + TranslateMessage = 'TranslateMessage', + VoiceToText = 'VoiceToText', + MultiSelection = 'MultiSelection', + EmojiReaction = 'EmojiReaction', + InputEmoji = 'InputEmoji', + InputStickers = 'InputStickers', + InputImage = 'InputImage', + InputVoice = 'InputVoice', + InputVideo = 'InputVideo', + InputFile = 'InputFile', + InputAlbum = 'InputAlbum', + InputCamera = 'InputCamera', + InputEvaluation = 'InputEvaluation', + InputQuickReplies = 'InputQuickReplies', + InputMention = 'InputMention', + MessageSearch = 'MessageSearch', + ReadStatus = 'ReadStatus', + ClearHistory = 'ClearHistory', +} + +class TUIChatConfig { + static instance: TUIChatConfig; + private chatType: string; + private features: Record; + private theme: string; + constructor() { + this.chatType = ''; + this.features = JSON.parse(JSON.stringify(defaultFeatures)); + this.theme = 'light'; + } + + static getInstance(): TUIChatConfig { + if (!TUIChatConfig.instance) { + TUIChatConfig.instance = new TUIChatConfig(); + } + return TUIChatConfig.instance; + } + + setChatType(chatType: string) { + this.chatType = chatType; + } + + getChatType() { + return this.chatType; + } + + showTUIChatFeatures(features?: string[]) { + if (!features) { + return; + } else { + features.forEach((feature: string) => { + this.features[feature] = true; + }); + } + } + + hideTUIChatFeatures(features: string[]) { + if (!features) { + return; + } + features.forEach((feature: string) => { + if (this.features[feature]) { + this.features[feature] = false; + } + }); + } + + getFeatureConfig(key?: string) { + if (key) { + return this.features[key]; + } + return this.features; + } + + setTheme(theme: string) { + this.theme = theme; + } + + getTheme() { + return this.theme; + } + + resetFeatureConfig() { + this.features = JSON.parse(JSON.stringify(defaultFeatures)); + } +} + +const ChatConfig = TUIChatConfig.getInstance(); +const hideTUIChatFeatures = ChatConfig.hideTUIChatFeatures.bind(ChatConfig); + +export { + hideTUIChatFeatures, + FeaturesType, +}; + +export default ChatConfig; diff --git a/TUIKit/components/TUIChat/emoji-config/custom-emoji.ts b/TUIKit/components/TUIChat/emoji-config/custom-emoji.ts new file mode 100644 index 0000000..d6501df --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/custom-emoji.ts @@ -0,0 +1,15 @@ +import { IEmojiGroupList } from '../../../interface'; + +/** +* Custom big emoji +*/ +export const CUSTOM_BIG_EMOJI_URL: string = ''; + +export const CUSTOM_BIG_EMOJI_GROUP_LIST: IEmojiGroupList = []; + +/** +* Custom basic emoji +*/ +export const CUSTOM_BASIC_EMOJI_URL: string = ''; + +export const CUSTOM_BASIC_EMOJI_URL_MAPPING: Record = {}; diff --git a/TUIKit/components/TUIChat/emoji-config/default-emoji.ts b/TUIKit/components/TUIChat/emoji-config/default-emoji.ts new file mode 100644 index 0000000..e90d1af --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/default-emoji.ts @@ -0,0 +1,114 @@ +/** + * Emoji input interface in the chat screen. + * In respect for the copyright of the emoji design, the Chat Demo/TUIKit project does not include the cutouts of large emoji elements. + * Please replace them with your own designed or copyrighted emoji packs before the official launch for commercial use. + * The default small yellow face emoji pack is copyrighted by Tencent Cloud and can be authorized for a fee. + * If you wish to obtain authorization, please submit a ticket to contact us. + * + * submit a ticket url:https://console.tencentcloud.com/workorder/category?level1_id=29&level2_id=40&source=14&data_title=Chat&step=1 + */ +import { default as emojiCNLocales } from './locales/zh_cn'; +import { default as emojiENLocales } from './locales/en'; +import { EMOJI_TYPE } from '../../../constant'; +import { IEmojiGroupList } from '../../../interface'; + +export const DEFAULT_BASIC_EMOJI_URL = 'https://web.sdk.qcloud.com/im/assets/emoji-plugin/'; +export const DEFAULT_BIG_EMOJI_URL = 'https://web.sdk.qcloud.com/im/assets/face-elem/'; + +export const DEFAULT_BASIC_EMOJI_URL_MAPPING: Record = { + '[TUIEmoji_Expect]': 'emoji_0@2x.png', + '[TUIEmoji_Blink]': 'emoji_1@2x.png', + '[TUIEmoji_Guffaw]': 'emoji_2@2x.png', + '[TUIEmoji_KindSmile]': 'emoji_3@2x.png', + '[TUIEmoji_Haha]': 'emoji_4@2x.png', + '[TUIEmoji_Cheerful]': 'emoji_5@2x.png', + '[TUIEmoji_Smile]': 'emoji_6@2x.png', + '[TUIEmoji_Sorrow]': 'emoji_7@2x.png', + '[TUIEmoji_Speechless]': 'emoji_8@2x.png', + '[TUIEmoji_Amazed]': 'emoji_9@2x.png', + '[TUIEmoji_Complacent]': 'emoji_10@2x.png', + '[TUIEmoji_Lustful]': 'emoji_11@2x.png', + '[TUIEmoji_Stareyes]': 'emoji_12@2x.png', + '[TUIEmoji_Giggle]': 'emoji_13@2x.png', + '[TUIEmoji_Daemon]': 'emoji_14@2x.png', + '[TUIEmoji_Rage]': 'emoji_15@2x.png', + '[TUIEmoji_Yawn]': 'emoji_16@2x.png', + '[TUIEmoji_TearsLaugh]': 'emoji_17@2x.png', + '[TUIEmoji_Silly]': 'emoji_18@2x.png', + '[TUIEmoji_Wail]': 'emoji_19@2x.png', + '[TUIEmoji_Kiss]': 'emoji_20@2x.png', + '[TUIEmoji_Trapped]': 'emoji_21@2x.png', + '[TUIEmoji_Fear]': 'emoji_22@2x.png', + '[TUIEmoji_BareTeeth]': 'emoji_23@2x.png', + '[TUIEmoji_FlareUp]': 'emoji_24@2x.png', + '[TUIEmoji_Tact]': 'emoji_25@2x.png', + '[TUIEmoji_Shit]': 'emoji_26@2x.png', + '[TUIEmoji_ShutUp]': 'emoji_27@2x.png', + '[TUIEmoji_Sigh]': 'emoji_28@2x.png', + '[TUIEmoji_Hehe]': 'emoji_29@2x.png', + '[TUIEmoji_Silent]': 'emoji_30@2x.png', + '[TUIEmoji_Skull]': 'emoji_31@2x.png', + '[TUIEmoji_Mask]': 'emoji_32@2x.png', + '[TUIEmoji_Beer]': 'emoji_33@2x.png', + '[TUIEmoji_Cake]': 'emoji_34@2x.png', + '[TUIEmoji_RedPacket]': 'emoji_35@2x.png', + '[TUIEmoji_Bombs]': 'emoji_36@2x.png', + '[TUIEmoji_Ai]': 'emoji_37@2x.png', + '[TUIEmoji_Celebrate]': 'emoji_38@2x.png', + '[TUIEmoji_Bless]': 'emoji_39@2x.png', + '[TUIEmoji_Flower]': 'emoji_40@2x.png', + '[TUIEmoji_Watermelon]': 'emoji_41@2x.png', + '[TUIEmoji_Cow]': 'emoji_42@2x.png', + '[TUIEmoji_Fool]': 'emoji_43@2x.png', + '[TUIEmoji_Surprised]': 'emoji_44@2x.png', + '[TUIEmoji_Askance]': 'emoji_45@2x.png', + '[TUIEmoji_Monster]': 'emoji_46@2x.png', + '[TUIEmoji_Pig]': 'emoji_47@2x.png', + '[TUIEmoji_Coffee]': 'emoji_48@2x.png', + '[TUIEmoji_Ok]': 'emoji_49@2x.png', + '[TUIEmoji_Heart]': 'emoji_50@2x.png', + '[TUIEmoji_Sun]': 'emoji_51@2x.png', + '[TUIEmoji_Moon]': 'emoji_52@2x.png', + '[TUIEmoji_Star]': 'emoji_53@2x.png', + '[TUIEmoji_Rich]': 'emoji_54@2x.png', + '[TUIEmoji_Fortune]': 'emoji_55@2x.png', + '[TUIEmoji_857]': 'emoji_56@2x.png', + '[TUIEmoji_666]': 'emoji_57@2x.png', + '[TUIEmoji_Prohibit]': 'emoji_58@2x.png', + '[TUIEmoji_Convinced]': 'emoji_59@2x.png', + '[TUIEmoji_Knife]': 'emoji_60@2x.png', + '[TUIEmoji_Like]': 'emoji_61@2x.png', +}; + +export const BIG_EMOJI_GROUP_LIST: IEmojiGroupList = [ + { + emojiGroupID: 1, + type: EMOJI_TYPE.BIG, + url: DEFAULT_BIG_EMOJI_URL, + list: ['yz00', 'yz01', 'yz02', 'yz03', 'yz04', 'yz05', 'yz06', 'yz07', 'yz08', + 'yz09', 'yz10', 'yz11', 'yz12', 'yz13', 'yz14', 'yz15', 'yz16', 'yz17'], + }, + { + emojiGroupID: 2, + type: EMOJI_TYPE.BIG, + url: DEFAULT_BIG_EMOJI_URL, + list: ['ys00', 'ys01', 'ys02', 'ys03', 'ys04', 'ys05', 'ys06', 'ys07', 'ys08', + 'ys09', 'ys10', 'ys11', 'ys12', 'ys13', 'ys14', 'ys15'], + }, + { + emojiGroupID: 3, + type: EMOJI_TYPE.BIG, + url: DEFAULT_BIG_EMOJI_URL, + list: ['gcs00', 'gcs01', 'gcs02', 'gcs03', 'gcs04', 'gcs05', 'gcs06', 'gcs07', + 'gcs08', 'gcs09', 'gcs10', 'gcs11', 'gcs12', 'gcs13', 'gcs14', 'gcs15', 'gcs16'], + }, +]; + +export const BASIC_EMOJI_NAME_TO_KEY_MAPPING = { + ...Object.fromEntries( + Object.entries(emojiCNLocales)?.map(([key, val]) => [val, key]), + ), + ...Object.fromEntries( + Object.entries(emojiENLocales)?.map(([key, val]) => [val, key]), + ), +}; diff --git a/TUIKit/components/TUIChat/emoji-config/index.ts b/TUIKit/components/TUIChat/emoji-config/index.ts new file mode 100644 index 0000000..259fffd --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/index.ts @@ -0,0 +1,140 @@ +import { TUITranslateService } from '@tencentcloud/chat-uikit-engine-lite'; +import { CUSTOM_BASIC_EMOJI_URL, CUSTOM_BIG_EMOJI_URL, CUSTOM_BASIC_EMOJI_URL_MAPPING, CUSTOM_BIG_EMOJI_GROUP_LIST } from './custom-emoji'; +import { DEFAULT_BASIC_EMOJI_URL, BIG_EMOJI_GROUP_LIST, DEFAULT_BASIC_EMOJI_URL_MAPPING, BASIC_EMOJI_NAME_TO_KEY_MAPPING, DEFAULT_BIG_EMOJI_URL } from './default-emoji'; +import { default as emojiCNLocales } from './locales/zh_cn'; +import { IEmojiGroupList } from '../../../interface'; +import { EMOJI_TYPE } from '../../../constant'; +import { isWeChat } from '../../../utils/env'; + +const hasCustomBasicEmoji = CUSTOM_BASIC_EMOJI_URL && Object.keys(CUSTOM_BASIC_EMOJI_URL_MAPPING).length; + +const BASIC_EMOJI_URL = hasCustomBasicEmoji ? CUSTOM_BASIC_EMOJI_URL : DEFAULT_BASIC_EMOJI_URL; + +const BASIC_EMOJI_URL_MAPPING = hasCustomBasicEmoji ? CUSTOM_BASIC_EMOJI_URL_MAPPING : DEFAULT_BASIC_EMOJI_URL_MAPPING; + +const EMOJI_GROUP_LIST: IEmojiGroupList = [ + { + emojiGroupID: 0, + type: EMOJI_TYPE.BASIC, + url: BASIC_EMOJI_URL, + list: Object.keys(BASIC_EMOJI_URL_MAPPING), + }, + ...BIG_EMOJI_GROUP_LIST, + ...CUSTOM_BIG_EMOJI_GROUP_LIST, +]; + +/** + * Converts a basic emoji key into its corresponding name. + * Example: + * '[Smile]' => '[TUIEmoji_Smile]' + * @param {string} key - The emoji key. + * @return {string} The corresponding emoji name. + */ +const convertKeyToEmojiName = (key: string): string => { + // WeChat does not support emoji translation + return isWeChat ? emojiCNLocales[key] : TUITranslateService.t(`Emoji.${key}`); +}; + +/** + * Transforms a text containing emoji keys into a text with Chinese or English basic emoji names + * Example: + * 'hello[TUIEmoji_Smile]!' => 'hello[Smile]!'' + * @param {string} text - The text containing emoji keys. + * @return {string} The transformed text with emoji keys replaced by emoji names. + */ +const transformTextWithKeysToEmojiNames = (text: string): string => { + if (!text) { + return ''; + } + const reg = /(\[.+?\])/g; + let txt: string = text; + if (reg.test(text)) { + txt = text.replace(reg, match => BASIC_EMOJI_URL_MAPPING[match] ? convertKeyToEmojiName(match) : match); + } + return txt; +}; + +/** + * Transforms a text containing Chinese or English basic emoji names into a text with emoji keys. + * Example: + * 'hello[Smile]!' => 'hello[TUIEmoji_Smile]!' + * @param {string} text - The text containing emoji names. + * @return {string} The transformed text with emoji names replaced by emoji keys. + */ +const transformTextWithEmojiNamesToKeys = (text: string) => { + if (!text) { + return ''; + } + const reg = /(\[.+?\])/g; + let txt: string = text; + if (reg.test(text)) { + txt = text.replace(reg, match => BASIC_EMOJI_NAME_TO_KEY_MAPPING[match] || match); + } + return txt; +}; + +/** +* The configuration aims to provide compatibility with versions prior to 2.2.0 +*/ +const emojiConfig = { + emojiBaseUrl: BASIC_EMOJI_URL, + emojiUrlMapping: BASIC_EMOJI_URL_MAPPING, + emojiNameMapping: { + ...emojiCNLocales, + }, +}; + +/** + * Transform text message to renderable array contains image and text. + * Example: hello[TUIEmoji_Smile], I am happy. + * -> [{type: 'text', content: 'hello'}, {type: 'image', content: 'https://.../smile.png'}, {type: 'text', content: ', I am happy.'}] + * @param text + * @returns Array<{ type: 'text' | 'image'; content: string; emojiKey?: string; }> + */ +const parseTextToRenderArray = (text: string): Array<{ type: 'text' | 'image'; content: string; emojiKey?: string }> => { + const emojiRegex = /\[([^\]]+)\]/g; + const result: any[] = []; + + let match: RegExpExecArray | null; + let lastIndex = 0; + + while ((match = emojiRegex.exec(text)) !== null) { + const startIndex = match.index; + const endIndex = emojiRegex.lastIndex; + const emojiKey = match[0]; + + if (startIndex > lastIndex) { + result.push({ type: 'text', content: text.substring(lastIndex, startIndex) }); + } + + const emojiUrl = BASIC_EMOJI_URL + BASIC_EMOJI_URL_MAPPING[emojiKey]; + if (emojiUrl) { + result.push({ type: 'image', content: emojiUrl, emojiKey }); + } else { + result.push({ type: 'text', content: emojiKey }); + } + + lastIndex = endIndex; + emojiRegex.lastIndex = lastIndex; + } + + if (lastIndex < text.length) { + result.push({ type: 'text', content: text.substring(lastIndex) }); + } + + return result; +}; + +export { + EMOJI_GROUP_LIST, + CUSTOM_BIG_EMOJI_URL, + DEFAULT_BIG_EMOJI_URL, + CUSTOM_BASIC_EMOJI_URL, + BASIC_EMOJI_URL_MAPPING, + CUSTOM_BASIC_EMOJI_URL_MAPPING, + convertKeyToEmojiName, + parseTextToRenderArray, + transformTextWithKeysToEmojiNames, + transformTextWithEmojiNamesToKeys, + emojiConfig, +}; diff --git a/TUIKit/components/TUIChat/emoji-config/locales/en.ts b/TUIKit/components/TUIChat/emoji-config/locales/en.ts new file mode 100644 index 0000000..baa4fd1 --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/locales/en.ts @@ -0,0 +1,66 @@ +const Emoji = { + '[TUIEmoji_Smile]': '[Smile]', + '[TUIEmoji_Expect]': '[Expect]', + '[TUIEmoji_Blink]': '[Blink]', + '[TUIEmoji_Guffaw]': '[Guffaw]', + '[TUIEmoji_KindSmile]': '[KindSmile]', + '[TUIEmoji_Haha]': '[Haha]', + '[TUIEmoji_Cheerful]': '[Cheerful]', + '[TUIEmoji_Speechless]': '[Speechless]', + '[TUIEmoji_Amazed]': '[Amazed]', + '[TUIEmoji_Sorrow]': '[Sorrow]', + '[TUIEmoji_Complacent]': '[Complacent]', + '[TUIEmoji_Silly]': '[Silly]', + '[TUIEmoji_Lustful]': '[Lustful]', + '[TUIEmoji_Giggle]': '[Giggle]', + '[TUIEmoji_Kiss]': '[Kiss]', + '[TUIEmoji_Wail]': '[Wail]', + '[TUIEmoji_TearsLaugh]': '[TearsLaugh]', + '[TUIEmoji_Trapped]': '[Trapped]', + '[TUIEmoji_Mask]': '[Mask]', + '[TUIEmoji_Fear]': '[Fear]', + '[TUIEmoji_BareTeeth]': '[BareTeeth]', + '[TUIEmoji_FlareUp]': '[FlareUp]', + '[TUIEmoji_Yawn]': '[Yawn]', + '[TUIEmoji_Tact]': '[Tact]', + '[TUIEmoji_Stareyes]': '[StarEyes]', + '[TUIEmoji_ShutUp]': '[ShutUp]', + '[TUIEmoji_Sigh]': '[Sigh]', + '[TUIEmoji_Hehe]': '[Hehe]', + '[TUIEmoji_Silent]': '[Silent]', + '[TUIEmoji_Surprised]': '[Surprised]', + '[TUIEmoji_Askance]': '[Askance]]', + '[TUIEmoji_Ok]': '[OK]', + '[TUIEmoji_Shit]': '[Shit]', + '[TUIEmoji_Monster]': '[Monster]', + '[TUIEmoji_Daemon]': '[Daemon]', + '[TUIEmoji_Rage]': '[Rage]', + '[TUIEmoji_Fool]': '[Fool]', + '[TUIEmoji_Pig]': '[Pig]', + '[TUIEmoji_Cow]': '[Cow]', + '[TUIEmoji_Ai]': '[AI]', + '[TUIEmoji_Skull]': '[Skull]', + '[TUIEmoji_Bombs]': '[Bombs]', + '[TUIEmoji_Coffee]': '[Coffee]', + '[TUIEmoji_Cake]': '[Cake]', + '[TUIEmoji_Beer]': '[Beer]', + '[TUIEmoji_Flower]': '[Flower]', + '[TUIEmoji_Watermelon]': '[Watermelon]', + '[TUIEmoji_Rich]': '[Rich]', + '[TUIEmoji_Heart]': '[Heart]', + '[TUIEmoji_Moon]': '[Moon]', + '[TUIEmoji_Sun]': '[Sun]', + '[TUIEmoji_Star]': '[Star]', + '[TUIEmoji_RedPacket]': '[RedPacket]', + '[TUIEmoji_Celebrate]': '[Celebrate]', + '[TUIEmoji_Bless]': '[Bless]', + '[TUIEmoji_Fortune]': '[Fortune]', + '[TUIEmoji_Convinced]': '[Convinced]', + '[TUIEmoji_Prohibit]': '[Prohibit]', + '[TUIEmoji_666]': '[666]', + '[TUIEmoji_857]': '[857]', + '[TUIEmoji_Knife]': '[Knife]', + '[TUIEmoji_Like]': '[Like]', +}; + +export default Emoji; diff --git a/TUIKit/components/TUIChat/emoji-config/locales/zh_cn.ts b/TUIKit/components/TUIChat/emoji-config/locales/zh_cn.ts new file mode 100644 index 0000000..7086a1f --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/locales/zh_cn.ts @@ -0,0 +1,66 @@ +const Emoji: Record = { + '[TUIEmoji_Smile]': '[微笑]', + '[TUIEmoji_Expect]': '[期待]', + '[TUIEmoji_Blink]': '[眨眼]', + '[TUIEmoji_Guffaw]': '[大笑]', + '[TUIEmoji_KindSmile]': '[姨母笑]', + '[TUIEmoji_Haha]': '[哈哈哈]', + '[TUIEmoji_Cheerful]': '[愉快]', + '[TUIEmoji_Speechless]': '[无语]', + '[TUIEmoji_Amazed]': '[惊讶]', + '[TUIEmoji_Sorrow]': '[悲伤]', + '[TUIEmoji_Complacent]': '[得意]', + '[TUIEmoji_Silly]': '[傻了]', + '[TUIEmoji_Lustful]': '[色]', + '[TUIEmoji_Giggle]': '[憨笑]', + '[TUIEmoji_Kiss]': '[亲亲]', + '[TUIEmoji_Wail]': '[大哭]', + '[TUIEmoji_TearsLaugh]': '[哭笑]', + '[TUIEmoji_Trapped]': '[困]', + '[TUIEmoji_Mask]': '[口罩]', + '[TUIEmoji_Fear]': '[恐惧]', + '[TUIEmoji_BareTeeth]': '[龇牙]', + '[TUIEmoji_FlareUp]': '[发怒]', + '[TUIEmoji_Yawn]': '[打哈欠]', + '[TUIEmoji_Tact]': '[机智]', + '[TUIEmoji_Stareyes]': '[星星眼]', + '[TUIEmoji_ShutUp]': '[闭嘴]', + '[TUIEmoji_Sigh]': '[叹气]', + '[TUIEmoji_Hehe]': '[呵呵]', + '[TUIEmoji_Silent]': '[收声]', + '[TUIEmoji_Surprised]': '[惊喜]', + '[TUIEmoji_Askance]': '[白眼]', + '[TUIEmoji_Ok]': '[OK]', + '[TUIEmoji_Shit]': '[便便]', + '[TUIEmoji_Monster]': '[怪兽]', + '[TUIEmoji_Daemon]': '[恶魔]', + '[TUIEmoji_Rage]': '[恶魔怒]', + '[TUIEmoji_Fool]': '[衰]', + '[TUIEmoji_Pig]': '[猪]', + '[TUIEmoji_Cow]': '[牛]', + '[TUIEmoji_Ai]': '[AI]', + '[TUIEmoji_Skull]': '[骷髅]', + '[TUIEmoji_Bombs]': '[炸弹]', + '[TUIEmoji_Coffee]': '[咖啡]', + '[TUIEmoji_Cake]': '[蛋糕]', + '[TUIEmoji_Beer]': '[啤酒]', + '[TUIEmoji_Flower]': '[花]', + '[TUIEmoji_Watermelon]': '[瓜]', + '[TUIEmoji_Rich]': '[壕]', + '[TUIEmoji_Heart]': '[爱心]', + '[TUIEmoji_Moon]': '[月亮]', + '[TUIEmoji_Sun]': '[太阳]', + '[TUIEmoji_Star]': '[星星]', + '[TUIEmoji_RedPacket]': '[红包]', + '[TUIEmoji_Celebrate]': '[庆祝]', + '[TUIEmoji_Bless]': '[福]', + '[TUIEmoji_Fortune]': '[发]', + '[TUIEmoji_Convinced]': '[服]', + '[TUIEmoji_Prohibit]': '[禁]', + '[TUIEmoji_666]': '[666]', + '[TUIEmoji_857]': '[857]', + '[TUIEmoji_Knife]': '[刀]', + '[TUIEmoji_Like]': '[赞]', +}; + +export default Emoji; diff --git a/TUIKit/components/TUIChat/emoji-config/locales/zh_tw.ts b/TUIKit/components/TUIChat/emoji-config/locales/zh_tw.ts new file mode 100644 index 0000000..144009e --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/locales/zh_tw.ts @@ -0,0 +1,66 @@ +const Emoji: Record = { + '[TUIEmoji_Smile]': '[微笑]', + '[TUIEmoji_Expect]': '[期待]', + '[TUIEmoji_Blink]': '[眨眼]', + '[TUIEmoji_Guffaw]': '[大笑]', + '[TUIEmoji_KindSmile]': '[姨母笑]', + '[TUIEmoji_Haha]': '[哈哈哈]', + '[TUIEmoji_Cheerful]': '[愉快]', + '[TUIEmoji_Speechless]': '[無語]', + '[TUIEmoji_Amazed]': '[驚訝]', + '[TUIEmoji_Sorrow]': '[悲傷]', + '[TUIEmoji_Complacent]': '[得意]', + '[TUIEmoji_Silly]': '[傻了]', + '[TUIEmoji_Lustful]': '[色]', + '[TUIEmoji_Giggle]': '[憨笑]', + '[TUIEmoji_Kiss]': '[親親]', + '[TUIEmoji_Wail]': '[大哭]', + '[TUIEmoji_TearsLaugh]': '[哭笑]', + '[TUIEmoji_Trapped]': '[困]', + '[TUIEmoji_Mask]': '[口罩]', + '[TUIEmoji_Fear]': '[恐懼]', + '[TUIEmoji_BareTeeth]': '[齜牙]', + '[TUIEmoji_FlareUp]': '[發怒]', + '[TUIEmoji_Yawn]': '[打哈欠]', + '[TUIEmoji_Tact]': '[機智]', + '[TUIEmoji_Stareyes]': '[星星眼]', + '[TUIEmoji_ShutUp]': '[閉嘴]', + '[TUIEmoji_Sigh]': '[嘆氣]', + '[TUIEmoji_Hehe]': '[呵呵]', + '[TUIEmoji_Silent]': '[收聲]', + '[TUIEmoji_Surprised]': '[驚喜]', + '[TUIEmoji_Askance]': '[白眼]', + '[TUIEmoji_Ok]': '[OK]', + '[TUIEmoji_Shit]': '[便便]', + '[TUIEmoji_Monster]': '[怪獸]', + '[TUIEmoji_Daemon]': '[惡魔]', + '[TUIEmoji_Rage]': '[惡魔怒]', + '[TUIEmoji_Fool]': '[衰]', + '[TUIEmoji_Pig]': '[豬]', + '[TUIEmoji_Cow]': '[牛]', + '[TUIEmoji_Ai]': '[AI]', + '[TUIEmoji_Skull]': '[骷髏]', + '[TUIEmoji_Bombs]': '[炸彈]', + '[TUIEmoji_Coffee]': '[咖啡]', + '[TUIEmoji_Cake]': '[蛋糕]', + '[TUIEmoji_Beer]': '[啤酒]', + '[TUIEmoji_Flower]': '[花]', + '[TUIEmoji_Watermelon]': '[瓜]', + '[TUIEmoji_Rich]': '[壕]', + '[TUIEmoji_Heart]': '[愛心]', + '[TUIEmoji_Moon]': '[月亮]', + '[TUIEmoji_Sun]': '[太陽]', + '[TUIEmoji_Star]': '[星星]', + '[TUIEmoji_RedPacket]': '[紅包]', + '[TUIEmoji_Celebrate]': '[慶祝]', + '[TUIEmoji_Bless]': '[福]', + '[TUIEmoji_Fortune]': '[發]', + '[TUIEmoji_Convinced]': '[服]', + '[TUIEmoji_Prohibit]': '[禁]', + '[TUIEmoji_666]': '[666]', + '[TUIEmoji_857]': '[857]', + '[TUIEmoji_Knife]': '[刀]', + '[TUIEmoji_Like]': '[讚]', +}; + +export default Emoji; diff --git a/TUIKit/components/TUIChat/entry-chat-only.ts b/TUIKit/components/TUIChat/entry-chat-only.ts new file mode 100644 index 0000000..86b8e15 --- /dev/null +++ b/TUIKit/components/TUIChat/entry-chat-only.ts @@ -0,0 +1,35 @@ +import { TUILogin } from '@tencentcloud/tui-core-lite'; +import { TUIConversationService } from '@tencentcloud/chat-uikit-engine-lite'; +// #ifdef MP-WEIXIN +import { TUIChatKit } from '../../index.ts'; +// #endif + +export const initChat = (options: Record) => { + // #ifdef MP-WEIXIN + // uni-app packages the mini program. + // If you call TUIChatKit.init() directly during import, an error will be reported. + // You need to init during the page onLoad. + TUIChatKit.init(); + // #endif + + // When opening TUIChat, the options and options.conversationID parameters carried in the url, + // determine whether to enter the Chat from the [Conversation List] or [Online Communication]. + const { chat } = TUILogin.getContext(); + if (options && options.conversationID && chat?.isReady()) { + const { conversationID } = options; + // verify conversationID + if (!conversationID.startsWith('C2C') && !conversationID.startsWith('GROUP')) { + console.warn('conversationID from options is invalid.'); + return; + } + // open chat + TUIConversationService.switchConversation(conversationID); + } +}; + +export const logout = (flag: boolean) => { + if (flag) { + return TUILogin.logout(); + } + return Promise.resolve(); +}; diff --git a/TUIKit/components/TUIChat/forward/index.vue b/TUIKit/components/TUIChat/forward/index.vue new file mode 100644 index 0000000..1e93751 --- /dev/null +++ b/TUIKit/components/TUIChat/forward/index.vue @@ -0,0 +1,159 @@ + + + diff --git a/TUIKit/components/TUIChat/index.ts b/TUIKit/components/TUIChat/index.ts new file mode 100644 index 0000000..a4f6c17 --- /dev/null +++ b/TUIKit/components/TUIChat/index.ts @@ -0,0 +1,6 @@ +import TUIChat from './index.vue'; +import Server from './server'; + +new Server(); + +export default TUIChat; diff --git a/TUIKit/components/TUIChat/index.vue b/TUIKit/components/TUIChat/index.vue new file mode 100644 index 0000000..51dadba --- /dev/null +++ b/TUIKit/components/TUIChat/index.vue @@ -0,0 +1,309 @@ + + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.ts b/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.ts new file mode 100644 index 0000000..d84f35a --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.ts @@ -0,0 +1,2 @@ +import AlbumUpload from './index.vue'; +export default AlbumUpload; diff --git a/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.vue b/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.vue new file mode 100644 index 0000000..dbd62b6 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/album-upload/index.vue @@ -0,0 +1,41 @@ + + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.ts b/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.ts new file mode 100644 index 0000000..9b497e3 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.ts @@ -0,0 +1,2 @@ +import CameraUpload from './index.vue'; +export default CameraUpload; diff --git a/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.vue b/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.vue new file mode 100644 index 0000000..4d47d90 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/camera-upload/index.vue @@ -0,0 +1,41 @@ + + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.ts b/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.ts new file mode 100644 index 0000000..e574464 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.ts @@ -0,0 +1,2 @@ +import Words from "./index.vue"; +export default Words; diff --git a/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.vue b/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.vue new file mode 100644 index 0000000..255b63f --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/clearHistory/index.vue @@ -0,0 +1,94 @@ + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue new file mode 100644 index 0000000..cf894ca --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue @@ -0,0 +1,186 @@ + + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.ts b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.ts new file mode 100644 index 0000000..33cc740 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.ts @@ -0,0 +1,2 @@ +import EmojiPicker from './index.vue'; +export default EmojiPicker; diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.vue b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.vue new file mode 100644 index 0000000..719f303 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/index.vue @@ -0,0 +1,81 @@ + + + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/h5.scss b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/h5.scss new file mode 100644 index 0000000..552adfc --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/h5.scss @@ -0,0 +1,25 @@ +.emoji-picker-h5 { + width: 100%; + + &-list { + justify-content: space-between; + } + + &-list::after { + content: ""; + display: block; + flex: 1 1 auto; + } + + .send-btn { + width: 50px; + height: 30px; + background-color: #55C06A; + position: absolute; + right: 10px; + font-size: 16px; + color: #fff; + text-align: center; + line-height: 30px; + } +} diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/index.scss b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/index.scss new file mode 100644 index 0000000..618221f --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/index.scss @@ -0,0 +1,4 @@ +@import "../../../../../assets/styles/common"; +@import "./web"; +@import "./h5"; + diff --git a/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/web.scss b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/web.scss new file mode 100644 index 0000000..536b050 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/style/web.scss @@ -0,0 +1,55 @@ +.emoji-picker { + width: 405px; + height: 300px; + display: flex; + flex-direction: column; + + &-list { + flex: 1; + display: flex; + flex-wrap: wrap; + overflow-y: auto; + margin: 2px; + + &::-webkit-scrollbar { + display: none; + } + + &-item { + cursor: pointer; + padding: 5px; + + .emoji { + width: 30px; + height: 30px; + } + + .emoji-big { + width: 70px; + height: 70px; + } + } + } + + &-tab { + display: flex; + align-items: center; + + &-item { + padding: 0 10px; + cursor: pointer; + + .icon { + margin: 10px; + width: 20px; + height: 20px; + + &-big { + margin: 2px 0; + width: 30px; + height: 30px; + } + } + } + } +} diff --git a/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.ts b/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.ts new file mode 100644 index 0000000..f9a4b11 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.ts @@ -0,0 +1,2 @@ +import Evaluate from './index.vue'; +export default Evaluate; diff --git a/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.vue b/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.vue new file mode 100644 index 0000000..53d1b67 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.vue @@ -0,0 +1,209 @@ +