diff --git a/.gitignore b/.gitignore index 385f0a20..ae26e741 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ # OSX .DS_Store -/TUIKit/ /node_modules/ #Intellij idea .idea/ diff --git a/TUIKit/CHANGELOG.md b/TUIKit/CHANGELOG.md new file mode 100644 index 00000000..83f74103 --- /dev/null +++ b/TUIKit/CHANGELOG.md @@ -0,0 +1,204 @@ +## [2.4.1] (2025-01-22) + +### Fix +- 修复 EmojiPicker 表情选择面板点击无响应问题。 + +## [2.4.0] (2025-01-16) + +### Fix +- 修复 sendMessage 时携带的默认信息,支持用户自定义配置。 + +## [2.3.8] (2025-01-10) + +### Features +- 支持文本消息 url 高亮跳转 + +## Fix +- 修复自定义大表情失效问题 +- 修复 login 时好友列表数据未重置问题 + +## [2.3.3] (2024-10-28) + +### Features +- 支持群组禁言后发送消息错误提示国际化 + +## Fix +- 修复集成 CallKit 点击通话按钮偶现无响应问题 + +## [2.3.2] (2024-10-28) + +## Fix + +- 修复 H5 环境下群管理页面返回直接回到会话列表页面的问题 +- 移除 H5 环境下群聊页面出现App环境下的菜单按钮 + +## [2.3.1] (2024-10-25) + +## Fix +- 修复撤回消息中撤回人为空问题 +- 修复 TUIContact 修改好友备注后列表显示未更新问题 +- 优化 uniapp 打包 app 群管理入口至导航栏 +- 优化 uniapp 打包 app 软键盘弹出体验 + +## [2.3.0] (2024-10-21) + +## Fix +- 修复集成音视频通话 InputToolbar 点击按钮无响应问题 + +## [2.2.9] (2024-10-17) + +## Fix +- 修复 Callkit 融合被叫超时无应答英文词条翻译错误问题 + +## [2.2.8] (2024-09-24) + +### Features +- 支持繁体中文语言 +- 支持新增自定义语言类型 + +## [2.2.7] (2024-09-13) + +### Features +- 优化 C2C 会话音视频通话信令上屏(对齐微信体验) + +## [2.2.6] (2024-09-06) + +### Features +- Work 类型群组支持普通群成员修改群名称、群公告信息 + +## [2.2.3] (2024-07-05) + +### Features +- 支持会话草稿 +- 语音消息使用红点提示是否播放 + +### Fix +- 修复邀请加入群聊选人组件未过滤已有群成员问题 +- 修复 TUISearch 搜索文本消息出现 [系统消息] 前缀问题 +- 修复 TUIGroup 中 group-profile\group-name在 vue3 环境下 UI 崩坏的问题 +- 修复 Overlay 在构建微信小程序时点击事件无法触发的问题 +- 修复消息引用语音但展示为"聊天记录"的问题 +- 修复 Callkit 在 H5 环境下布局只有半屏的问题 + +## [2.2.0] (2024-06-17) + +### Features +- 支持消息多选、消息逐条转发、消息合并转发 +- 优化 TUIKit 集成流程 +- 支持表情包自定义 +- uniapp callkit 支持 offlinePushInfo +- uniapp callkit 支持自定义铃音 +- 被引用消息撤回时隐藏原始消息内容并提醒已撤回 + +## [2.1.3] (2024-05-17) + +### Features +- TUIKit 适配 uniapp cli +- 点击空白区域时收起小表情面板和工具栏 +- callkit 提供音视频通话中途加人能力 不包括app平台 + +### Fix +- 修复视频一定概率无法播放的问题 +- 修复消息引用的视觉左侧未对齐的问题 + +## [2.1.1] (2024-04-26) + +### Features +- 支持语音转文字 +- 文本消息转翻译兼容小表情上屏,兼容提及所有人 + +### Fix +- 优化已读回执详情列表超长昵称的显示效果 +- 解决转发消息已读回执失效的问题 +- 解决加没有群申请时额外请求用户信息的问题 + +## [2.1.0] (2024-04-12) + +### Features +- 新增消息翻译功能 + +### Fix +- uniapp 修复选人组件搜索失效问题 + +## [2.0.9] (2024-03-29) + +### Features +- ScrollButton 支持未读新消息提示 +- 群未决申请展示优化 + +### Update +- 下线本地审核相关入口 + +### Fix +- 修复 nick 过长样式溢出问题 + +## [2.0.8] (2024-03-15) + +### Fix +- 修复已知问题,提升稳定性 + +## [2.0.7] (2024-03-15) + +### Features +- 会话列表菜单出现位置跟随手指 + +### Fix +- 修复一定概率下图片无法预览的问题 + +## [2.0.6] (2024-03-01) + +### Features + +- 升级 universal api 引入方式 +- 支持 TUISearch 消息云端搜索 + +## [2.0.5] (2024-02-04) + +### Features + +- 聊天界面更新黄脸小表情 +- 添加音频播放动画 + +### Fix + +- 语音场景优化 修复了语音播放相关的体验问题 + +## [2.0.4] (2024-01-19) + +### Features + +- 支持文本消息复制 + +### Fix + +- 修复 uniapp 打包 APP、小程序 语音首次发送失败问题 + +## [2.0.3] (2024-01-12) + +### Features + +- TUIContact 关系链支持用户在线状态。 +- TUIContact 中获取客服列表的时机调整为 Engine 设置商业化能力位之后。 + +### Fix + +- 修复已知问题,提升稳定性 + +## [2.0.2] (2024-01-05) + +### Fix + +- 修复已知问题,提升稳定性 + +## [2.0.0] (2023-12-21) + +### Features + +- 全面支持 uniapp Vue2 & uniapp Vue3,包括以下主体功能: + - TUIChat: 负责消息界面展示,包括多类型消息收发,消息引用/删除/撤回/转发、查询消息已读回执详情等功能。 + - TUIConversation: 负责会话列表的展示和编辑,包括会话置顶、会话消息免打扰、会话删除等功能. + - TUIGroup: 负责群聊的创建以及群资料、群成员、群组权限、群公告、群禁言的管理。 + - TUIContact: 负责联系人与群组展示,添加好友,移入黑名单,好友备注,信息展示等功能。 +- 同时,我们还提供了功能丰富的插件系统: + - TUICustomerService: 在线客服插件,支持灵活的路由排队、客服接待、智能机器人功能,配合功能丰富的管理端与数据分析能力,支持客服多终端办公,免费试用请点击 https://cloud.tencent.com/document/product/269/92648#ae4e3f5c-94db-4df3-8a49-65d23ce417b8 开通。 + - TUICallKit: 音视频通话 UI 组件,支持两人或多人进行音视频通话,覆盖游戏社交、在线客服、视频客服、在线问诊、保险咨询等场景,免费试用请点击 https://cloud.tencent.com/document/product/269/79861#step1 开通。 diff --git a/TUIKit/README.md b/TUIKit/README.md new file mode 100644 index 00000000..0e5b58d9 --- /dev/null +++ b/TUIKit/README.md @@ -0,0 +1,56 @@ +## 关于 chat-uikit-uniapp + +chat-uikit-uniapp (vue2 / vue3)是基于腾讯云 Chat SDK 的一款 uniapp UI 组件库,它提供了一些通用的 UI 组件,包含会话、聊天、群组、关系链等功能。基于这些精心设计的 UI 组件,您可以快速构建优雅的、可靠的、可扩展的 Chat 应用。 +chat-uikit-uniapp 界面效果如下图所示: +![](https://qcloudimg.tencent-cloud.cn/raw/2f16b1be0591a325250f9066af898036.png) + +> 为尊重表情设计版权,IM Demo/TUIKit 工程中不包含大表情元素切图,正式上线商用前请您替换为自己设计或拥有版权的其他表情包。默认的小黄脸表情包版权归腾讯云所有,可有偿授权使用,如您希望获得授权可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=14&data_title=%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1%20IM&step=1) 联系我们。 + +## chat-uikit-uniapp 支持平台 + +- Android +- iOS +- 微信小程序 +- H5 + +## 含 UI 集成 TUILogin 使用说明 + +``` javascript +// 引入 TUILogin 模块 +import { TUILogin } from '@tencentcloud/tui-core'; +``` +初始化登录参数 options 配置说明: +| 参数 | 类型 | 含义 | +| --- | --- | --- | +| SDKAppID | number | 云通信应用的 SDKAppID,必填 | +| userID | string | 用户 ID,必填 | +| userSig |string | 用户登录密钥,必填 | +| TIMPush | any | 推送插件实例,uniapp 打包 app 时集成推送插件可用 | +| pushConfig | object | 推送插件配置信息,uniapp 打包 app 时集成推送插件可用 | +| useUploadPlugin | boolean | 是否使用上传插件, 默认 false | +| proxyServer | string | WebSocket 服务器代理地址 | +| fileUploadProxy | string | 图片、视频、文件上传代理地址 | +| fileDownloadProxy | string | 图片、视频、文件下载代理地址 | +| framework | string \| undefined | 使用的 UI 框架,可选值: vue2、vue3、undefined,必填 | + +``` javascript +// 初始化登录 +TUILogin.login(options); +``` + +``` javascript +// 登出 +TUILogin.logout(); +``` + +``` javascript +// 设置 Chat SDK 日志输出级别 +TUILogin.setLogLevel(0); // 0:普通日志级别 1:release 级别日志 2:告警级别 3:错误级别 4:无日志级别 +``` + +``` javascript +// 获取 Chat SDK 实例 +const { chat } = TUILogin.getContext(); +``` + +## 【源码集成】[请参考 TUIKit 集成文档](https://cloud.tencent.com/document/product/269/64507) diff --git a/TUIKit/adapter-vue.ts b/TUIKit/adapter-vue.ts new file mode 100644 index 00000000..f1d94542 --- /dev/null +++ b/TUIKit/adapter-vue.ts @@ -0,0 +1,14 @@ +let vueVersion: number; +let framework = 'vue2'; +// #ifndef VUE3 +export * from '@vue/composition-api'; +vueVersion = 2; +// #endif + +// #ifdef VUE3 +export * from 'vue'; +vueVersion = 3; +framework = 'vue3'; +// #endif +console.warn(`[adapter-vue]: vue version is ${vueVersion}`); +export { vueVersion, framework }; diff --git a/TUIKit/assets/icon/add-circle.svg b/TUIKit/assets/icon/add-circle.svg new file mode 100644 index 00000000..aa908005 --- /dev/null +++ b/TUIKit/assets/icon/add-circle.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TUIKit/assets/icon/add.svg b/TUIKit/assets/icon/add.svg new file mode 100644 index 00000000..f154f346 --- /dev/null +++ b/TUIKit/assets/icon/add.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/at.svg b/TUIKit/assets/icon/at.svg new file mode 100644 index 00000000..e26825a4 --- /dev/null +++ b/TUIKit/assets/icon/at.svg @@ -0,0 +1,12 @@ + + + 画板 + + + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/audio.svg b/TUIKit/assets/icon/audio.svg new file mode 100644 index 00000000..deacedee --- /dev/null +++ b/TUIKit/assets/icon/audio.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/TUIKit/assets/icon/back.svg b/TUIKit/assets/icon/back.svg new file mode 100644 index 00000000..0af55aaf --- /dev/null +++ b/TUIKit/assets/icon/back.svg @@ -0,0 +1,16 @@ + + + ic_back_white + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/call-video.svg b/TUIKit/assets/icon/call-video.svg new file mode 100644 index 00000000..dc76641b --- /dev/null +++ b/TUIKit/assets/icon/call-video.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/call-voice.svg b/TUIKit/assets/icon/call-voice.svg new file mode 100644 index 00000000..4793fcf5 --- /dev/null +++ b/TUIKit/assets/icon/call-voice.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/call.png b/TUIKit/assets/icon/call.png new file mode 100644 index 00000000..d8d86fe7 Binary files /dev/null and b/TUIKit/assets/icon/call.png differ diff --git a/TUIKit/assets/icon/camera-uni.png b/TUIKit/assets/icon/camera-uni.png new file mode 100644 index 00000000..5596ae26 Binary files /dev/null and b/TUIKit/assets/icon/camera-uni.png differ diff --git a/TUIKit/assets/icon/cancel.svg b/TUIKit/assets/icon/cancel.svg new file mode 100644 index 00000000..1cf848b4 --- /dev/null +++ b/TUIKit/assets/icon/cancel.svg @@ -0,0 +1,23 @@ + + + 清除 + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/check-sm.svg b/TUIKit/assets/icon/check-sm.svg new file mode 100644 index 00000000..69a5e1c8 --- /dev/null +++ b/TUIKit/assets/icon/check-sm.svg @@ -0,0 +1,3 @@ + + + diff --git a/TUIKit/assets/icon/close-dark.svg b/TUIKit/assets/icon/close-dark.svg new file mode 100644 index 00000000..cfc8bc05 --- /dev/null +++ b/TUIKit/assets/icon/close-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/TUIKit/assets/icon/close-image.png b/TUIKit/assets/icon/close-image.png new file mode 100644 index 00000000..d6cc4349 Binary files /dev/null and b/TUIKit/assets/icon/close-image.png differ diff --git a/TUIKit/assets/icon/convertText_en.svg b/TUIKit/assets/icon/convertText_en.svg new file mode 100644 index 00000000..6a8dd655 --- /dev/null +++ b/TUIKit/assets/icon/convertText_en.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TUIKit/assets/icon/convertText_zh.svg b/TUIKit/assets/icon/convertText_zh.svg new file mode 100644 index 00000000..ef2c6434 --- /dev/null +++ b/TUIKit/assets/icon/convertText_zh.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/TUIKit/assets/icon/d-left-arrow.svg b/TUIKit/assets/icon/d-left-arrow.svg new file mode 100644 index 00000000..24d57594 --- /dev/null +++ b/TUIKit/assets/icon/d-left-arrow.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/d-right-arrow.svg b/TUIKit/assets/icon/d-right-arrow.svg new file mode 100644 index 00000000..6fca7c5c --- /dev/null +++ b/TUIKit/assets/icon/d-right-arrow.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/del-icon.svg b/TUIKit/assets/icon/del-icon.svg new file mode 100644 index 00000000..b2832c0f --- /dev/null +++ b/TUIKit/assets/icon/del-icon.svg @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/double-arrow.svg b/TUIKit/assets/icon/double-arrow.svg new file mode 100644 index 00000000..0496fda4 --- /dev/null +++ b/TUIKit/assets/icon/double-arrow.svg @@ -0,0 +1 @@ + diff --git a/TUIKit/assets/icon/down-icon.svg b/TUIKit/assets/icon/down-icon.svg new file mode 100644 index 00000000..a921e8ea --- /dev/null +++ b/TUIKit/assets/icon/down-icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/downaload-image.png b/TUIKit/assets/icon/downaload-image.png new file mode 100644 index 00000000..498d63af Binary files /dev/null and b/TUIKit/assets/icon/downaload-image.png differ diff --git a/TUIKit/assets/icon/download.svg b/TUIKit/assets/icon/download.svg new file mode 100644 index 00000000..9d49c854 --- /dev/null +++ b/TUIKit/assets/icon/download.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/edit.svg b/TUIKit/assets/icon/edit.svg new file mode 100644 index 00000000..2ad307eb --- /dev/null +++ b/TUIKit/assets/icon/edit.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/evalute-dark.svg b/TUIKit/assets/icon/evalute-dark.svg new file mode 100644 index 00000000..b9833be7 --- /dev/null +++ b/TUIKit/assets/icon/evalute-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/TUIKit/assets/icon/evalute-light.svg b/TUIKit/assets/icon/evalute-light.svg new file mode 100644 index 00000000..7cd651b8 --- /dev/null +++ b/TUIKit/assets/icon/evalute-light.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/face-dark.svg b/TUIKit/assets/icon/face-dark.svg new file mode 100644 index 00000000..fcbe3adf --- /dev/null +++ b/TUIKit/assets/icon/face-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TUIKit/assets/icon/face-light.svg b/TUIKit/assets/icon/face-light.svg new file mode 100644 index 00000000..98bf5631 --- /dev/null +++ b/TUIKit/assets/icon/face-light.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/face-uni.png b/TUIKit/assets/icon/face-uni.png new file mode 100644 index 00000000..93214877 Binary files /dev/null and b/TUIKit/assets/icon/face-uni.png differ diff --git a/TUIKit/assets/icon/file-dark.svg b/TUIKit/assets/icon/file-dark.svg new file mode 100644 index 00000000..c5d07730 --- /dev/null +++ b/TUIKit/assets/icon/file-dark.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/TUIKit/assets/icon/file-light.svg b/TUIKit/assets/icon/file-light.svg new file mode 100644 index 00000000..a3acf0c8 --- /dev/null +++ b/TUIKit/assets/icon/file-light.svg @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/forward-each.svg b/TUIKit/assets/icon/forward-each.svg new file mode 100644 index 00000000..41599b42 --- /dev/null +++ b/TUIKit/assets/icon/forward-each.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/TUIKit/assets/icon/forward-merge.svg b/TUIKit/assets/icon/forward-merge.svg new file mode 100644 index 00000000..7a8588a2 --- /dev/null +++ b/TUIKit/assets/icon/forward-merge.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/TUIKit/assets/icon/icon-arrow-left.svg b/TUIKit/assets/icon/icon-arrow-left.svg new file mode 100644 index 00000000..97d4c986 --- /dev/null +++ b/TUIKit/assets/icon/icon-arrow-left.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/icon-c2c.svg b/TUIKit/assets/icon/icon-c2c.svg new file mode 100644 index 00000000..e33ef15d --- /dev/null +++ b/TUIKit/assets/icon/icon-c2c.svg @@ -0,0 +1,36 @@ + + + 编组 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/icon-close.svg b/TUIKit/assets/icon/icon-close.svg new file mode 100644 index 00000000..f5f3e045 --- /dev/null +++ b/TUIKit/assets/icon/icon-close.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/image-dark.svg b/TUIKit/assets/icon/image-dark.svg new file mode 100644 index 00000000..6a122ae7 --- /dev/null +++ b/TUIKit/assets/icon/image-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/image-light.svg b/TUIKit/assets/icon/image-light.svg new file mode 100644 index 00000000..1088ed6d --- /dev/null +++ b/TUIKit/assets/icon/image-light.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/image-uni.png b/TUIKit/assets/icon/image-uni.png new file mode 100644 index 00000000..7d12d843 Binary files /dev/null and b/TUIKit/assets/icon/image-uni.png differ diff --git a/TUIKit/assets/icon/input-close.svg b/TUIKit/assets/icon/input-close.svg new file mode 100644 index 00000000..b224ddd4 --- /dev/null +++ b/TUIKit/assets/icon/input-close.svg @@ -0,0 +1,3 @@ + + + diff --git a/TUIKit/assets/icon/left-arrow.svg b/TUIKit/assets/icon/left-arrow.svg new file mode 100644 index 00000000..2be419f0 --- /dev/null +++ b/TUIKit/assets/icon/left-arrow.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/loading.gif b/TUIKit/assets/icon/loading.gif new file mode 100644 index 00000000..be7c806e Binary files /dev/null and b/TUIKit/assets/icon/loading.gif differ diff --git a/TUIKit/assets/icon/loading.png b/TUIKit/assets/icon/loading.png new file mode 100644 index 00000000..6adfca7a Binary files /dev/null and b/TUIKit/assets/icon/loading.png differ diff --git a/TUIKit/assets/icon/minus.svg b/TUIKit/assets/icon/minus.svg new file mode 100644 index 00000000..b92ab01d --- /dev/null +++ b/TUIKit/assets/icon/minus.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/more-uni.png b/TUIKit/assets/icon/more-uni.png new file mode 100644 index 00000000..8376db26 Binary files /dev/null and b/TUIKit/assets/icon/more-uni.png differ diff --git a/TUIKit/assets/icon/more.png b/TUIKit/assets/icon/more.png new file mode 100644 index 00000000..d91bb0a9 Binary files /dev/null and b/TUIKit/assets/icon/more.png differ diff --git a/TUIKit/assets/icon/msg-audio.svg b/TUIKit/assets/icon/msg-audio.svg new file mode 100644 index 00000000..f2315fd4 --- /dev/null +++ b/TUIKit/assets/icon/msg-audio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TUIKit/assets/icon/msg-copy.svg b/TUIKit/assets/icon/msg-copy.svg new file mode 100644 index 00000000..a5ed5890 --- /dev/null +++ b/TUIKit/assets/icon/msg-copy.svg @@ -0,0 +1,30 @@ + + + 编组 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/msg-del.svg b/TUIKit/assets/icon/msg-del.svg new file mode 100644 index 00000000..2d01337f --- /dev/null +++ b/TUIKit/assets/icon/msg-del.svg @@ -0,0 +1,33 @@ + + + 矩形 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/msg-forward.svg b/TUIKit/assets/icon/msg-forward.svg new file mode 100644 index 00000000..172bfb5e --- /dev/null +++ b/TUIKit/assets/icon/msg-forward.svg @@ -0,0 +1,31 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/msg-quote.svg b/TUIKit/assets/icon/msg-quote.svg new file mode 100644 index 00000000..d5332710 --- /dev/null +++ b/TUIKit/assets/icon/msg-quote.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/TUIKit/assets/icon/msg-revoke.svg b/TUIKit/assets/icon/msg-revoke.svg new file mode 100644 index 00000000..d3494f7f --- /dev/null +++ b/TUIKit/assets/icon/msg-revoke.svg @@ -0,0 +1,29 @@ + + + 矩形 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/multiple-select.svg b/TUIKit/assets/icon/multiple-select.svg new file mode 100644 index 00000000..d4da3c57 --- /dev/null +++ b/TUIKit/assets/icon/multiple-select.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/TUIKit/assets/icon/mute.svg b/TUIKit/assets/icon/mute.svg new file mode 100644 index 00000000..59a5f074 --- /dev/null +++ b/TUIKit/assets/icon/mute.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/TUIKit/assets/icon/plus.svg b/TUIKit/assets/icon/plus.svg new file mode 100644 index 00000000..2ccfad2a --- /dev/null +++ b/TUIKit/assets/icon/plus.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/radio.svg b/TUIKit/assets/icon/radio.svg new file mode 100644 index 00000000..bb4f31b8 --- /dev/null +++ b/TUIKit/assets/icon/radio.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/TUIKit/assets/icon/right-arrow.svg b/TUIKit/assets/icon/right-arrow.svg new file mode 100644 index 00000000..3dc5700b --- /dev/null +++ b/TUIKit/assets/icon/right-arrow.svg @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/right-icon.svg b/TUIKit/assets/icon/right-icon.svg new file mode 100644 index 00000000..c90c2fd1 --- /dev/null +++ b/TUIKit/assets/icon/right-icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/rotate-left.svg b/TUIKit/assets/icon/rotate-left.svg new file mode 100644 index 00000000..1a3c875a --- /dev/null +++ b/TUIKit/assets/icon/rotate-left.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/rotate-right.svg b/TUIKit/assets/icon/rotate-right.svg new file mode 100644 index 00000000..7ab04abd --- /dev/null +++ b/TUIKit/assets/icon/rotate-right.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/search-default.svg b/TUIKit/assets/icon/search-default.svg new file mode 100644 index 00000000..16607cba --- /dev/null +++ b/TUIKit/assets/icon/search-default.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/search-more.svg b/TUIKit/assets/icon/search-more.svg new file mode 100644 index 00000000..af3e11ce --- /dev/null +++ b/TUIKit/assets/icon/search-more.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TUIKit/assets/icon/search.svg b/TUIKit/assets/icon/search.svg new file mode 100644 index 00000000..d64b94f7 --- /dev/null +++ b/TUIKit/assets/icon/search.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/TUIKit/assets/icon/selected.svg b/TUIKit/assets/icon/selected.svg new file mode 100644 index 00000000..7fd5bd31 --- /dev/null +++ b/TUIKit/assets/icon/selected.svg @@ -0,0 +1,27 @@ + + + 编组 14 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/setting.svg b/TUIKit/assets/icon/setting.svg new file mode 100644 index 00000000..ebda9dc3 --- /dev/null +++ b/TUIKit/assets/icon/setting.svg @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/star-light.png b/TUIKit/assets/icon/star-light.png new file mode 100644 index 00000000..77c9e32b Binary files /dev/null and b/TUIKit/assets/icon/star-light.png differ diff --git a/TUIKit/assets/icon/star.png b/TUIKit/assets/icon/star.png new file mode 100644 index 00000000..821c83ff Binary files /dev/null and b/TUIKit/assets/icon/star.png differ diff --git a/TUIKit/assets/icon/start-group.svg b/TUIKit/assets/icon/start-group.svg new file mode 100644 index 00000000..6fd02f85 --- /dev/null +++ b/TUIKit/assets/icon/start-group.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/translate.svg b/TUIKit/assets/icon/translate.svg new file mode 100644 index 00000000..8b7ae249 --- /dev/null +++ b/TUIKit/assets/icon/translate.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/TUIKit/assets/icon/video-dark.svg b/TUIKit/assets/icon/video-dark.svg new file mode 100644 index 00000000..1828560c --- /dev/null +++ b/TUIKit/assets/icon/video-dark.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/TUIKit/assets/icon/video-light.svg b/TUIKit/assets/icon/video-light.svg new file mode 100644 index 00000000..d9915101 --- /dev/null +++ b/TUIKit/assets/icon/video-light.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/video-play.png b/TUIKit/assets/icon/video-play.png new file mode 100644 index 00000000..15957a98 Binary files /dev/null and b/TUIKit/assets/icon/video-play.png differ diff --git a/TUIKit/assets/icon/video-uni.png b/TUIKit/assets/icon/video-uni.png new file mode 100644 index 00000000..2cfe4338 Binary files /dev/null and b/TUIKit/assets/icon/video-uni.png differ diff --git a/TUIKit/assets/icon/words-dark.svg b/TUIKit/assets/icon/words-dark.svg new file mode 100644 index 00000000..c8f6c89e --- /dev/null +++ b/TUIKit/assets/icon/words-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/TUIKit/assets/icon/words-light.svg b/TUIKit/assets/icon/words-light.svg new file mode 100644 index 00000000..934bcdae --- /dev/null +++ b/TUIKit/assets/icon/words-light.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/zoom-in.svg b/TUIKit/assets/icon/zoom-in.svg new file mode 100644 index 00000000..d861ab70 --- /dev/null +++ b/TUIKit/assets/icon/zoom-in.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/icon/zoom-out.svg b/TUIKit/assets/icon/zoom-out.svg new file mode 100644 index 00000000..890cf9fb --- /dev/null +++ b/TUIKit/assets/icon/zoom-out.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/TUIKit/assets/styles/sample.scss b/TUIKit/assets/styles/sample.scss new file mode 100644 index 00000000..8a110b02 --- /dev/null +++ b/TUIKit/assets/styles/sample.scss @@ -0,0 +1,99 @@ +/* stylelint-disable */ +.TUIKit { + display: flex; + width: 100vw; + height: 100vh; + overflow: hidden; + text-align: left; + .TUIKit-navbar { + background: #e8e8e9; + overflow: hidden; + .TUIKit-navbar-item { + padding: 10px; + color: #147aff; + font-weight: 500; + cursor: pointer; + } + .TUIKit-navbar-item-active { + background: #dddddd; + } + } + .TUIKit-main-container { + flex: 1; + display: flex; + overflow: hidden; + .TUIKit-main { + flex: 1; + display: flex; + .TUIKit-main-aside { + min-width: 285px; + flex: 0 0 24%; + border-right: 1px solid #f4f5f9; + } + .TUIKit-main-main { + flex: 1; + display: flex; + .chat{ + flex: 1; + } + .chat-aside { + position: absolute; + top: 50px; + right: 0; + box-sizing: border-box; + max-width: 360px; + max-height: calc(100% - 50px); + border-radius: 8px 0 0 8px; + z-index: 9999; + } + } + } + .callkit-container { + position: fixed; + left: calc(50% - 25rem); + top: calc(50% - 18rem); + width: 50rem; + height: 36rem; + } + .callkit-container.miniMized { + left: auto; + right: 10px; + top: 70px; + background: transparent; + } + } +} +.TUIKit-h5 { + display: flex; + flex-direction: column-reverse; + .TUIKit-navbar { + display: flex; + flex-direction: row; + .TUIKit-navbar-item { + flex: 1; + text-align: center; + cursor: none; + } + } + .TUIKit-main-container { + flex: 1; + .TUIKit-main { + .TUIKit-main-aside { + flex: 1; + } + .TUIKit-main-main { + .chat-popup { + position: absolute; + max-width: 100%; + max-height: 100%; + } + } + } + .callkit-container { + left: 0; + top: 0; + width: 100%; + height: 100%; + } + } +} diff --git a/TUIKit/components/TUIChat/chat-header/index.vue b/TUIKit/components/TUIChat/chat-header/index.vue new file mode 100644 index 00000000..b64b3373 --- /dev/null +++ b/TUIKit/components/TUIChat/chat-header/index.vue @@ -0,0 +1,91 @@ + + + \ No newline at end of file diff --git a/TUIKit/components/TUIChat/config.ts b/TUIKit/components/TUIChat/config.ts new file mode 100644 index 00000000..ed99f3d6 --- /dev/null +++ b/TUIKit/components/TUIChat/config.ts @@ -0,0 +1,83 @@ +class TUIChatConfig { + static instance: TUIChatConfig; + private chatType: string; + private features: Record; + private theme: string; + constructor() { + this.chatType = ''; + this.features = { + 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, + InputEvaluation: true, + InputQuickReplies: true, + InputMention: true, + MessageSearch: true, + ReadStatus: true, + }; + 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; + } + + 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; + } +} + +const ChatConfig = TUIChatConfig.getInstance(); +const hideTUIChatFeatures = ChatConfig.hideTUIChatFeatures.bind(ChatConfig); + +export { + hideTUIChatFeatures, +}; + +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 00000000..d6501df1 --- /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 00000000..e90d1af9 --- /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 00000000..c6ee4dc2 --- /dev/null +++ b/TUIKit/components/TUIChat/emoji-config/index.ts @@ -0,0 +1,140 @@ +import { TUITranslateService } from '@tencentcloud/chat-uikit-engine'; +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 00000000..baa4fd11 --- /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 00000000..7086a1f1 --- /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 00000000..144009ea --- /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 00000000..6a2188ce --- /dev/null +++ b/TUIKit/components/TUIChat/entry-chat-only.ts @@ -0,0 +1,35 @@ +import { TUILogin } from '@tencentcloud/tui-core'; +import { TUIConversationService } from '@tencentcloud/chat-uikit-engine'; +// #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 00000000..4b87813d --- /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 00000000..a4f6c17f --- /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/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 00000000..faf192d3 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue @@ -0,0 +1,185 @@ + + + + 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 00000000..33cc7405 --- /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 00000000..3066bc85 --- /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 00000000..552adfca --- /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 00000000..618221ff --- /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 00000000..536b0500 --- /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 00000000..f9a4b117 --- /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 00000000..83e41fa6 --- /dev/null +++ b/TUIKit/components/TUIChat/message-input-toolbar/evaluate/index.vue @@ -0,0 +1,211 @@ +