mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +08:00
feat: search translate history (#9342)
* feat(翻译历史): 添加搜索翻译历史UI 在翻译历史页面添加搜索框 * feat(翻译历史): 优化搜索功能并添加延迟渲染 - 将搜索逻辑提取为独立函数并使用useDeferredValue优化性能 - 重构类型命名和状态管理 - 格式化日期显示并移入memo计算 * feat(i18n): 为翻译历史添加搜索框占位文本 * refactor(translate): 移除未使用的InputRef引用和inputRef变量
This commit is contained in:
parent
1ac32bad14
commit
fe097a937c
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Failed to save translation history"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Search translation history"
|
||||
},
|
||||
"title": "Translation History"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "保存翻訳履歴に失敗しました"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "翻訳履歴を検索する"
|
||||
},
|
||||
"title": "翻訳履歴"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Не удалось сохранить историю переводов"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Поиск истории переводов"
|
||||
},
|
||||
"title": "История переводов"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "保存翻译历史失败"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "搜索翻译历史"
|
||||
},
|
||||
"title": "翻译历史"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "保存翻譯歷史失敗"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "搜索翻譯歷史"
|
||||
},
|
||||
"title": "翻譯歷史"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Αποτυχία αποθήκευσης του ιστορικού μεταφράσεων"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Αναζήτηση ιστορικού μεταφράσεων"
|
||||
},
|
||||
"title": "Ιστορικό μετάφρασης"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Error al guardar el historial de traducciones"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Historial de búsqueda de traducción"
|
||||
},
|
||||
"title": "Historial de traducciones"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Échec de la sauvegarde de l'historique des traductions"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Rechercher l'historique des traductions"
|
||||
},
|
||||
"title": "Historique des traductions"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -3723,6 +3723,9 @@
|
||||
"error": {
|
||||
"save": "Falha ao guardar o histórico de traduções"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Pesquisar histórico de tradução"
|
||||
},
|
||||
"title": "Histórico de Tradução"
|
||||
},
|
||||
"input": {
|
||||
|
||||
@ -1,28 +1,32 @@
|
||||
import { DeleteOutlined } from '@ant-design/icons'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { DynamicVirtualList } from '@renderer/components/VirtualList'
|
||||
import db from '@renderer/databases'
|
||||
import useTranslate from '@renderer/hooks/useTranslate'
|
||||
import { clearHistory, deleteHistory } from '@renderer/services/TranslateService'
|
||||
import { TranslateHistory, TranslateLanguage } from '@renderer/types'
|
||||
import { Button, Drawer, Dropdown, Empty, Flex, Popconfirm } from 'antd'
|
||||
import { Button, Drawer, Dropdown, Empty, Flex, Input, Popconfirm } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import { useLiveQuery } from 'dexie-react-hooks'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { FC, useMemo } from 'react'
|
||||
import { SearchIcon } from 'lucide-react'
|
||||
import { FC, useCallback, useDeferredValue, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
type DisplayedTranslateHistory = TranslateHistory & {
|
||||
type DisplayedTranslateHistoryItem = TranslateHistory & {
|
||||
_sourceLanguage: TranslateLanguage
|
||||
_targetLanguage: TranslateLanguage
|
||||
}
|
||||
|
||||
type TranslateHistoryProps = {
|
||||
isOpen: boolean
|
||||
onHistoryItemClick: (history: DisplayedTranslateHistory) => void
|
||||
onHistoryItemClick: (history: DisplayedTranslateHistoryItem) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
// const logger = loggerService.withContext('TranslateHistory')
|
||||
|
||||
// px
|
||||
const ITEM_HEIGHT = 140
|
||||
|
||||
@ -30,17 +34,35 @@ const TranslateHistoryList: FC<TranslateHistoryProps> = ({ isOpen, onHistoryItem
|
||||
const { t } = useTranslation()
|
||||
const { getLanguageByLangcode } = useTranslate()
|
||||
const _translateHistory = useLiveQuery(() => db.translate_history.orderBy('createdAt').reverse().toArray(), [])
|
||||
const [search, setSearch] = useState('')
|
||||
const [displayedHistory, setDisplayedHistory] = useState<DisplayedTranslateHistoryItem[]>([])
|
||||
|
||||
const translateHistory: DisplayedTranslateHistory[] = useMemo(() => {
|
||||
const translateHistory: DisplayedTranslateHistoryItem[] = useMemo(() => {
|
||||
if (!_translateHistory) return []
|
||||
|
||||
return _translateHistory.map((item) => ({
|
||||
...item,
|
||||
_sourceLanguage: getLanguageByLangcode(item.sourceLanguage),
|
||||
_targetLanguage: getLanguageByLangcode(item.targetLanguage)
|
||||
_targetLanguage: getLanguageByLangcode(item.targetLanguage),
|
||||
createdAt: dayjs(item.createdAt).format('MM/DD HH:mm')
|
||||
}))
|
||||
}, [_translateHistory, getLanguageByLangcode])
|
||||
|
||||
const searchFilter = useCallback(
|
||||
(item: DisplayedTranslateHistoryItem) => {
|
||||
if (isEmpty(search)) return true
|
||||
const content = `${item._sourceLanguage.label()} ${item._targetLanguage.label()} ${item.sourceText} ${item.targetText} ${item.createdAt}`
|
||||
return content.includes(search)
|
||||
},
|
||||
[search]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayedHistory(translateHistory.filter(searchFilter))
|
||||
}, [searchFilter, translateHistory])
|
||||
|
||||
const deferredHistory = useDeferredValue(displayedHistory)
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={t('translate.history.title')}
|
||||
@ -71,9 +93,32 @@ const TranslateHistoryList: FC<TranslateHistoryProps> = ({ isOpen, onHistoryItem
|
||||
}
|
||||
}}>
|
||||
<HistoryContainer>
|
||||
{translateHistory && translateHistory.length ? (
|
||||
{/* Search Bar */}
|
||||
<HStack style={{ padding: '0 12px', borderBottom: '1px solid var(--ant-color-split)' }}>
|
||||
<Input
|
||||
prefix={
|
||||
<IconWrapper>
|
||||
<SearchIcon size={18} />
|
||||
</IconWrapper>
|
||||
}
|
||||
placeholder={t('translate.history.search.placeholder')}
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
setSearch(e.target.value)
|
||||
}}
|
||||
allowClear
|
||||
autoFocus
|
||||
spellCheck={false}
|
||||
style={{ paddingLeft: 0, height: '3em' }}
|
||||
variant="borderless"
|
||||
size="middle"
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
{/* Virtual List */}
|
||||
{deferredHistory.length > 0 ? (
|
||||
<HistoryList>
|
||||
<DynamicVirtualList list={translateHistory} estimateSize={() => ITEM_HEIGHT}>
|
||||
<DynamicVirtualList list={deferredHistory} estimateSize={() => ITEM_HEIGHT}>
|
||||
{(item) => {
|
||||
return (
|
||||
<Dropdown
|
||||
@ -98,7 +143,7 @@ const TranslateHistoryList: FC<TranslateHistoryProps> = ({ isOpen, onHistoryItem
|
||||
<HistoryListItemLanguage>{item._sourceLanguage.label()} →</HistoryListItemLanguage>
|
||||
<HistoryListItemLanguage>{item._targetLanguage.label()}</HistoryListItemLanguage>
|
||||
</Flex>
|
||||
<HistoryListItemDate>{dayjs(item.createdAt).format('MM/DD HH:mm')}</HistoryListItemDate>
|
||||
<HistoryListItemDate>{item.createdAt}</HistoryListItemDate>
|
||||
</Flex>
|
||||
<HistoryListItemTitle>{item.sourceText}</HistoryListItemTitle>
|
||||
<HistoryListItemTitle style={{ color: 'var(--color-text-2)' }}>
|
||||
@ -192,4 +237,14 @@ const HistoryListItemLanguage = styled.div`
|
||||
color: var(--color-text-3);
|
||||
`
|
||||
|
||||
const IconWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 15px;
|
||||
background-color: var(--color-background-soft);
|
||||
`
|
||||
|
||||
export default TranslateHistoryList
|
||||
|
||||
Loading…
Reference in New Issue
Block a user