From 12af2a86b23f7ac35cd7285291df04c09fded875 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sat, 28 Aug 2021 21:26:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=96=B5=E8=AF=AD=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E4=B8=8E=E6=B6=88=E6=81=AF=E8=A7=A3=E9=87=8A=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/plugins/README.md | 43 +++++++++++++++ .../com.msgbyte.miaolang/manifest.json | 9 ++++ web/plugins/com.msgbyte.miaolang/package.json | 9 ++++ web/plugins/com.msgbyte.miaolang/src/index.ts | 19 +++++++ web/plugins/com.msgbyte.miaolang/src/trans.ts | 13 +++++ .../com.msgbyte.miaolang/tsconfig.json | 11 ++++ web/plugins/com.msgbyte.miaolang/yarn.lock | 15 ++++++ web/plugins/com.msgbyte.webview/manifest.json | 9 ++++ .../ChatBox/ChatMessageList/Item.tsx | 10 +++- .../useRenderPluginMessageInterpreter.tsx | 52 +++++++++++++++++++ web/src/plugin/common/reg.ts | 12 +++++ 11 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 web/plugins/README.md create mode 100644 web/plugins/com.msgbyte.miaolang/manifest.json create mode 100644 web/plugins/com.msgbyte.miaolang/package.json create mode 100644 web/plugins/com.msgbyte.miaolang/src/index.ts create mode 100644 web/plugins/com.msgbyte.miaolang/src/trans.ts create mode 100644 web/plugins/com.msgbyte.miaolang/tsconfig.json create mode 100644 web/plugins/com.msgbyte.miaolang/yarn.lock create mode 100644 web/plugins/com.msgbyte.webview/manifest.json create mode 100644 web/src/components/ChatBox/ChatMessageList/useRenderPluginMessageInterpreter.tsx diff --git a/web/plugins/README.md b/web/plugins/README.md new file mode 100644 index 00000000..82f30eb8 --- /dev/null +++ b/web/plugins/README.md @@ -0,0 +1,43 @@ +## 如何创建一个插件 + +### 内部插件 + +> 内部插件是指随 `tailchat` 分发而提供的插件 + +在web目录执行: + +```bash +yarn ministar createPlugin +``` + +插件名请准守反域名模式, 如: `com.msgbyte.xxx` + +设置`tsconfig.json`如下: +```json +{ + "compilerOptions": { + "rootDir": "./src", + "baseUrl": "./src", + "esModuleInterop": true, + "jsx": "react", + "paths": { + "@capital/*": ["../../../src/plugin/*"], + } + } +} +``` + +创建一个`manifest.json`文件 + +示例: +```json +{ + "label": "网页面板插件", + "name": "com.msgbyte.webview", + "url": "/plugins/com.msgbyte.webview/index.js", + "version": "0.0.0", + "author": "msgbyte", + "description": "为群组提供创建网页面板的功能", + "requireRestart": false +} +``` diff --git a/web/plugins/com.msgbyte.miaolang/manifest.json b/web/plugins/com.msgbyte.miaolang/manifest.json new file mode 100644 index 00000000..9c9d9b2c --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/manifest.json @@ -0,0 +1,9 @@ +{ + "label": "喵语言", + "name": "com.msgbyte.miaolang", + "url": "/plugins/com.msgbyte.miaolang/index.js", + "version": "0.0.0", + "author": "msgbyte", + "description": "为聊天提供喵语言对话功能", + "requireRestart": true +} diff --git a/web/plugins/com.msgbyte.miaolang/package.json b/web/plugins/com.msgbyte.miaolang/package.json new file mode 100644 index 00000000..74dfb6ba --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/package.json @@ -0,0 +1,9 @@ +{ + "name": "@plugins/com.msgbyte.miaolang", + "main": "src/index.ts", + "version": "0.0.0", + "private": true, + "dependencies": { + "miao-lang": "^1.0.3" + } +} diff --git a/web/plugins/com.msgbyte.miaolang/src/index.ts b/web/plugins/com.msgbyte.miaolang/src/index.ts new file mode 100644 index 00000000..fe724b07 --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/src/index.ts @@ -0,0 +1,19 @@ +import { decode, encode, isMiao } from './trans'; +import { regMessageInterpreter } from '@capital/common'; + +const miao = encode('喵语翻译已加载'); +const human = decode(miao); + +console.log(`${miao}\n${human}`); + +regMessageInterpreter({ + name: '喵语翻译', + explainMessage(message: string) { + // 喵语 -> 人话 + if (!isMiao(message)) { + return null; + } + + return decode(message); + }, +}); diff --git a/web/plugins/com.msgbyte.miaolang/src/trans.ts b/web/plugins/com.msgbyte.miaolang/src/trans.ts new file mode 100644 index 00000000..045cf030 --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/src/trans.ts @@ -0,0 +1,13 @@ +import Miao from 'miao-lang'; + +export function encode(human: string): string { + return Miao.encode(human); +} + +export function decode(miao: string): string { + return Miao.decode(miao); +} + +export function isMiao(input: string): boolean { + return Miao.isMiao(input); +} diff --git a/web/plugins/com.msgbyte.miaolang/tsconfig.json b/web/plugins/com.msgbyte.miaolang/tsconfig.json new file mode 100644 index 00000000..beb3c60f --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "rootDir": "./src", + "baseUrl": "./src", + "esModuleInterop": true, + "jsx": "react", + "paths": { + "@capital/*": ["../../../src/plugin/*"], + } + } +} diff --git a/web/plugins/com.msgbyte.miaolang/yarn.lock b/web/plugins/com.msgbyte.miaolang/yarn.lock new file mode 100644 index 00000000..ac1a4ffb --- /dev/null +++ b/web/plugins/com.msgbyte.miaolang/yarn.lock @@ -0,0 +1,15 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +js-base64@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.1.tgz#555aae398b74694b4037af1f8a5a6209d170efbe" + integrity sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ== + +miao-lang@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/miao-lang/-/miao-lang-1.0.3.tgz#276999788f6eee2b600db66a0d72b3f53bcbd6ab" + integrity sha512-AXxAKfRUSFwvF0RMJ8qkUtUbVHdNqGA71k+4/38ikh2mK1iRoiDueuTannVF+9NqzSXi770GKMuGEFXu/+Ithg== + dependencies: + js-base64 "^3.6.0" diff --git a/web/plugins/com.msgbyte.webview/manifest.json b/web/plugins/com.msgbyte.webview/manifest.json new file mode 100644 index 00000000..83d89b9a --- /dev/null +++ b/web/plugins/com.msgbyte.webview/manifest.json @@ -0,0 +1,9 @@ +{ + "label": "网页面板插件", + "name": "com.msgbyte.webview", + "url": "/plugins/com.msgbyte.webview/index.js", + "version": "0.0.0", + "author": "msgbyte", + "description": "为群组提供创建网页面板的功能", + "requireRestart": false +} diff --git a/web/src/components/ChatBox/ChatMessageList/Item.tsx b/web/src/components/ChatBox/ChatMessageList/Item.tsx index 4034a097..88e43662 100644 --- a/web/src/components/ChatBox/ChatMessageList/Item.tsx +++ b/web/src/components/ChatBox/ChatMessageList/Item.tsx @@ -6,6 +6,7 @@ import { } from 'tailchat-shared'; import { Avatar } from '@/components/Avatar'; import clsx from 'clsx'; +import { useRenderPluginMessageInterpreter } from './useRenderPluginMessageInterpreter'; interface ChatMessageItemProps { showAvatar: boolean; @@ -29,7 +30,7 @@ export const ChatMessageItem: React.FC = React.memo( )} -
+
{showAvatar && (
{userInfo.nickname}
@@ -39,7 +40,12 @@ export const ChatMessageItem: React.FC = React.memo(
)} -
{payload.content}
+
+ {payload.content} + + {/* 解释器按钮 */} + {useRenderPluginMessageInterpreter(payload.content)} +
); diff --git a/web/src/components/ChatBox/ChatMessageList/useRenderPluginMessageInterpreter.tsx b/web/src/components/ChatBox/ChatMessageList/useRenderPluginMessageInterpreter.tsx new file mode 100644 index 00000000..c7443919 --- /dev/null +++ b/web/src/components/ChatBox/ChatMessageList/useRenderPluginMessageInterpreter.tsx @@ -0,0 +1,52 @@ +import { messageInterpreter } from '@/plugin/common'; +import { Icon } from '@iconify/react'; +import { Popover } from 'antd'; +import React from 'react'; +import { useMemo } from 'react'; +import { t } from 'tailchat-shared'; + +export function useRenderPluginMessageInterpreter(message: string) { + const availableInterpreter = useMemo( + () => + messageInterpreter + .map(({ name, explainMessage }) => ({ + name, + render: explainMessage(message), + })) + .filter(({ render }) => render !== null), + [message] + ); + + if (availableInterpreter.length === 0) { + return null; + } + + return ( + + + {availableInterpreter.map((ai, i) => ( +

+ {ai.name && ( + + {t('来自')} {ai.name} :{' '} + + )} + {ai.render} +

+ ))} + + } + trigger="click" + > + +
+
+ ); +} diff --git a/web/src/plugin/common/reg.ts b/web/src/plugin/common/reg.ts index b751a381..57d174a5 100644 --- a/web/src/plugin/common/reg.ts +++ b/web/src/plugin/common/reg.ts @@ -32,3 +32,15 @@ export interface PluginGroupPanel { } export const [pluginGroupPanel, regGroupPanel] = buildRegList(); + +export interface PluginMessageInterpreter { + name?: string; + explainMessage: (message: string) => React.ReactElement | null; +} + +/** + * 消息解释器 + * 即用于解释消息内容, 并把结果渲染到消息下面 + */ +export const [messageInterpreter, regMessageInterpreter] = + buildRegList();