From 77db2a1e2b36f6636d8f82b939c8ae970bfcf085 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 1 Nov 2024 11:00:17 +0800 Subject: [PATCH] feat: improved ui layout and added reusable add agent card component --- src/renderer/src/pages/agents/Agents.tsx | 187 +++++------------- src/renderer/src/pages/agents/AgentsPage.tsx | 61 ++---- .../pages/agents/components/AddAgentCard.tsx | 41 ++++ .../src/pages/agents/components/AgentCard.tsx | 151 +++++++------- 4 files changed, 179 insertions(+), 261 deletions(-) create mode 100644 src/renderer/src/pages/agents/components/AddAgentCard.tsx diff --git a/src/renderer/src/pages/agents/Agents.tsx b/src/renderer/src/pages/agents/Agents.tsx index 6a7d07ca1b..66aa2cc17b 100644 --- a/src/renderer/src/pages/agents/Agents.tsx +++ b/src/renderer/src/pages/agents/Agents.tsx @@ -1,26 +1,22 @@ import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons' import AssistantSettingsPopup from '@renderer/components/AssistantSettings' -import DragableList from '@renderer/components/DragableList' import { useAgents } from '@renderer/hooks/useAgents' import { createAssistantFromAgent } from '@renderer/services/AssistantService' import { Agent } from '@renderer/types' -import { Button, Col, Typography } from 'antd' -import { useCallback, useState } from 'react' +import { Col } from 'antd' +import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' -import AddAgentPopup from './components/AddAgentPopup' import AgentCard from './components/AgentCard' interface Props { onClick?: (agent: Agent) => void - cardStyle?: 'new' | 'old' } -const Agents: React.FC = ({ onClick, cardStyle = 'old' }) => { +const Agents: React.FC = ({ onClick }) => { const { t } = useTranslation() - const { agents, removeAgent, updateAgents } = useAgents() - const [dragging, setDragging] = useState(false) + const { agents, removeAgent } = useAgents() const handleDelete = useCallback( (agent: Agent) => { @@ -33,135 +29,58 @@ const Agents: React.FC = ({ onClick, cardStyle = 'old' }) => { [removeAgent, t] ) - if (cardStyle === 'new') { - return ( - <> - {agents.map((agent) => { - const dropdownMenuItems = [ - { - key: 'edit', - label: t('agents.edit.title'), - icon: , - onClick: () => AssistantSettingsPopup.show({ assistant: agent }) - }, - { - key: 'create', - label: t('agents.add.button'), - icon: , - onClick: () => createAssistantFromAgent(agent) - }, - { - key: 'delete', - label: t('common.delete'), - icon: , - danger: true, - onClick: () => handleDelete(agent) - } - ] - - const contextMenuItems = [ - { - label: t('agents.edit.title'), - onClick: () => AssistantSettingsPopup.show({ assistant: agent }) - }, - { - label: t('agents.add.button'), - onClick: () => createAssistantFromAgent(agent) - }, - { - label: t('common.delete'), - onClick: () => handleDelete(agent) - } - ] - - return ( - - onClick?.(agent)} - contextMenu={contextMenuItems} - menuItems={dropdownMenuItems} - /> - - ) - })} - - ) - } - return ( - -
- - {t('agents.my_agents')} - - {agents.length > 0 && ( - setDragging(true)} - onDragEnd={() => setDragging(false)}> - {(agent: Agent) => { - const dropdownMenuItems = [ - { - key: 'edit', - label: t('agents.edit.title'), - icon: , - onClick: () => AssistantSettingsPopup.show({ assistant: agent }) - }, - { - key: 'create', - label: t('agents.add.button'), - icon: , - onClick: () => createAssistantFromAgent(agent) - }, - { - key: 'delete', - label: t('common.delete'), - icon: , - danger: true, - onClick: () => handleDelete(agent) - } - ] + <> + {agents.map((agent) => { + const dropdownMenuItems = [ + { + key: 'edit', + label: t('agents.edit.title'), + icon: , + onClick: () => AssistantSettingsPopup.show({ assistant: agent }) + }, + { + key: 'create', + label: t('agents.add.button'), + icon: , + onClick: () => createAssistantFromAgent(agent) + }, + { + key: 'delete', + label: t('common.delete'), + icon: , + danger: true, + onClick: () => handleDelete(agent) + } + ] - const contextMenuItems = [ - { - label: t('agents.edit.title'), - onClick: () => AssistantSettingsPopup.show({ assistant: agent }) - }, - { - label: t('agents.add.button'), - onClick: () => createAssistantFromAgent(agent) - }, - { - label: t('common.delete'), - onClick: () => handleDelete(agent) - } - ] + const contextMenuItems = [ + { + label: t('agents.edit.title'), + onClick: () => AssistantSettingsPopup.show({ assistant: agent }) + }, + { + label: t('agents.add.button'), + onClick: () => createAssistantFromAgent(agent) + }, + { + label: t('common.delete'), + onClick: () => handleDelete(agent) + } + ] - return ( - onClick?.(agent)} - contextMenu={contextMenuItems} - menuItems={dropdownMenuItems} - /> - ) - }} - - )} - {!dragging && ( - - )} -
-
- + return ( + + onClick?.(agent)} + contextMenu={contextMenuItems} + menuItems={dropdownMenuItems} + /> + + ) + })} + ) } diff --git a/src/renderer/src/pages/agents/AgentsPage.tsx b/src/renderer/src/pages/agents/AgentsPage.tsx index cbc7fa6c06..085353f1c9 100644 --- a/src/renderer/src/pages/agents/AgentsPage.tsx +++ b/src/renderer/src/pages/agents/AgentsPage.tsx @@ -1,4 +1,4 @@ -import { PlusOutlined, SearchOutlined } from '@ant-design/icons' +import { SearchOutlined } from '@ant-design/icons' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import Scrollbar from '@renderer/components/Scrollbar' import SystemAgents from '@renderer/config/agents.json' @@ -14,6 +14,7 @@ import styled from 'styled-components' import { groupTranslations } from './agentGroupTranslations' import Agents from './Agents' +import AddAgentCard from './components/AddAgentCard' import AddAgentPopup from './components/AddAgentPopup' import AgentCard from './components/AgentCard' @@ -128,17 +129,17 @@ const AgentsPage: FC = () => { {localizedGroupName} - + {group === '我的' ? ( <> - + AddAgentPopup.show()} /> - + ) : ( filteredAgentGroups[group]?.map((agent, index) => ( - + onAddAgentConfirm(getAgentFromSystemAgent(agent))} agent={agent as any} /> )) @@ -151,7 +152,7 @@ const AgentsPage: FC = () => { }, [filteredAgentGroups, getLocalizedGroupName, onAddAgentConfirm]) return ( - + {t('agents.title')} @@ -173,7 +174,7 @@ const AgentsPage: FC = () => { {tabItems.length > 0 ? ( - + ) : ( @@ -181,11 +182,11 @@ const AgentsPage: FC = () => { )} - + ) } -const StyledContainer = styled.div` +const Container = styled.div` display: flex; flex: 1; flex-direction: column; @@ -199,6 +200,7 @@ const ContentContainer = styled.div` justify-content: center; height: 100%; padding: 0 10px; + padding-left: 0; ` const AssistantsContainer = styled.div` @@ -211,7 +213,7 @@ const AssistantsContainer = styled.div` const TabContent = styled(Scrollbar)` height: calc(100vh - var(--navbar-height)); padding: 10px 10px 10px 15px; - margin-right: 4px; + margin-right: -4px; overflow-x: hidden; ` @@ -235,7 +237,11 @@ const Tabs = styled(TabsAntd)` flex: 1; flex-direction: row-reverse; .ant-tabs-tabpane { - padding-left: 0 !important; + padding-right: 0 !important; + } + .ant-tabs-nav { + min-width: 120px; + max-width: 120px; } .ant-tabs-nav-list { padding: 10px 8px; @@ -259,8 +265,8 @@ const Tabs = styled(TabsAntd)` border-right: none; } .ant-tabs-content-holder { - border-left: none; - border-right: 0.5px solid var(--color-border); + border-left: 0.5px solid var(--color-border); + border-right: none; } .ant-tabs-ink-bar { display: none; @@ -275,33 +281,4 @@ const Tabs = styled(TabsAntd)` } ` -const AddAgentCard = styled(({ onClick, className }: { onClick: () => void; className?: string }) => { - const { t } = useTranslation() - - return ( -
- - {t('agents.add.title')} -
- ) -})` - width: 100%; - height: 220px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background-color: var(--color-background); - border-radius: 15px; - border: 1px dashed var(--color-border); - cursor: pointer; - transition: all 0.3s ease; - color: var(--color-text-soft); - - &:hover { - border-color: var(--color-primary); - color: var(--color-primary); - } -` - export default AgentsPage diff --git a/src/renderer/src/pages/agents/components/AddAgentCard.tsx b/src/renderer/src/pages/agents/components/AddAgentCard.tsx new file mode 100644 index 0000000000..ea58ffdcc3 --- /dev/null +++ b/src/renderer/src/pages/agents/components/AddAgentCard.tsx @@ -0,0 +1,41 @@ +import { PlusOutlined } from '@ant-design/icons' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' + +interface AddAgentCardProps { + onClick: () => void + className?: string +} + +const AddAgentCard = ({ onClick, className }: AddAgentCardProps) => { + const { t } = useTranslation() + + return ( + + + {t('agents.add.title')} + + ) +} + +const StyledCard = styled.div` + width: 100%; + height: 180px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--color-background); + border-radius: 15px; + border: 1px dashed var(--color-border); + cursor: pointer; + transition: all 0.3s ease; + color: var(--color-text-soft); + + &:hover { + border-color: var(--color-primary); + color: var(--color-primary); + } +` + +export default AddAgentCard diff --git a/src/renderer/src/pages/agents/components/AgentCard.tsx b/src/renderer/src/pages/agents/components/AgentCard.tsx index b9fd6465a1..04b8faa4e1 100644 --- a/src/renderer/src/pages/agents/components/AgentCard.tsx +++ b/src/renderer/src/pages/agents/components/AgentCard.tsx @@ -17,9 +17,63 @@ interface Props { }[] } +const AgentCard: React.FC = ({ agent, onClick, contextMenu, menuItems }) => { + const emoji = agent.emoji || getLeadingEmoji(agent.name) + const prompt = (agent.description || agent.prompt).substring(0, 100).replace(/\\n/g, '') + const content = ( + + {agent.emoji && {agent.emoji}} + {emoji} + {menuItems && ( + e.stopPropagation()}> + ({ + ...item, + onClick: (e) => { + e.domEvent.stopPropagation() + e.domEvent.preventDefault() + setTimeout(() => { + item.onClick() + }, 0) + } + })) + }} + trigger={['click']} + placement="bottomRight"> + + + + )} + + {agent.name} + {prompt}... + + + ) + + if (contextMenu) { + return ( + ({ + key: item.label, + label: item.label, + onClick: () => item.onClick() + })) + }} + trigger={['contextMenu']}> + {content} + + ) + } + + return content +} + const Container = styled.div` width: 100%; - height: 220px; + height: 180px; display: flex; flex-direction: column; align-items: center; @@ -36,7 +90,7 @@ const Container = styled.div` &::before { content: ''; width: 100%; - height: 80px; + height: 70px; position: absolute; top: 0; left: 0; @@ -51,41 +105,21 @@ const Container = styled.div` z-index: 1; } - &:hover::before { - width: 100%; - height: 100%; - border-radius: 15px; - } - - &:hover .card-info { - transform: translateY(-15px); - padding: 0 20px; - - .agent-prompt { - opacity: 1; - transform: translateY(0); - } - } - - &:hover .emoji-container { - transform: scale(0.6); - margin-top: 5px; - } - - &:hover .banner-background { - height: 100%; + .agent-prompt { + opacity: 1; + transform: translateY(0); } ` const EmojiContainer = styled.div` - width: 70px; - height: 70px; - min-width: 70px; - min-height: 70px; + width: 60px; + height: 60px; + min-width: 60px; + min-height: 60px; background-color: var(--color-background); border-radius: 50%; border: 4px solid var(--color-border); - margin-top: 20px; + margin-top: 5px; transition: all 0.5s ease; display: flex; align-items: center; @@ -126,7 +160,7 @@ const AgentPrompt = styled.p` transition: all 0.5s ease; margin: 0; display: -webkit-box; - -webkit-line-clamp: 4; + -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.4; @@ -137,7 +171,7 @@ const BannerBackground = styled.div` top: 0; left: 0; width: 100%; - height: 80px; + height: 70px; display: flex; justify-content: center; align-items: center; @@ -171,57 +205,4 @@ const MenuContainer = styled.div` } ` -const AgentCard: React.FC = ({ agent, onClick, contextMenu, menuItems }) => { - const emoji = agent.emoji || getLeadingEmoji(agent.name) - const content = ( - - {agent.emoji && {agent.emoji}} - {emoji} - {menuItems && ( - e.stopPropagation()}> - ({ - ...item, - onClick: (e) => { - e.domEvent.stopPropagation() - e.domEvent.preventDefault() - setTimeout(() => { - item.onClick() - }, 0) - } - })) - }} - trigger={['click']} - placement="bottomRight"> - - - - )} - - {agent.name} - {(agent.description || agent.prompt).substring(0, 100)}... - - - ) - - if (contextMenu) { - return ( - ({ - key: item.label, - label: item.label, - onClick: () => item.onClick() - })) - }} - trigger={['contextMenu']}> - {content} - - ) - } - - return content -} - export default AgentCard