refactor: tooltip icons (#9841)

* refactor: add HelpTooltip, group tooltip icons

* refactor: add a tip for preview tools

* refactor: use HelpTooltip in SettingsTab
This commit is contained in:
one 2025-09-03 18:02:53 +08:00 committed by GitHub
parent 8a4c635c97
commit b1a9fbc6fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 83 additions and 48 deletions

View File

@ -0,0 +1,20 @@
import { Tooltip, TooltipProps } from 'antd'
import { HelpCircle } from 'lucide-react'
type InheritedTooltipProps = Omit<TooltipProps, 'children'>
interface HelpTooltipProps extends InheritedTooltipProps {
iconColor?: string
iconSize?: string | number
iconStyle?: React.CSSProperties
}
const HelpTooltip = ({ iconColor = 'var(--color-text-2)', iconSize = 14, iconStyle, ...rest }: HelpTooltipProps) => {
return (
<Tooltip {...rest}>
<HelpCircle size={iconSize} color={iconColor} style={{ ...iconStyle }} role="img" aria-label="Help" />
</Tooltip>
)
}
export default HelpTooltip

View File

@ -9,7 +9,7 @@ interface InfoTooltipProps extends InheritedTooltipProps {
iconStyle?: React.CSSProperties
}
const InfoTooltip = ({ iconColor = 'var(--color-text-3)', iconSize = 14, iconStyle, ...rest }: InfoTooltipProps) => {
const InfoTooltip = ({ iconColor = 'var(--color-text-2)', iconSize = 14, iconStyle, ...rest }: InfoTooltipProps) => {
return (
<Tooltip {...rest}>
<Info size={iconSize} color={iconColor} style={{ ...iconStyle }} role="img" aria-label="Information" />

View File

@ -0,0 +1,3 @@
export { default as HelpTooltip } from './HelpTooltip'
export { default as InfoTooltip } from './InfoTooltip'
export { default as WarnTooltip } from './WarnTooltip'

View File

@ -538,7 +538,10 @@
"tip": "The run button will be displayed in the toolbar of executable code blocks, please do not execute dangerous code!",
"title": "Code Execution"
},
"code_image_tools": "Enable preview tools",
"code_image_tools": {
"label": "Enable preview tools",
"tip": "Enable preview tools for images rendered from code blocks such as mermaid"
},
"code_wrappable": "Code block wrappable",
"context_count": {
"label": "Context",

View File

@ -538,7 +538,10 @@
"tip": "実行可能なコードブロックのツールバーには実行ボタンが表示されます。危険なコードを実行しないでください!",
"title": "コード実行"
},
"code_image_tools": "プレビューツールを有効にする",
"code_image_tools": {
"label": "プレビューツールを有効にする",
"tip": "mermaid などのコードブロックから生成された画像に対してプレビューツールを有効にする"
},
"code_wrappable": "コードブロック折り返し",
"context_count": {
"label": "コンテキスト",

View File

@ -538,7 +538,10 @@
"tip": "Выполнение кода в блоке кода возможно, но не рекомендуется выполнять опасный код!",
"title": "Выполнение кода"
},
"code_image_tools": "Включить инструменты предпросмотра",
"code_image_tools": {
"label": "Включить инструменты предпросмотра",
"tip": "Включить инструменты предпросмотра для изображений, сгенерированных из блоков кода (например mermaid)"
},
"code_wrappable": "Блок кода можно переносить",
"context_count": {
"label": "Контекст",

View File

@ -538,7 +538,10 @@
"tip": "可执行的代码块工具栏中会显示运行按钮,注意不要执行危险代码!",
"title": "代码执行"
},
"code_image_tools": "启用预览工具",
"code_image_tools": {
"label": "启用预览工具",
"tip": "为 mermaid 等代码块渲染后的图像启用预览工具"
},
"code_wrappable": "代码块可换行",
"context_count": {
"label": "上下文数",

View File

@ -538,7 +538,10 @@
"tip": "可執行的程式碼塊工具欄中會顯示運行按鈕,注意不要執行危險程式碼!",
"title": "程式碼執行"
},
"code_image_tools": "啟用預覽工具",
"code_image_tools": {
"label": "啟用預覽工具",
"tip": "為 mermaid 等程式碼區塊渲染後的圖像啟用預覽工具"
},
"code_wrappable": "程式碼區塊可自動換行",
"context_count": {
"label": "上下文",

View File

@ -2,6 +2,7 @@ import EditableNumber from '@renderer/components/EditableNumber'
import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar'
import Selector from '@renderer/components/Selector'
import { HelpTooltip } from '@renderer/components/TooltipIcons'
import { DEFAULT_CONTEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { isOpenAIModel } from '@renderer/config/models'
import { UNKNOWN } from '@renderer/config/translate'
@ -48,8 +49,8 @@ import {
import { Assistant, AssistantSettings, CodeStyleVarious, MathEngine, ThemeMode } from '@renderer/types'
import { modalConfirm } from '@renderer/utils'
import { getSendMessageShortcutLabel } from '@renderer/utils/input'
import { Button, Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { CircleHelp, Settings2 } from 'lucide-react'
import { Button, Col, InputNumber, Row, Slider, Switch } from 'antd'
import { Settings2 } from 'lucide-react'
import { FC, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@ -193,10 +194,10 @@ const SettingsTab: FC<Props> = (props) => {
}>
<SettingGroup style={{ marginTop: 5 }}>
<Row align="middle">
<SettingRowTitleSmall>{t('chat.settings.temperature.label')}</SettingRowTitleSmall>
<Tooltip title={t('chat.settings.temperature.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<SettingRowTitleSmall>
{t('chat.settings.temperature.label')}
<HelpTooltip title={t('chat.settings.temperature.tip')} />
</SettingRowTitleSmall>
<Switch
size="small"
style={{ marginLeft: 'auto' }}
@ -224,10 +225,10 @@ const SettingsTab: FC<Props> = (props) => {
<SettingDivider />
)}
<Row align="middle">
<SettingRowTitleSmall>{t('chat.settings.context_count.label')}</SettingRowTitleSmall>
<Tooltip title={t('chat.settings.context_count.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<SettingRowTitleSmall>
{t('chat.settings.context_count.label')}
<HelpTooltip title={t('chat.settings.context_count.tip')} />
</SettingRowTitleSmall>
</Row>
<Row align="middle" gutter={10}>
<Col span={23}>
@ -256,10 +257,10 @@ const SettingsTab: FC<Props> = (props) => {
<SettingDivider />
<SettingRow>
<Row align="middle">
<SettingRowTitleSmall>{t('chat.settings.max_tokens.label')}</SettingRowTitleSmall>
<Tooltip title={t('chat.settings.max_tokens.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<SettingRowTitleSmall>
{t('chat.settings.max_tokens.label')}
<HelpTooltip title={t('chat.settings.max_tokens.tip')} />
</SettingRowTitleSmall>
</Row>
<Switch
size="small"
@ -327,9 +328,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRow>
<SettingRowTitleSmall>
{t('chat.settings.thought_auto_collapse.label')}
<Tooltip title={t('chat.settings.thought_auto_collapse.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<HelpTooltip title={t('chat.settings.thought_auto_collapse.tip')} />
</SettingRowTitleSmall>
<Switch
size="small"
@ -426,10 +425,8 @@ const SettingsTab: FC<Props> = (props) => {
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>
{t('settings.math.single_dollar.label')}{' '}
<Tooltip title={t('settings.math.single_dollar.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
{t('settings.math.single_dollar.label')}
<HelpTooltip title={t('settings.math.single_dollar.tip')} />
</SettingRowTitleSmall>
<Switch
size="small"
@ -457,9 +454,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRow>
<SettingRowTitleSmall>
{t('chat.settings.code_execution.title')}
<Tooltip title={t('chat.settings.code_execution.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<HelpTooltip title={t('chat.settings.code_execution.tip')} />
</SettingRowTitleSmall>
<Switch
size="small"
@ -473,9 +468,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRow style={{ paddingLeft: 8 }}>
<SettingRowTitleSmall>
{t('chat.settings.code_execution.timeout_minutes.label')}
<Tooltip title={t('chat.settings.code_execution.timeout_minutes.tip')}>
<CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip>
<HelpTooltip title={t('chat.settings.code_execution.timeout_minutes.tip')} />
</SettingRowTitleSmall>
<EditableNumber
size="small"
@ -563,7 +556,10 @@ const SettingsTab: FC<Props> = (props) => {
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('chat.settings.code_image_tools')}</SettingRowTitleSmall>
<SettingRowTitleSmall>
{t('chat.settings.code_image_tools.label')}
<HelpTooltip title={t('chat.settings.code_image_tools.tip')} />
</SettingRowTitleSmall>
<Switch
size="small"
checked={codeImageTools}
@ -713,6 +709,7 @@ const Container = styled(Scrollbar)`
const SettingRowTitleSmall = styled(SettingRowTitle)`
font-size: 13px;
gap: 4px;
`
const SettingGroup = styled.div<{ theme?: ThemeMode }>`

View File

@ -25,8 +25,8 @@ const mocks = vi.hoisted(() => {
}
})
vi.mock('@renderer/components/InfoTooltip', () => ({
default: ({ title }: { title: string }) => <div>{mocks.i18n.t(title)}</div>
vi.mock('@renderer/components/TooltipIcons', () => ({
InfoTooltip: ({ title }: { title: string }) => <div>{mocks.i18n.t(title)}</div>
}))
vi.mock('react-i18next', () => ({

View File

@ -31,8 +31,8 @@ const mocks = vi.hoisted(() => ({
}))
// Mock InfoTooltip component
vi.mock('@renderer/components/InfoTooltip', () => ({
default: ({ title, placement }: { title: string; placement: string }) => (
vi.mock('@renderer/components/TooltipIcons', () => ({
InfoTooltip: ({ title, placement }: { title: string; placement: string }) => (
<span data-testid="info-tooltip" title={title} data-placement={placement}>
</span>

View File

@ -1,4 +1,4 @@
import InfoTooltip from '@renderer/components/InfoTooltip'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { KnowledgeBase } from '@renderer/types'
import { Alert, InputNumber } from 'antd'
import { TriangleAlert } from 'lucide-react'

View File

@ -1,6 +1,6 @@
import InfoTooltip from '@renderer/components/InfoTooltip'
import InputEmbeddingDimension from '@renderer/components/InputEmbeddingDimension'
import ModelSelector from '@renderer/components/ModelSelector'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { DEFAULT_KNOWLEDGE_DOCUMENT_COUNT } from '@renderer/config/constant'
import { isEmbeddingModel, isRerankModel } from '@renderer/config/models'
import { useProviders } from '@renderer/hooks/useProvider'

View File

@ -1,8 +1,8 @@
import { loggerService } from '@logger'
import AiProvider from '@renderer/aiCore'
import InfoTooltip from '@renderer/components/InfoTooltip'
import InputEmbeddingDimension from '@renderer/components/InputEmbeddingDimension'
import ModelSelector from '@renderer/components/ModelSelector'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { isEmbeddingModel, isRerankModel } from '@renderer/config/models'
import { useModel } from '@renderer/hooks/useModel'
import { useProviders } from '@renderer/hooks/useProvider'

View File

@ -1,6 +1,6 @@
// import { loggerService } from '@logger'
import InfoTooltip from '@renderer/components/InfoTooltip'
import { SuccessTag } from '@renderer/components/Tags/SuccessTag'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { isMac, isWin } from '@renderer/config/constant'
import { useOcrProvider } from '@renderer/hooks/useOcrProvider'
import useTranslate from '@renderer/hooks/useTranslate'

View File

@ -1,6 +1,6 @@
// import { loggerService } from '@logger'
import InfoTooltip from '@renderer/components/InfoTooltip'
import CustomTag from '@renderer/components/Tags/CustomTag'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { TESSERACT_LANG_MAP } from '@renderer/config/ocr'
import { useOcrProvider } from '@renderer/hooks/useOcrProvider'
import useTranslate from '@renderer/hooks/useTranslate'

View File

@ -1,7 +1,7 @@
import { InfoCircleOutlined } from '@ant-design/icons'
import InfoTooltip from '@renderer/components/InfoTooltip'
import { HStack } from '@renderer/components/Layout'
import Selector from '@renderer/components/Selector'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useEnableDeveloperMode, useSettings } from '@renderer/hooks/useSettings'
import { useTimer } from '@renderer/hooks/useTimer'

View File

@ -1,7 +1,7 @@
import { RedoOutlined } from '@ant-design/icons'
import InfoTooltip from '@renderer/components/InfoTooltip'
import { HStack } from '@renderer/components/Layout'
import ModelSelector from '@renderer/components/ModelSelector'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/config/models'
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
import { useTheme } from '@renderer/context/ThemeProvider'

View File

@ -1,5 +1,5 @@
import InfoTooltip from '@renderer/components/InfoTooltip'
import { HStack } from '@renderer/components/Layout'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import { useProvider } from '@renderer/hooks/useProvider'
import { Provider } from '@renderer/types'
import { Flex, Switch } from 'antd'

View File

@ -7,7 +7,7 @@ import {
VisionTag,
WebSearchTag
} from '@renderer/components/Tags/Model'
import WarnTooltip from '@renderer/components/WarnTooltip'
import { WarnTooltip } from '@renderer/components/TooltipIcons'
import { endpointTypeOptions } from '@renderer/config/endpointTypes'
import {
isEmbeddingModel,

View File

@ -1,6 +1,6 @@
import { loggerService } from '@logger'
import EmojiPicker from '@renderer/components/EmojiPicker'
import InfoTooltip from '@renderer/components/InfoTooltip'
import { InfoTooltip } from '@renderer/components/TooltipIcons'
import useTranslate from '@renderer/hooks/useTranslate'
import { addCustomLanguage, updateCustomLanguage } from '@renderer/services/TranslateService'
import { CustomTranslateLanguage } from '@renderer/types'