mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 22:39:36 +08:00
refactor(translate): reorganize translation settings and remove deprecated components
- Removed TranslateSettings and TranslateModelSettings components to streamline the translation settings interface. - Introduced CustomLanguageSettings and TranslatePromptSettings components for better management of custom languages and prompt settings. - Updated ModelSettings to utilize the new TranslateSettingsPopup for handling translation-related configurations. - Enhanced the overall structure and readability of the translation settings page.
This commit is contained in:
parent
c666361611
commit
809a532a6c
@ -1,7 +1,6 @@
|
||||
import { RedoOutlined } from '@ant-design/icons'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import ModelSelector from '@renderer/components/ModelSelector'
|
||||
import PromptPopup from '@renderer/components/Popups/PromptPopup'
|
||||
import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/config/models'
|
||||
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
@ -19,6 +18,7 @@ import { FC, useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { SettingContainer, SettingDescription, SettingGroup, SettingTitle } from '..'
|
||||
import TranslateSettingsPopup from '../TranslateSettingsPopup/TranslateSettingsPopup'
|
||||
import DefaultAssistantSettings from './DefaultAssistantSettings'
|
||||
import TopicNamingModalPopup from './TopicNamingModalPopup'
|
||||
|
||||
@ -53,21 +53,6 @@ const ModelSettings: FC = () => {
|
||||
[translateModel]
|
||||
)
|
||||
|
||||
const onUpdateTranslateModel = async () => {
|
||||
const prompt = await PromptPopup.show({
|
||||
title: t('settings.models.translate_model_prompt_title'),
|
||||
message: t('settings.models.translate_model_prompt_message'),
|
||||
defaultValue: translateModelPrompt,
|
||||
inputProps: {
|
||||
rows: 10,
|
||||
onPressEnter: () => {}
|
||||
}
|
||||
})
|
||||
if (prompt) {
|
||||
dispatch(setTranslateModelPrompt(prompt))
|
||||
}
|
||||
}
|
||||
|
||||
const onResetTranslatePrompt = () => {
|
||||
dispatch(setTranslateModelPrompt(TRANSLATE_PROMPT))
|
||||
}
|
||||
@ -133,7 +118,11 @@ const ModelSettings: FC = () => {
|
||||
onChange={(value) => setTranslateModel(find(allModels, JSON.parse(value)) as Model)}
|
||||
placeholder={t('settings.models.empty')}
|
||||
/>
|
||||
<Button icon={<Settings2 size={16} />} style={{ marginLeft: 8 }} onClick={onUpdateTranslateModel} />
|
||||
<Button
|
||||
icon={<Settings2 size={16} />}
|
||||
style={{ marginLeft: 8 }}
|
||||
onClick={() => TranslateSettingsPopup.show()}
|
||||
/>
|
||||
{translateModelPrompt !== TRANSLATE_PROMPT && (
|
||||
<Tooltip title={t('common.reset')}>
|
||||
<Button icon={<RedoOutlined />} style={{ marginLeft: 8 }} onClick={onResetTranslatePrompt}></Button>
|
||||
|
||||
@ -7,7 +7,6 @@ import {
|
||||
FolderCog,
|
||||
HardDrive,
|
||||
Info,
|
||||
Languages,
|
||||
MonitorCog,
|
||||
Package,
|
||||
PictureInPicture2,
|
||||
@ -31,7 +30,6 @@ import QuickAssistantSettings from './QuickAssistantSettings'
|
||||
import SelectionAssistantSettings from './SelectionAssistantSettings/SelectionAssistantSettings'
|
||||
import ShortcutSettings from './ShortcutSettings'
|
||||
import ToolSettings from './ToolSettings'
|
||||
import TranslateSettings from './TranslateSettings/TranslateSettings'
|
||||
|
||||
const SettingsPage: FC = () => {
|
||||
const { pathname } = useLocation()
|
||||
@ -82,12 +80,6 @@ const SettingsPage: FC = () => {
|
||||
{t('settings.mcp.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/translate">
|
||||
<MenuItem className={isRoute('/settings/translate')}>
|
||||
<Languages size={18} />
|
||||
{t('settings.translate.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/memory">
|
||||
<MenuItem className={isRoute('/settings/memory')}>
|
||||
<Brain size={18} />
|
||||
@ -131,7 +123,6 @@ const SettingsPage: FC = () => {
|
||||
<Route path="model" element={<ModelSettings />} />
|
||||
<Route path="tool/*" element={<ToolSettings />} />
|
||||
<Route path="mcp/*" element={<MCPSettings />} />
|
||||
<Route path="translate" element={<TranslateSettings />} />
|
||||
<Route path="memory" element={<MemorySettings />} />
|
||||
<Route path="general/*" element={<GeneralSettings />} />
|
||||
<Route path="display" element={<DisplaySettings />} />
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import ModelSelector from '@renderer/components/ModelSelector'
|
||||
import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/config/models'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useDefaultModel } from '@renderer/hooks/useAssistant'
|
||||
import { useProviders } from '@renderer/hooks/useProvider'
|
||||
import { getModelUniqId, hasModel } from '@renderer/services/ModelService'
|
||||
import { Model } from '@renderer/types'
|
||||
import { find } from 'lodash'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { SettingDescription, SettingGroup, SettingTitle } from '..'
|
||||
|
||||
const TranslateModelSettings = () => {
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const { providers } = useProviders()
|
||||
const { translateModel, setTranslateModel } = useDefaultModel()
|
||||
|
||||
const allModels = useMemo(() => providers.map((p) => p.models).flat(), [providers])
|
||||
|
||||
const modelPredicate = useCallback(
|
||||
(m: Model) => !isEmbeddingModel(m) && !isRerankModel(m) && !isTextToImageModel(m),
|
||||
[]
|
||||
)
|
||||
|
||||
const defaultTranslateModel = useMemo(
|
||||
() => (hasModel(translateModel) ? getModelUniqId(translateModel) : undefined),
|
||||
[translateModel]
|
||||
)
|
||||
|
||||
return (
|
||||
<SettingGroup theme={theme}>
|
||||
<SettingTitle style={{ marginBottom: 12 }}>
|
||||
<HStack alignItems="center" gap={10}>
|
||||
{t('settings.models.translate_model')}
|
||||
</HStack>
|
||||
</SettingTitle>
|
||||
<HStack alignItems="center">
|
||||
<ModelSelector
|
||||
providers={providers}
|
||||
predicate={modelPredicate}
|
||||
value={defaultTranslateModel}
|
||||
defaultValue={defaultTranslateModel}
|
||||
style={{ width: 360 }}
|
||||
onChange={(value) => setTranslateModel(find(allModels, JSON.parse(value)) as Model)}
|
||||
placeholder={t('settings.models.empty')}
|
||||
/>
|
||||
</HStack>
|
||||
<SettingDescription>{t('settings.models.translate_model_description')}</SettingDescription>
|
||||
</SettingGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export default TranslateModelSettings
|
||||
@ -1,51 +0,0 @@
|
||||
import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import CustomLanguageSettings from '@renderer/pages/settings/TranslateSettings/CustomLanguageSettings'
|
||||
import { getAllCustomLanguages } from '@renderer/services/TranslateService'
|
||||
import { CustomTranslateLanguage } from '@renderer/types'
|
||||
import { Suspense, useEffect, useState } from 'react'
|
||||
|
||||
import { SettingContainer, SettingGroup } from '..'
|
||||
import TranslateModelSettings from './TranslateModelSettings'
|
||||
import TranslatePromptSettings from './TranslatePromptSettings'
|
||||
|
||||
const TranslateSettings = () => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
const [dataPromise, setDataPromise] = useState<Promise<CustomTranslateLanguage[]>>(Promise.resolve([]))
|
||||
|
||||
useEffect(() => {
|
||||
setDataPromise(getAllCustomLanguages())
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingContainer theme={theme}>
|
||||
<TranslateModelSettings />
|
||||
<TranslatePromptSettings />
|
||||
<SettingGroup theme={theme} style={{ flex: 1 }}>
|
||||
<Suspense fallback={<CustomLanguagesSettingsFallback />}>
|
||||
<CustomLanguageSettings dataPromise={dataPromise} />
|
||||
</Suspense>
|
||||
</SettingGroup>
|
||||
</SettingContainer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const CustomLanguagesSettingsFallback = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 250,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<SvgSpinners180Ring />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TranslateSettings
|
||||
@ -98,7 +98,9 @@ const CustomLanguageModal = ({ isOpen, editingCustomLanguage, onAdd, onEdit, onC
|
||||
footer={footer}
|
||||
onCancel={onCancel}
|
||||
maskClosable={false}
|
||||
transitionName="animation-move-down"
|
||||
forceRender
|
||||
centered
|
||||
styles={{
|
||||
body: {
|
||||
padding: '20px'
|
||||
@ -1,20 +1,19 @@
|
||||
import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import { loggerService } from '@logger'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { deleteCustomLanguage } from '@renderer/services/TranslateService'
|
||||
import { deleteCustomLanguage, getAllCustomLanguages } from '@renderer/services/TranslateService'
|
||||
import { CustomTranslateLanguage } from '@renderer/types'
|
||||
import { Button, Popconfirm, Space, Table, TableProps } from 'antd'
|
||||
import { memo, startTransition, use, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { memo, startTransition, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import { SettingRowTitle } from '..'
|
||||
import CustomLanguageModal from './CustomLanguageModal'
|
||||
|
||||
type Props = {
|
||||
dataPromise: Promise<CustomTranslateLanguage[]>
|
||||
}
|
||||
const logger = loggerService.withContext('CustomLanguageSettings')
|
||||
|
||||
const CustomLanguageSettings = ({ dataPromise }: Props) => {
|
||||
const CustomLanguageSettings = () => {
|
||||
const { t } = useTranslation()
|
||||
const [displayedItems, setDisplayedItems] = useState<CustomTranslateLanguage[]>([])
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
@ -104,18 +103,28 @@ const CustomLanguageSettings = ({ dataPromise }: Props) => {
|
||||
[onDelete, t]
|
||||
)
|
||||
|
||||
const data = use(dataPromise)
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayedItems(data)
|
||||
}, [data])
|
||||
const loadData = async () => {
|
||||
try {
|
||||
const data = await getAllCustomLanguages()
|
||||
setDisplayedItems(data)
|
||||
} catch (error) {
|
||||
logger.error('Failed to load custom languages:', error as Error)
|
||||
}
|
||||
}
|
||||
loadData()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<CustomLanguageSettingsContainer>
|
||||
<HStack justifyContent="space-between" style={{ padding: '4px 0' }}>
|
||||
<SettingRowTitle>{t('translate.custom.label')}</SettingRowTitle>
|
||||
<Button type="primary" icon={<PlusOutlined size={16} />} onClick={onClickAdd}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined size={16} />}
|
||||
onClick={onClickAdd}
|
||||
style={{ marginBottom: 5, marginTop: -5 }}>
|
||||
{t('common.add')}
|
||||
</Button>
|
||||
</HStack>
|
||||
@ -45,7 +45,8 @@ const TranslatePromptSettings = () => {
|
||||
onChange={(e) => setLocalPrompt(e.target.value)}
|
||||
onBlur={(e) => dispatch(setTranslateModelPrompt(e.target.value))}
|
||||
autoSize={{ minRows: 4, maxRows: 10 }}
|
||||
placeholder={t('settings.models.translate_model_prompt_message')}></Input.TextArea>
|
||||
placeholder={t('settings.models.translate_model_prompt_message')}
|
||||
/>
|
||||
</SettingGroup>
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { Modal } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { SettingContainer, SettingGroup } from '..'
|
||||
import CustomLanguageSettings from './CustomLanguageSettings'
|
||||
import TranslatePromptSettings from './TranslatePromptSettings'
|
||||
|
||||
interface Props {
|
||||
resolve: (data: any) => void
|
||||
}
|
||||
|
||||
const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
const [open, setOpen] = useState(true)
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const onOk = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
resolve({})
|
||||
}
|
||||
|
||||
TranslateSettingsPopup.hide = onCancel
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t('settings.translate.title')}
|
||||
open={open}
|
||||
onOk={onOk}
|
||||
onCancel={onCancel}
|
||||
afterClose={onClose}
|
||||
transitionName="animation-move-down"
|
||||
width="80vw"
|
||||
centered>
|
||||
<SettingContainer theme={theme} style={{ padding: '10px 0' }}>
|
||||
<TranslatePromptSettings />
|
||||
<SettingGroup theme={theme} style={{ flex: 1 }}>
|
||||
<CustomLanguageSettings />
|
||||
</SettingGroup>
|
||||
</SettingContainer>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const TopViewKey = 'TranslateSettingsPopup'
|
||||
|
||||
export default class TranslateSettingsPopup {
|
||||
static topviewId = 0
|
||||
static hide() {
|
||||
TopView.hide(TopViewKey)
|
||||
}
|
||||
static show() {
|
||||
return new Promise<any>((resolve) => {
|
||||
TopView.show(
|
||||
<PopupContainer
|
||||
resolve={(v) => {
|
||||
resolve(v)
|
||||
TopView.hide(TopViewKey)
|
||||
}}
|
||||
/>,
|
||||
TopViewKey
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,14 @@
|
||||
import { RedoOutlined } from '@ant-design/icons'
|
||||
import LanguageSelect from '@renderer/components/LanguageSelect'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
||||
import db from '@renderer/databases'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import useTranslate from '@renderer/hooks/useTranslate'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import { setTranslateModelPrompt } from '@renderer/store/settings'
|
||||
import { Model, TranslateLanguage } from '@renderer/types'
|
||||
import { Button, Flex, Input, Modal, Space, Switch, Tooltip } from 'antd'
|
||||
import { ChevronDown, HelpCircle } from 'lucide-react'
|
||||
import { Button, Flex, Modal, Space, Switch, Tooltip } from 'antd'
|
||||
import { HelpCircle } from 'lucide-react'
|
||||
import { FC, memo, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import TranslateSettingsPopup from '../settings/TranslateSettingsPopup/TranslateSettingsPopup'
|
||||
|
||||
const TranslateSettings: FC<{
|
||||
visible: boolean
|
||||
@ -39,37 +35,16 @@ const TranslateSettings: FC<{
|
||||
setBidirectionalPair
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { translateModelPrompt } = useSettings()
|
||||
const dispatch = useAppDispatch()
|
||||
const [localPair, setLocalPair] = useState<[TranslateLanguage, TranslateLanguage]>(bidirectionalPair)
|
||||
const [showPrompt, setShowPrompt] = useState(false)
|
||||
const [localPrompt, setLocalPrompt] = useState(translateModelPrompt)
|
||||
const { getLanguageByLangcode } = useTranslate()
|
||||
|
||||
useEffect(() => {
|
||||
setLocalPair(bidirectionalPair)
|
||||
setLocalPrompt(translateModelPrompt)
|
||||
}, [bidirectionalPair, translateModelPrompt, visible])
|
||||
}, [bidirectionalPair, visible])
|
||||
|
||||
const handleSave = () => {
|
||||
if (localPair[0] === localPair[1]) {
|
||||
window.message.warning({
|
||||
content: t('translate.language.same'),
|
||||
key: 'translate-message'
|
||||
})
|
||||
return
|
||||
}
|
||||
setBidirectionalPair(localPair)
|
||||
db.settings.put({ id: 'translate:bidirectional:pair', value: [localPair[0].langCode, localPair[1].langCode] })
|
||||
db.settings.put({ id: 'translate:scroll:sync', value: isScrollSyncEnabled })
|
||||
db.settings.put({ id: 'translate:markdown:enabled', value: enableMarkdown })
|
||||
db.settings.put({ id: 'translate:model:prompt', value: localPrompt })
|
||||
dispatch(setTranslateModelPrompt(localPrompt))
|
||||
window.message.success({
|
||||
content: t('message.save.success.title'),
|
||||
key: 'translate-settings-save'
|
||||
})
|
||||
const onMoreSetting = () => {
|
||||
onClose()
|
||||
TranslateSettingsPopup.show()
|
||||
}
|
||||
|
||||
return (
|
||||
@ -78,27 +53,33 @@ const TranslateSettings: FC<{
|
||||
open={visible}
|
||||
onCancel={onClose}
|
||||
centered={true}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={onClose}>
|
||||
{t('common.cancel')}
|
||||
</Button>,
|
||||
<Button key="save" type="primary" onClick={handleSave}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
]}
|
||||
width={420}>
|
||||
<Flex vertical gap={16} style={{ marginTop: 16 }}>
|
||||
footer={null}
|
||||
width={420}
|
||||
transitionName="animation-move-down">
|
||||
<Flex vertical gap={16} style={{ marginTop: 16, paddingBottom: 20 }}>
|
||||
<div>
|
||||
<Flex align="center" justify="space-between">
|
||||
<div style={{ fontWeight: 500 }}>{t('translate.settings.preview')}</div>
|
||||
<Switch checked={enableMarkdown} onChange={setEnableMarkdown} />
|
||||
<Switch
|
||||
checked={enableMarkdown}
|
||||
onChange={(checked) => {
|
||||
setEnableMarkdown(checked)
|
||||
db.settings.put({ id: 'translate:markdown:enabled', value: checked })
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Flex align="center" justify="space-between">
|
||||
<div style={{ fontWeight: 500 }}>{t('translate.settings.scroll_sync')}</div>
|
||||
<Switch checked={isScrollSyncEnabled} onChange={setIsScrollSyncEnabled} />
|
||||
<Switch
|
||||
checked={isScrollSyncEnabled}
|
||||
onChange={(checked) => {
|
||||
setIsScrollSyncEnabled(checked)
|
||||
db.settings.put({ id: 'translate:scroll:sync', value: checked })
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</div>
|
||||
|
||||
@ -114,7 +95,13 @@ const TranslateSettings: FC<{
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
</div>
|
||||
<Switch checked={isBidirectional} onChange={setIsBidirectional} />
|
||||
<Switch
|
||||
checked={isBidirectional}
|
||||
onChange={(checked) => {
|
||||
setIsBidirectional(checked)
|
||||
// 双向翻译设置不需要持久化,它只是界面状态
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
{isBidirectional && (
|
||||
<Space direction="vertical" style={{ width: '100%', marginTop: 8 }}>
|
||||
@ -122,78 +109,52 @@ const TranslateSettings: FC<{
|
||||
<LanguageSelect
|
||||
style={{ flex: 1 }}
|
||||
value={localPair[0].langCode}
|
||||
onChange={(value) => setLocalPair([getLanguageByLangcode(value), localPair[1]])}
|
||||
onChange={(value) => {
|
||||
const newPair: [TranslateLanguage, TranslateLanguage] = [getLanguageByLangcode(value), localPair[1]]
|
||||
if (newPair[0] === newPair[1]) {
|
||||
window.message.warning({
|
||||
content: t('translate.language.same'),
|
||||
key: 'translate-message'
|
||||
})
|
||||
return
|
||||
}
|
||||
setLocalPair(newPair)
|
||||
setBidirectionalPair(newPair)
|
||||
db.settings.put({
|
||||
id: 'translate:bidirectional:pair',
|
||||
value: [newPair[0].langCode, newPair[1].langCode]
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<span>⇆</span>
|
||||
<LanguageSelect
|
||||
style={{ flex: 1 }}
|
||||
value={localPair[1].langCode}
|
||||
onChange={(value) => setLocalPair([localPair[0], getLanguageByLangcode(value)])}
|
||||
onChange={(value) => {
|
||||
const newPair: [TranslateLanguage, TranslateLanguage] = [localPair[0], getLanguageByLangcode(value)]
|
||||
if (newPair[0] === newPair[1]) {
|
||||
window.message.warning({
|
||||
content: t('translate.language.same'),
|
||||
key: 'translate-message'
|
||||
})
|
||||
return
|
||||
}
|
||||
setLocalPair(newPair)
|
||||
setBidirectionalPair(newPair)
|
||||
db.settings.put({
|
||||
id: 'translate:bidirectional:pair',
|
||||
value: [newPair[0].langCode, newPair[1].langCode]
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Flex align="center" justify="space-between">
|
||||
<div
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => setShowPrompt(!showPrompt)}>
|
||||
{t('settings.models.translate_model_prompt_title')}
|
||||
<ChevronDown
|
||||
size={16}
|
||||
style={{
|
||||
transform: showPrompt ? 'rotate(180deg)' : 'rotate(0deg)',
|
||||
transition: 'transform 0.3s',
|
||||
marginLeft: 5
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{localPrompt !== TRANSLATE_PROMPT && (
|
||||
<Tooltip title={t('common.reset')}>
|
||||
<Button
|
||||
icon={<RedoOutlined />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => setLocalPrompt(TRANSLATE_PROMPT)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
|
||||
<div style={{ display: showPrompt ? 'block' : 'none' }}>
|
||||
<Textarea
|
||||
rows={8}
|
||||
value={localPrompt}
|
||||
onChange={(e) => setLocalPrompt(e.target.value)}
|
||||
placeholder={t('settings.models.translate_model_prompt_message')}
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={onMoreSetting}>{t('settings.moresetting.label')}</Button>
|
||||
</Flex>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(TranslateSettings)
|
||||
|
||||
const Textarea = styled(Input.TextArea)`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
border-radius: 0;
|
||||
.ant-input {
|
||||
resize: none;
|
||||
padding: 5px 16px;
|
||||
}
|
||||
.ant-input-clear-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user