From fd8595396744807cf69345cfe5245f7ead5c01d4 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 29 Sep 2022 18:04:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20topic=20=E5=9F=BA=E6=9C=AC=E7=95=8C?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 并优化了tailchat.d.ts 类型声明 --- client/web/package.json | 1 - .../modals/GroupPanel/useGroupPanelFields.tsx | 2 +- client/web/tailchat.d.ts | 26 +- pnpm-lock.yaml | 14 +- server/plugins/com.msgbyte.topic/package.json | 4 +- .../plugins/com.msgbyte.topic/package.json | 6 +- .../src/components/TopicCard.less | 44 +++ .../src/components/TopicCard.tsx | 33 ++ .../src/group/GroupTopicPanelRender.less | 5 + .../src/group/GroupTopicPanelRender.tsx | 16 + .../plugins/com.msgbyte.topic/src/index.tsx | 12 +- .../com.msgbyte.topic/src/translate.ts | 5 + .../com.msgbyte.topic/types/tailchat.d.ts | 306 +++++++++++++++++- 13 files changed, 459 insertions(+), 15 deletions(-) create mode 100644 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.less create mode 100644 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.tsx create mode 100644 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.less create mode 100644 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx create mode 100644 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts diff --git a/client/web/package.json b/client/web/package.json index ce1a3542..ecbaad45 100644 --- a/client/web/package.json +++ b/client/web/package.json @@ -20,7 +20,6 @@ "plugins:new": "ministar createPlugin", "plugins:all": "ministar buildPlugin all", "plugins:watch": "ministar watchPlugin all", - "plugins:declaration": "cross-env TS_NODE_PROJECT='tsconfig.node.json' ts-node ./scripts/plugin-declaration.ts", "plugins:declaration:generate": "cross-env TS_NODE_PROJECT='tsconfig.node.json' ts-node ./scripts/generate-plugin-declaration.typescript.ts" }, "dependencies": { diff --git a/client/web/src/components/modals/GroupPanel/useGroupPanelFields.tsx b/client/web/src/components/modals/GroupPanel/useGroupPanelFields.tsx index 227ebde1..03e60dbe 100644 --- a/client/web/src/components/modals/GroupPanel/useGroupPanelFields.tsx +++ b/client/web/src/components/modals/GroupPanel/useGroupPanelFields.tsx @@ -87,7 +87,7 @@ export function useGroupPanelFields( // 需要从插件信息中获取额外的字段 const panelInfo = findPluginPanelInfoByName(currentValues.type); if (panelInfo) { - return [...baseFields, ...panelInfo.extraFormMeta]; + return [...baseFields, ...(panelInfo.extraFormMeta ?? [])]; } } diff --git a/client/web/tailchat.d.ts b/client/web/tailchat.d.ts index d2a277b3..2babb196 100644 --- a/client/web/tailchat.d.ts +++ b/client/web/tailchat.d.ts @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +/// + /** * 该文件由 Tailchat 自动生成 * 用于插件的类型声明 @@ -66,6 +68,8 @@ declare module '@capital/common' { export const appendUrlSearch: any; + export const getServiceWorkerRegistration: any; + export const useGroupIdContext: any; export const getServiceUrl: () => string; @@ -84,7 +88,14 @@ declare module '@capital/common' { export const getCachedConverseInfo: any; - export const localTrans: any; + /** + * 本地翻译 + * @example + * localTrans({'zh-CN': '你好', 'en-US': 'Hello'}); + * + * @param trans 翻译对象 + */ + export const localTrans: (trans: Record<'zh-CN' | 'en-US', string>) => string; export const getLanguage: any; @@ -114,7 +125,7 @@ declare module '@capital/common' { export const useLocation: any; - export const useHistory: any; + export const useNavigate: any; export const createFastFormSchema: any; @@ -242,9 +253,14 @@ declare module '@capital/component' { export const Image: any; - export const Icon: any; + export const Icon: React.FC<{ icon: string } & React.SVGProps>; - export const IconBtn: any; + export const IconBtn: React.FC<{ + icon: string; + iconClassName?: string; + shape?: 'circle' | 'square'; + title?: string; + }>; export const PillTabs: any; @@ -296,4 +312,6 @@ declare module '@capital/component' { userId: string; className?: string; }>; + + export const Markdown: any; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10f0224d..3a931ac1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -840,9 +840,11 @@ importers: server/plugins/com.msgbyte.topic: specifiers: '@types/react': 18.0.20 + less: ^4.1.3 lodash: ^4.17.21 mini-star: '*' nanoid: ^3.1.23 + rollup-plugin-less: ^1.1.3 tailchat-server-sdk: '*' dependencies: lodash: 4.17.21 @@ -850,13 +852,19 @@ importers: tailchat-server-sdk: link:../../packages/sdk devDependencies: '@types/react': 18.0.20 + less: 4.1.3 mini-star: 1.3.1 + rollup-plugin-less: 1.1.3 server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic: specifiers: - react: 17.0.2 + less: ^4.1.3 + react: 18.2.0 + rollup-plugin-less: ^1.1.3 devDependencies: - react: 17.0.2 + less: 4.1.3 + react: 18.2.0 + rollup-plugin-less: 1.1.3 website: specifiers: @@ -10547,7 +10555,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 dev: true /debug/4.3.4: diff --git a/server/plugins/com.msgbyte.topic/package.json b/server/plugins/com.msgbyte.topic/package.json index b88e9197..03832f7f 100644 --- a/server/plugins/com.msgbyte.topic/package.json +++ b/server/plugins/com.msgbyte.topic/package.json @@ -12,7 +12,9 @@ }, "devDependencies": { "@types/react": "18.0.20", - "mini-star": "*" + "less": "^4.1.3", + "mini-star": "*", + "rollup-plugin-less": "^1.1.3" }, "dependencies": { "lodash": "^4.17.21", diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/package.json b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/package.json index 44d703d0..e48c780f 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/package.json +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/package.json @@ -4,8 +4,10 @@ "version": "0.0.0", "description": "为群组提供话题功能", "private": true, - "dependencies": {}, + "scripts": { + "sync:declaration": "tailchat declaration github" + }, "devDependencies": { - "react": "17.0.2" + "react": "18.2.0" } } diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.less b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.less new file mode 100644 index 00000000..57585bdb --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.less @@ -0,0 +1,44 @@ +.plugin-topic-card { + background-color: rgba(0, 0, 0, 0.25); + padding: 10px; + border-radius: 3px; + margin: 10px; + width: auto; + display: flex; + + .left { + margin-right: 10px; + } + + .right { + flex: 1; + user-select: text; + + .header { + display: flex; + line-height: 32px; + + .name { + margin-right: 4px; + } + + .date { + opacity: 0.6; + } + } + + .body { + .content { + margin-top: 6px; + margin-bottom: 6px; + } + + .reply { + padding: 10px; + margin-bottom: 6px; + border-radius: 3px; + background-color: rgba(0, 0, 0, 0.25); + } + } + } +} diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.tsx new file mode 100644 index 00000000..6c65060c --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/components/TopicCard.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Avatar, IconBtn } from '@capital/component'; +import './TopicCard.less'; + +export const TopicCard: React.FC = React.memo(() => { + return ( +
+
+ +
+ +
+
+
用户名
+
12:00
+
+ +
+
+ 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 +
+ +
回复回复回复
+
+ +
+ +
+
+
+ ); +}); +TopicCard.displayName = 'TopicCard'; diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.less b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.less new file mode 100644 index 00000000..a4ac3d29 --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.less @@ -0,0 +1,5 @@ +.plugin-topic-group-panel { + display: flex; + flex-direction: column; + width: 100%; +} diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx new file mode 100644 index 00000000..2aa9a4fc --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { TopicCard } from '../components/TopicCard'; +import './GroupTopicPanelRender.less'; + +const GroupTopicPanelRender: React.FC = React.memo(() => { + return ( +
+ {Array.from({ length: 20 }).map((_, i) => ( + + ))} +
+ ); +}); +GroupTopicPanelRender.displayName = 'GroupTopicPanelRender'; + +export default GroupTopicPanelRender; diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx index f7090de5..313c89e9 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx @@ -1 +1,11 @@ -console.log('Plugin 群组话题 is loaded'); +import { regGroupPanel, Loadable } from '@capital/common'; +import { Translate } from './translate'; + +const PLUGIN_NAME = 'com.msgbyte.topic'; + +regGroupPanel({ + name: `${PLUGIN_NAME}/grouppanel`, + label: Translate.topicpanel, + provider: PLUGIN_NAME, + render: Loadable(() => import('./group/GroupTopicPanelRender')), +}); diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts new file mode 100644 index 00000000..63a9cade --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts @@ -0,0 +1,5 @@ +import { localTrans } from '@capital/common'; + +export const Translate = { + topicpanel: localTrans({ 'zh-CN': '话题面板', 'en-US': 'Topic Panel' }), +}; diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts index 49f524ae..c59324aa 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts @@ -1,2 +1,304 @@ -declare module '@capital/common'; -declare module '@capital/component'; +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** + * 该文件由 Tailchat 自动生成 + * 用于插件的类型声明 + * 生成命令: pnpm run plugins:declaration:generate + */ + +/** + * Tailchat 通用 + */ +declare module '@capital/common' { + export const useGroupPanelParams: any; + + /** + * 打开模态框 + */ + export const openModal: ( + content: React.ReactNode, + + props?: { + /** + * 是否显示右上角的关闭按钮 + * @default false + */ + closable?: boolean; + + /** + * 遮罩层是否可关闭 + */ + maskClosable?: boolean; + + /** + * 关闭modal的回调 + */ + onCloseModal?: () => void; + } + ) => number; + + export const closeModal: any; + + export const ModalWrapper: any; + + export const useModalContext: any; + + export const openConfirmModal: any; + + export const openReconfirmModal: any; + + export const Loadable: any; + + export const getGlobalState: any; + + export const getJWTUserInfo: () => Promise<{ + _id?: string; + nickname?: string; + email?: string; + avatar?: string; + }>; + + export const dataUrlToFile: any; + + export const urlSearchStringify: any; + + export const urlSearchParse: any; + + export const appendUrlSearch: any; + + export const useGroupIdContext: any; + + export const getServiceUrl: () => string; + + export const getCachedUserInfo: ( + userId: string, + refetch?: boolean + ) => Promise<{ + _id: string; + email: string; + nickname: string; + discriminator: string; + avatar: string | null; + temporary: boolean; + }>; + + export const getCachedConverseInfo: any; + + export const localTrans: any; + + export const getLanguage: any; + + export const sharedEvent: any; + + export const useAsync: any; + + export const useAsyncFn: any; + + export const useAsyncRefresh: any; + + export const useAsyncRequest: any; + + export const uploadFile: any; + + export const showToasts: any; + + export const showErrorToasts: any; + + export const fetchAvailableServices: any; + + export const isValidStr: any; + + export const useGroupPanelInfo: any; + + export const sendMessage: any; + + export const useLocation: any; + + export const useHistory: any; + + export const createFastFormSchema: any; + + export const fieldSchema: any; + + export const useCurrentUserInfo: any; + + export const createPluginRequest: (pluginName: string) => { + get: (actionName: string, config?: any) => Promise; + post: (actionName: string, data?: any, config?: any) => Promise; + }; + + export const postRequest: any; + + export const pluginCustomPanel: any; + + export const regCustomPanel: any; + + export const pluginGroupPanel: any; + + export const regGroupPanel: any; + + export const messageInterpreter: any; + + export const regMessageInterpreter: any; + + export const getMessageRender: any; + + export const regMessageRender: any; + + export const getMessageTextDecorators: any; + + export const regMessageTextDecorators: any; + + export const ChatInputActionContextProps: any; + + export const pluginChatInputActions: any; + + export const regChatInputAction: any; + + export const regSocketEventListener: (item: { + eventName: string; + eventFn: (...args: any[]) => void; + }) => void; + + export const pluginColorScheme: any; + + export const regPluginColorScheme: any; + + export const pluginInspectServices: any; + + export const regInspectService: any; + + export const pluginMessageExtraParsers: any; + + export const regMessageExtraParser: any; + + export const pluginRootRoute: any; + + export const regPluginRootRoute: any; + + export const pluginPanelActions: any; + + export const regPluginPanelAction: any; + + export const pluginPermission: any; + + export const regPluginPermission: (permission: { + /** + * 权限唯一key, 用于写入数据库 + * 如果为插件则权限点应当符合命名规范, 如: plugin.com.msgbyte.github.manage + */ + key: string; + /** + * 权限点显示名称 + */ + title: string; + /** + * 权限描述 + */ + desc: string; + /** + * 是否默认开启 + */ + default: boolean; + /** + * 是否依赖其他权限点 + */ + required?: string[]; + }) => void; +} + +/** + * Tailchat 组件 + */ +declare module '@capital/component' { + export const Button: any; + + export const Checkbox: any; + + export const Input: any; + + export const Divider: any; + + export const Space: any; + + export const Menu: any; + + export const Table: any; + + export const Switch: any; + + export const Tooltip: any; + + /** + * @link https://ant.design/components/notification-cn/ + */ + export const notification: any; + + export const Avatar: any; + + export const SensitiveText: React.FC<{ className?: string; text: string }>; + + export const TextArea: any; + + export const Image: any; + + export const Icon: React.FC<{ icon: string } & React.SVGProps>; + + export const IconBtn: React.FC<{ + icon: string; + iconClassName?: string; + shape?: 'circle' | 'square'; + title?: string; + }>; + + export const PillTabs: any; + + export const PillTabPane: any; + + export const LoadingSpinner: any; + + export const WebFastForm: any; + + export const WebMetaForm: any; + + export const createMetaFormSchema: any; + + export const metaFormFieldSchema: any; + + export const FullModalField: any; + + export const DefaultFullModalInputEditorRender: any; + + export const DefaultFullModalTextAreaEditorRender: any; + + export const openModal: any; + + export const closeModal: any; + + export const ModalWrapper: any; + + export const useModalContext: any; + + export const openConfirmModal: any; + + export const openReconfirmModal: any; + + export const Loading: any; + + export const SidebarView: any; + + export const GroupPanelSelector: any; + + export const Emoji: any; + + export const PortalAdd: any; + + export const PortalRemove: any; + + export const ErrorBoundary: any; + + export const UserName: React.FC<{ + userId: string; + className?: string; + }>; +}