refactor(agent-settings): extract shared components and improve styling

- Move common components (AgentLabel, SettingsTitle, SettingsInline) to shared file
- Update CSS to use @layer base for better organization
- Fix agent type label translation key in AgentModal
- Add agent type label utility function
This commit is contained in:
icarus 2025-09-21 22:16:15 +08:00
parent bfe2e87f59
commit ea62294bd8
7 changed files with 80 additions and 25 deletions

View File

@ -11,12 +11,14 @@
@import '../fonts/ubuntu/ubuntu.css'; @import '../fonts/ubuntu/ubuntu.css';
@import '../fonts/country-flag-fonts/flag.css'; @import '../fonts/country-flag-fonts/flag.css';
*, @layer base {
*::before, *,
*::after { *::before,
box-sizing: border-box; *::after {
/* margin: 0; */ box-sizing: border-box;
font-weight: normal; /* margin: 0; */
font-weight: normal;
}
} }
*:focus { *:focus {

View File

@ -317,7 +317,7 @@ export const AgentModal: React.FC<Props> = ({ agent, trigger, isOpen: _isOpen, o
selectedKeys={[form.type]} selectedKeys={[form.type]}
onChange={onAgentTypeChange} onChange={onAgentTypeChange}
items={agentOptions} items={agentOptions}
label={t('agent.add.type.label')} label={t('agent.type.label')}
placeholder={t('agent.add.type.placeholder')} placeholder={t('agent.add.type.placeholder')}
renderValue={renderOption}> renderValue={renderOption}>
{(option) => ( {(option) => (

View File

@ -5,7 +5,13 @@
*/ */
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { BuiltinMCPServerName, BuiltinMCPServerNames, BuiltinOcrProviderId, ThinkingOption } from '@renderer/types' import {
AgentType,
BuiltinMCPServerName,
BuiltinMCPServerNames,
BuiltinOcrProviderId,
ThinkingOption
} from '@renderer/types'
import i18n from './index' import i18n from './index'
@ -339,3 +345,11 @@ export const getBuiltinOcrProviderLabel = (key: BuiltinOcrProviderId) => {
else if (key == 'paddleocr') return 'PaddleOCR' else if (key == 'paddleocr') return 'PaddleOCR'
else return getLabel(builtinOcrProviderKeyMap, key) else return getLabel(builtinOcrProviderKeyMap, key)
} }
const agentTypeKeyMap = {
'claude-code': 'Claude Code'
} as const satisfies Record<AgentType, string>
export const getAgentTypeLabel = (key: AgentType) => {
return getLabel(agentTypeKeyMap, key, t('agent.type.unknown'))
}

View File

@ -1,12 +1,13 @@
import { Avatar } from '@heroui/react' import { HStack } from '@renderer/components/Layout'
import { Box, HStack } from '@renderer/components/Layout'
import { getAgentAvatar } from '@renderer/config/agent'
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent' import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
import { AgentEntity, UpdateAgentForm } from '@renderer/types' import { AgentEntity, UpdateAgentForm } from '@renderer/types'
import { Input } from 'antd' import { Input } from 'antd'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { SettingDivider } from '..'
import { AgentLabel, SettingsInline, SettingsTitle } from './shared'
interface AgentEssentialSettingsProps { interface AgentEssentialSettingsProps {
agent: AgentEntity | undefined | null agent: AgentEntity | undefined | null
update: ReturnType<typeof useUpdateAgent> update: ReturnType<typeof useUpdateAgent>
@ -26,11 +27,13 @@ const AgentEssentialSettings: FC<AgentEssentialSettingsProps> = ({ agent, update
return ( return (
<div className="flex flex-1 flex-col overflow-hidden"> <div className="flex flex-1 flex-col overflow-hidden">
<Box mb={8} style={{ fontWeight: 'bold' }}> <SettingsInline>
{t('common.name')} <SettingsTitle>{t('agent.type.label')}</SettingsTitle>
</Box> <AgentLabel type={agent.type} />
</SettingsInline>
<SettingDivider />
<SettingsTitle>{t('common.name')}</SettingsTitle>
<HStack gap={8} alignItems="center"> <HStack gap={8} alignItems="center">
<Avatar src={getAgentAvatar(agent.type)} title={agent.type} className="h-5 w-5" />
<Input <Input
placeholder={t('common.assistant') + t('common.name')} placeholder={t('common.assistant') + t('common.name')}
value={name} value={name}

View File

@ -1,5 +1,5 @@
import CodeEditor from '@renderer/components/CodeEditor' import CodeEditor from '@renderer/components/CodeEditor'
import { Box, HSpaceBetweenStack, HStack } from '@renderer/components/Layout' import { HSpaceBetweenStack } from '@renderer/components/Layout'
import { RichEditorRef } from '@renderer/components/RichEditor/types' import { RichEditorRef } from '@renderer/components/RichEditor/types'
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent' import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
import { usePromptProcessor } from '@renderer/hooks/usePromptProcessor' import { usePromptProcessor } from '@renderer/hooks/usePromptProcessor'
@ -12,6 +12,8 @@ import { useTranslation } from 'react-i18next'
import ReactMarkdown from 'react-markdown' import ReactMarkdown from 'react-markdown'
import styled from 'styled-components' import styled from 'styled-components'
import { SettingsTitle } from './shared'
interface AgentPromptSettingsProps { interface AgentPromptSettingsProps {
agent: AgentEntity | undefined | null agent: AgentEntity | undefined | null
update: ReturnType<typeof useUpdateAgent> update: ReturnType<typeof useUpdateAgent>
@ -50,12 +52,12 @@ const AgentPromptSettings: FC<AgentPromptSettingsProps> = ({ agent, update }) =>
return ( return (
<Container> <Container>
<HStack mb={8} alignItems="center" gap={4}> <SettingsTitle>
<Box style={{ fontWeight: 'bold' }}>{t('common.prompt')}</Box> {t('common.prompt')}
<Popover title={t('agents.add.prompt.variables.tip.title')} content={promptVarsContent}> <Popover title={t('agents.add.prompt.variables.tip.title')} content={promptVarsContent}>
<HelpCircle size={14} color="var(--color-text-2)" /> <HelpCircle size={14} color="var(--color-text-2)" />
</Popover> </Popover>
</HStack> </SettingsTitle>
<TextAreaContainer> <TextAreaContainer>
<RichEditorContainer> <RichEditorContainer>
{showPreview ? ( {showPreview ? (

View File

@ -1,7 +1,5 @@
import { Avatar } from '@heroui/react'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import { TopView } from '@renderer/components/TopView' import { TopView } from '@renderer/components/TopView'
import { getAgentAvatar } from '@renderer/config/agent'
import { useAgent } from '@renderer/hooks/agents/useAgent' import { useAgent } from '@renderer/hooks/agents/useAgent'
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent' import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
import { Menu, Modal } from 'antd' import { Menu, Modal } from 'antd'
@ -11,6 +9,7 @@ import styled from 'styled-components'
import AgentEssentialSettings from './AgentEssentialSettings' import AgentEssentialSettings from './AgentEssentialSettings'
import AgentPromptSettings from './AgentPromptSettings' import AgentPromptSettings from './AgentPromptSettings'
import { AgentLabel } from './shared'
interface AgentSettingPopupShowParams { interface AgentSettingPopupShowParams {
agentId: string agentId: string
@ -65,10 +64,12 @@ const AgentSettingPopupContainer: React.FC<AgentSettingPopupParams> = ({ tab, ag
maskClosable={false} maskClosable={false}
footer={null} footer={null}
title={ title={
<div className="flex items-center"> <AgentLabel
<Avatar size="sm" className="mr-2 h-5 w-5" src={agent ? getAgentAvatar(agent.type) : undefined} /> type={agent?.type ?? 'claude-code'}
<span className="font-extrabold text-xl">{agent?.name ?? ''}</span> name={agent?.name}
</div> classNames={{ name: 'text-lg font-extrabold' }}
avatarProps={{ size: 'sm' }}
/>
} }
transitionName="animation-move-down" transitionName="animation-move-down"
styles={{ styles={{

View File

@ -0,0 +1,33 @@
import { Avatar, AvatarProps, cn } from '@heroui/react'
import { getAgentAvatar } from '@renderer/config/agent'
import { getAgentTypeLabel } from '@renderer/i18n/label'
import { AgentType } from '@renderer/types'
import React from 'react'
export const SettingsTitle: React.FC<React.PropsWithChildren> = ({ children }) => {
return <div className="mb-1 flex items-center gap-2 font-bold">{children}</div>
}
export const SettingsInline: React.FC<React.PropsWithChildren> = ({ children }) => {
return <div className="flex items-center justify-between gap-2">{children}</div>
}
export type AgentLabelProps = {
type: AgentType
name?: string
classNames?: {
container?: string
avatar?: string
name?: string
}
avatarProps?: AvatarProps
}
export const AgentLabel: React.FC<AgentLabelProps> = ({ type, name, classNames, avatarProps }) => {
return (
<div className={cn('flex items-center gap-2', classNames?.container)}>
<Avatar src={getAgentAvatar(type)} title={type} {...avatarProps} className={cn('h-5 w-5', classNames?.avatar)} />
<span className={classNames?.name}>{name ?? getAgentTypeLabel(type)}</span>
</div>
)
}