diff --git a/client/shared/i18n/langs/en-US/translation.json b/client/shared/i18n/langs/en-US/translation.json index 37c9a68f..0a0b52f3 100644 --- a/client/shared/i18n/langs/en-US/translation.json +++ b/client/shared/i18n/langs/en-US/translation.json @@ -42,6 +42,7 @@ "k267cc491": "Me", "k2a1422d2": "Configuration", "k2a8031e": "Homepage", + "k2b411a11": "Component can only work in the group panel", "k2c6ee8d": "Confirm the action", "k2c7df74f": "Modify Group Panel", "k2d6cfb27": "Chat Channel", @@ -313,6 +314,7 @@ "ke071c620": "Allow members to manage users, such as banning, removing users, etc.", "ke17b2c87": "Do not upload pictures that violate local laws and regulations", "ke187440d": "Panel type cannot be empty", + "ke2431c67": "Plugin render function does not exist", "ke3d797fd": "Drop files to send into current converse", "ke59ffe49": "Muted, there are {{remain}} left", "kea977d95": "The following users are offline", diff --git a/client/shared/i18n/langs/zh-CN/translation.json b/client/shared/i18n/langs/zh-CN/translation.json index 08420a1d..589321c9 100644 --- a/client/shared/i18n/langs/zh-CN/translation.json +++ b/client/shared/i18n/langs/zh-CN/translation.json @@ -42,6 +42,7 @@ "k267cc491": "我", "k2a1422d2": "配置", "k2a8031e": "个人主页", + "k2b411a11": "组件只能在群组面板中才能正常显示", "k2c6ee8d": "确认操作", "k2c7df74f": "编辑群组面板", "k2d6cfb27": "聊天频道", @@ -313,6 +314,7 @@ "ke071c620": "允许成员管理用户,如禁言、移除用户等操作", "ke17b2c87": "请勿上传违反当地法律法规的图片", "ke187440d": "面板类型不能为空", + "ke2431c67": "插件渲染函数不存在", "ke3d797fd": "拖放文件以发送到当前会话", "ke59ffe49": "禁言中, 还剩 {{remain}}", "kea977d95": "以下用户已离线", diff --git a/client/web/src/components/Panel/common/Wrapper.tsx b/client/web/src/components/Panel/common/Wrapper.tsx index a27c44c4..f1db0f60 100644 --- a/client/web/src/components/Panel/common/Wrapper.tsx +++ b/client/web/src/components/Panel/common/Wrapper.tsx @@ -12,11 +12,11 @@ interface RightPanelType { /** * 面板通用包装器 */ -interface CommonPanelWrapperProps extends PropsWithChildren { +export interface CommonPanelWrapperProps extends PropsWithChildren { header: React.ReactNode; - actions?: ( - setRightPanel: (info: RightPanelType) => void - ) => React.ReactElement[]; + actions?: (ctx: { + setRightPanel: (info: RightPanelType) => void; + }) => React.ReactElement[]; } export const CommonPanelWrapper: React.FC = React.memo( (props) => { @@ -33,7 +33,7 @@ export const CommonPanelWrapper: React.FC = React.memo( {/* 主面板 */}
{props.header} diff --git a/client/web/src/components/Panel/group/PluginPanel.tsx b/client/web/src/components/Panel/group/PluginPanel.tsx index 94727f95..8477087e 100644 --- a/client/web/src/components/Panel/group/PluginPanel.tsx +++ b/client/web/src/components/Panel/group/PluginPanel.tsx @@ -2,7 +2,6 @@ import { findPluginPanelInfoByName } from '@/utils/plugin-helper'; import { Alert } from 'antd'; import React, { useMemo } from 'react'; import { isValidStr, t, useGroupPanelInfo } from 'tailchat-shared'; -import { GroupPanelWrapper } from './Wrapper'; interface GroupPluginPanelProps { groupId: string; @@ -68,15 +67,7 @@ export const GroupPluginPanel: React.FC = React.memo( return null; } - return ( - - - - ); + return ; } ); GroupPluginPanel.displayName = 'GroupPluginPanel'; diff --git a/client/web/src/components/Panel/group/TextPanel.tsx b/client/web/src/components/Panel/group/TextPanel.tsx index 7d0326cd..af7fdc2d 100644 --- a/client/web/src/components/Panel/group/TextPanel.tsx +++ b/client/web/src/components/Panel/group/TextPanel.tsx @@ -1,5 +1,10 @@ import { ChatBox } from '@/components/ChatBox'; import { ChatInputMentionsContextProvider } from '@/components/ChatBox/ChatInputBox/context'; +import { IconBtn } from '@/components/IconBtn'; +import { + GroupPluginPanelActionProps, + pluginPanelActions, +} from '@/plugin/common'; import React, { useCallback, useLayoutEffect, useState } from 'react'; import { useGroupPanelInfo, @@ -14,7 +19,8 @@ import { useGroupInfo, GroupPanelType, } from 'tailchat-shared'; -import { GroupPanelWrapper } from './Wrapper'; +import { MembersPanel } from './MembersPanel'; +import { GroupPanelContainer } from './shared/GroupPanelContainer'; /** * 聊天输入框显示状态管理 @@ -84,7 +90,47 @@ export const TextPanel: React.FC = React.memo( } return ( - + [ + ...pluginPanelActions + .filter( + (action): action is GroupPluginPanelActionProps => + action.position === 'group' + ) + .map((action) => ( + + action.onClick({ + groupId, + panelId, + }) + } + /> + )), + ]} + suffixActions={({ setRightPanel }) => [ + + setRightPanel({ + name: t('成员') + ` (${groupMembers.length})`, + panel: , + }) + } + />, + ]} + > ({ id: m._id, @@ -106,7 +152,7 @@ export const TextPanel: React.FC = React.memo( groupId={groupId} /> - + ); } ); diff --git a/client/web/src/components/Panel/group/Wrapper.tsx b/client/web/src/components/Panel/group/Wrapper.tsx deleted file mode 100644 index 38622b33..00000000 --- a/client/web/src/components/Panel/group/Wrapper.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import React, { PropsWithChildren, useEffect, useMemo } from 'react'; -import { t, useGroupInfo, useGroupPanelInfo } from 'tailchat-shared'; -import _isNil from 'lodash/isNil'; -import { MembersPanel } from './MembersPanel'; -import { CommonPanelWrapper } from '../common/Wrapper'; -import { usePanelWindow } from '@/hooks/usePanelWindow'; -import { OpenedPanelTip } from '@/components/OpenedPanelTip'; -import { IconBtn } from '@/components/IconBtn'; -import { - GroupPluginPanelActionProps, - pluginPanelActions, -} from '@/plugin/common'; -import { useUserSessionPreference } from '@/hooks/useUserPreference'; -import { GroupPanelContext } from '@/context/GroupPanelContext'; - -/** - * 记录下最后访问的面板id - */ -function useRecordGroupPanel(groupId: string, panelId: string) { - const [lastVisitPanel, setLastVisitPanel] = useUserSessionPreference( - 'groupLastVisitPanel' - ); - - useEffect(() => { - setLastVisitPanel({ - ...lastVisitPanel, - [groupId]: panelId, - }); - }, [groupId, panelId]); -} - -/** - * 群组面板通用包装器 - */ -interface GroupPanelWrapperProps extends PropsWithChildren { - groupId: string; - panelId: string; - - /** - * 是否显示面板头 - */ - showHeader: boolean; -} -export const GroupPanelWrapper: React.FC = React.memo( - (props) => { - const { groupId, panelId } = props; - const groupInfo = useGroupInfo(groupId); - const panelInfo = useGroupPanelInfo(groupId, panelId); - const groupMemberCount = (groupInfo?.members ?? []).length; - useRecordGroupPanel(groupId, panelId); - - const { hasOpenedPanel, openPanelWindow, closePanelWindow } = - usePanelWindow(`/panel/group/${groupId}/${panelId}`); - - const groupPanelContextValue = useMemo( - () => ({ - groupId, - panelId, - }), - [groupId, panelId] - ); - - if (_isNil(panelInfo)) { - return null; - } - - if (hasOpenedPanel) { - return ; - } - - if (!props.showHeader) { - return ( - - {props.children} - - ); - } - - return ( - - [ - ...pluginPanelActions - .filter( - (action): action is GroupPluginPanelActionProps => - action.position === 'group' - ) - .map((action) => ( - - action.onClick({ - groupId: props.groupId, - panelId: props.panelId, - }) - } - /> - )), - , - - setRightPanel({ - name: t('成员') + ` (${groupMemberCount})`, - panel: , - }) - } - />, - ]} - > - {props.children} - - - ); - } -); -GroupPanelWrapper.displayName = 'GroupPanelWrapper'; diff --git a/client/web/src/components/Panel/group/shared/GroupPanelContainer.tsx b/client/web/src/components/Panel/group/shared/GroupPanelContainer.tsx new file mode 100644 index 00000000..03dfbe3e --- /dev/null +++ b/client/web/src/components/Panel/group/shared/GroupPanelContainer.tsx @@ -0,0 +1,55 @@ +import { IconBtn } from '@/components/IconBtn'; +import React, { PropsWithChildren } from 'react'; +import { t, useGroupPanelInfo } from 'tailchat-shared'; +import { + CommonPanelWrapper, + CommonPanelWrapperProps, +} from '../../common/Wrapper'; +import _isNil from 'lodash/isNil'; +import { usePanelWindow } from '@/hooks/usePanelWindow'; +import { OpenedPanelTip } from '@/components/OpenedPanelTip'; + +interface GroupPanelWithHeader extends PropsWithChildren { + groupId: string; + panelId: string; + + prefixActions?: CommonPanelWrapperProps['actions']; + suffixActions?: CommonPanelWrapperProps['actions']; +} +export const GroupPanelContainer: React.FC = React.memo( + (props) => { + const { groupId, panelId } = props; + const panelInfo = useGroupPanelInfo(groupId, panelId); + const { hasOpenedPanel, openPanelWindow, closePanelWindow } = + usePanelWindow(`/panel/group/${groupId}/${panelId}`); + + if (_isNil(panelInfo)) { + return null; + } + + if (hasOpenedPanel) { + return ; + } + + return ( + [ + ...(props.prefixActions?.(ctx) ?? []), + , + ...(props.suffixActions?.(ctx) ?? []), + ]} + > + {props.children} + + ); + } +); +GroupPanelContainer.displayName = 'GroupPanelWithHeader'; diff --git a/client/web/src/routes/Main/Content/Group/Panel.tsx b/client/web/src/routes/Main/Content/Group/Panel.tsx index 897bcf3b..b582aa95 100644 --- a/client/web/src/routes/Main/Content/Group/Panel.tsx +++ b/client/web/src/routes/Main/Content/Group/Panel.tsx @@ -1,8 +1,10 @@ import { GroupPluginPanel } from '@/components/Panel/group/PluginPanel'; import { TextPanel } from '@/components/Panel/group/TextPanel'; import { Problem } from '@/components/Problem'; +import { GroupPanelContext } from '@/context/GroupPanelContext'; +import { useUserSessionPreference } from '@/hooks/useUserPreference'; import { Alert } from 'antd'; -import React from 'react'; +import React, { useEffect, useMemo } from 'react'; import { GroupInfoContextProvider, GroupPanelType, @@ -12,6 +14,22 @@ import { } from 'tailchat-shared'; import { useGroupPanelParams } from './utils'; +/** + * 记录下最后访问的面板id + */ +function useRecordGroupPanel(groupId: string, panelId: string) { + const [lastVisitPanel, setLastVisitPanel] = useUserSessionPreference( + 'groupLastVisitPanel' + ); + + useEffect(() => { + setLastVisitPanel({ + ...lastVisitPanel, + [groupId]: panelId, + }); + }, [groupId, panelId]); +} + interface GroupPanelRenderProps { groupId: string; panelId: string; @@ -21,6 +39,14 @@ export const GroupPanelRender: React.FC = React.memo( const { groupId, panelId } = props; const groupInfo = useGroupInfo(groupId); const panelInfo = useGroupPanelInfo(groupId, panelId); + const groupPanelContextValue = useMemo( + () => ({ + groupId, + panelId, + }), + [groupId, panelId] + ); + useRecordGroupPanel(groupId, panelId); if (groupInfo === null) { return ( @@ -39,11 +65,18 @@ export const GroupPanelRender: React.FC = React.memo( if (panelInfo.type === GroupPanelType.TEXT) { return ( - + + + ); - } else if (panelInfo.type === GroupPanelType.PLUGIN) { - return ; + } + if (panelInfo.type === GroupPanelType.PLUGIN) { + return ( + + ; + + ); } return (