fix: handle optional list length in DraggableVirtualList and update padding in QuickPanel

This commit is contained in:
kangfenmao 2025-07-17 13:39:11 +08:00
parent f01b7075fb
commit 30b080efbd
15 changed files with 115 additions and 86 deletions

View File

@ -226,10 +226,11 @@ const StyledModal = styled(Modal)<{ $isFullscreen?: boolean }>`
} }
.ant-modal-header { .ant-modal-header {
padding: 10px 12px !important; padding: 10px !important;
border-bottom: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
background: var(--color-background); background: var(--color-background);
margin-bottom: 0 !important; margin-bottom: 0 !important;
border-radius: 0 !important;
} }
` `

View File

@ -82,7 +82,7 @@ function DraggableVirtualList<T>({
const parentRef = useRef<HTMLDivElement>(null) const parentRef = useRef<HTMLDivElement>(null)
const virtualizer = useVirtualizer({ const virtualizer = useVirtualizer({
count: list.length, count: list?.length ?? 0,
getScrollElement: useCallback(() => parentRef.current, []), getScrollElement: useCallback(() => parentRef.current, []),
getItemKey: itemKey, getItemKey: itemKey,
estimateSize: useCallback(() => 50, []), estimateSize: useCallback(() => 50, []),

View File

@ -611,7 +611,7 @@ const QuickPanelContainer = styled.div<{
left: 0; left: 0;
right: 0; right: 0;
width: 100%; width: 100%;
padding: 0 30px 0 30px; padding: 0 35px 0 35px;
transform: translateY(-100%); transform: translateY(-100%);
transform-origin: bottom; transform-origin: bottom;
transition: max-height 0.2s ease; transition: max-height 0.2s ease;

View File

@ -410,6 +410,7 @@ export const REFERENCE_PROMPT = `Please answer the question based on the referen
- Please cite the context at the end of sentences when appropriate. - Please cite the context at the end of sentences when appropriate.
- Please use the format of citation number [number] to reference the context in corresponding parts of your answer. - Please use the format of citation number [number] to reference the context in corresponding parts of your answer.
- If a sentence comes from multiple contexts, please list all relevant citation numbers, e.g., [1][2]. Remember not to group citations at the end but list them in the corresponding parts of your answer. - If a sentence comes from multiple contexts, please list all relevant citation numbers, e.g., [1][2]. Remember not to group citations at the end but list them in the corresponding parts of your answer.
- If all reference content is not relevant to the user's question, please answer based on your knowledge.
## My question is: ## My question is:

View File

@ -460,7 +460,8 @@
"swap": "Swap", "swap": "Swap",
"topics": "Topics", "topics": "Topics",
"warning": "Warning", "warning": "Warning",
"you": "You" "you": "You",
"i_know": "I know"
}, },
"docs": { "docs": {
"title": "Docs" "title": "Docs"
@ -2308,7 +2309,7 @@
}, },
"provider": "OCR Provider", "provider": "OCR Provider",
"provider_placeholder": "Choose an OCR provider", "provider_placeholder": "Choose an OCR provider",
"title": "OCR" "title": "OCR Settings"
}, },
"preprocess": { "preprocess": {
"provider": "Pre Process Provider", "provider": "Pre Process Provider",
@ -2557,7 +2558,8 @@
"please_select_embedding_model": "Please select an embedding model", "please_select_embedding_model": "Please select an embedding model",
"select_embedding_model_placeholder": "Select Embedding Model", "select_embedding_model_placeholder": "Select Embedding Model",
"embedding_dimensions": "Embedding Dimensions", "embedding_dimensions": "Embedding Dimensions",
"stored_memories": "Stored Memories" "stored_memories": "Stored Memories",
"global_memory_description": "To use memory features, please enable global memory in assistant settings."
} }
} }
} }

View File

@ -460,7 +460,8 @@
"swap": "交換", "swap": "交換",
"topics": "トピック", "topics": "トピック",
"warning": "警告", "warning": "警告",
"you": "あなた" "you": "あなた",
"i_know": "わかりました"
}, },
"docs": { "docs": {
"title": "ドキュメント" "title": "ドキュメント"
@ -2455,6 +2456,7 @@
"visualization": "可視化" "visualization": "可視化"
}, },
"memory": { "memory": {
"title": "グローバルメモリ",
"add_memory": "メモリーを追加", "add_memory": "メモリーを追加",
"edit_memory": "メモリーを編集", "edit_memory": "メモリーを編集",
"memory_content": "メモリー内容", "memory_content": "メモリー内容",
@ -2476,7 +2478,6 @@
"user": "ユーザー", "user": "ユーザー",
"content": "内容", "content": "内容",
"score": "スコア", "score": "スコア",
"title": "メモリー",
"memories_description": "{{total}}件中{{count}}件のメモリーを表示", "memories_description": "{{total}}件中{{count}}件のメモリーを表示",
"search_placeholder": "メモリーを検索...", "search_placeholder": "メモリーを検索...",
"start_date": "開始日", "start_date": "開始日",
@ -2557,7 +2558,8 @@
"please_select_embedding_model": "埋め込みモデルを選択してください", "please_select_embedding_model": "埋め込みモデルを選択してください",
"select_embedding_model_placeholder": "埋め込みモデルを選択", "select_embedding_model_placeholder": "埋め込みモデルを選択",
"embedding_dimensions": "埋め込み次元", "embedding_dimensions": "埋め込み次元",
"stored_memories": "保存された記憶" "stored_memories": "保存された記憶",
"global_memory_description": "メモリ機能を使用するには、アシスタント設定でグローバルメモリを有効にしてください。"
} }
} }
} }

View File

@ -460,7 +460,8 @@
"swap": "Поменять местами", "swap": "Поменять местами",
"topics": "Топики", "topics": "Топики",
"warning": "Предупреждение", "warning": "Предупреждение",
"you": "Вы" "you": "Вы",
"i_know": "Я понял"
}, },
"docs": { "docs": {
"title": "Документация" "title": "Документация"
@ -2455,6 +2456,7 @@
"visualization": "Визуализация" "visualization": "Визуализация"
}, },
"memory": { "memory": {
"title": "Глобальная память",
"add_memory": "Добавить память", "add_memory": "Добавить память",
"edit_memory": "Редактировать память", "edit_memory": "Редактировать память",
"memory_content": "Содержимое памяти", "memory_content": "Содержимое памяти",
@ -2531,7 +2533,6 @@
"total_memories": "всего воспоминаний", "total_memories": "всего воспоминаний",
"default": "По умолчанию", "default": "По умолчанию",
"custom": "Пользовательский", "custom": "Пользовательский",
"title": "Воспоминания",
"description": "Память позволяет хранить и управлять информацией о ваших взаимодействиях с ассистентом. Вы можете добавлять, редактировать и удалять воспоминания, а также фильтровать и искать их.", "description": "Память позволяет хранить и управлять информацией о ваших взаимодействиях с ассистентом. Вы можете добавлять, редактировать и удалять воспоминания, а также фильтровать и искать их.",
"global_memory_enabled": "Глобальная память включена", "global_memory_enabled": "Глобальная память включена",
"global_memory": "Глобальная память", "global_memory": "Глобальная память",
@ -2557,7 +2558,8 @@
"please_select_embedding_model": "Пожалуйста, выберите модель для внедрения", "please_select_embedding_model": "Пожалуйста, выберите модель для внедрения",
"select_embedding_model_placeholder": "Выберите модель внедрения", "select_embedding_model_placeholder": "Выберите модель внедрения",
"embedding_dimensions": "Размерность вложения", "embedding_dimensions": "Размерность вложения",
"stored_memories": "Запасённые воспоминания" "stored_memories": "Запасённые воспоминания",
"global_memory_description": "Для использования функций памяти необходимо включить глобальную память в настройках ассистента."
} }
} }
} }

View File

@ -460,7 +460,8 @@
"swap": "交换", "swap": "交换",
"topics": "话题", "topics": "话题",
"warning": "警告", "warning": "警告",
"you": "用户" "you": "用户",
"i_know": "我知道了"
}, },
"docs": { "docs": {
"title": "帮助文档" "title": "帮助文档"
@ -2308,7 +2309,7 @@
}, },
"provider": "OCR 服务商", "provider": "OCR 服务商",
"provider_placeholder": "选择一个 OCR 服务商", "provider_placeholder": "选择一个 OCR 服务商",
"title": "OCR" "title": "OCR 文字识别"
}, },
"preprocess": { "preprocess": {
"provider": "文档预处理服务商", "provider": "文档预处理服务商",
@ -2455,6 +2456,7 @@
"visualization": "可视化" "visualization": "可视化"
}, },
"memory": { "memory": {
"title": "全局记忆",
"settings": "设置", "settings": "设置",
"statistics": "统计", "statistics": "统计",
"search": "搜索", "search": "搜索",
@ -2464,8 +2466,8 @@
"memory_content": "记忆内容", "memory_content": "记忆内容",
"please_enter_memory": "请输入记忆内容", "please_enter_memory": "请输入记忆内容",
"memory_placeholder": "输入记忆内容...", "memory_placeholder": "输入记忆内容...",
"user_id": "用户ID", "user_id": "用户 ID",
"user_id_placeholder": "输入用户ID可选", "user_id_placeholder": "输入用户 ID可选",
"load_failed": "加载记忆失败", "load_failed": "加载记忆失败",
"add_success": "记忆添加成功", "add_success": "记忆添加成功",
"add_failed": "添加记忆失败", "add_failed": "添加记忆失败",
@ -2480,7 +2482,6 @@
"user": "用户", "user": "用户",
"content": "内容", "content": "内容",
"score": "分数", "score": "分数",
"title": "记忆",
"memories_description": "显示 {{count}} / {{total}} 条记忆", "memories_description": "显示 {{count}} / {{total}} 条记忆",
"search_placeholder": "搜索记忆...", "search_placeholder": "搜索记忆...",
"start_date": "开始日期", "start_date": "开始日期",
@ -2557,7 +2558,8 @@
"please_select_embedding_model": "请选择嵌入模型", "please_select_embedding_model": "请选择嵌入模型",
"select_embedding_model_placeholder": "选择嵌入模型", "select_embedding_model_placeholder": "选择嵌入模型",
"embedding_dimensions": "嵌入维度", "embedding_dimensions": "嵌入维度",
"stored_memories": "已存储记忆" "stored_memories": "已存储记忆",
"global_memory_description": "需要开启助手设置中的全局记忆才能使用"
} }
} }
} }

View File

@ -460,7 +460,8 @@
"swap": "交換", "swap": "交換",
"topics": "話題", "topics": "話題",
"warning": "警告", "warning": "警告",
"you": "您" "you": "您",
"i_know": "我知道了"
}, },
"docs": { "docs": {
"title": "說明文件" "title": "說明文件"
@ -2308,7 +2309,7 @@
}, },
"provider": "OCR 供應商", "provider": "OCR 供應商",
"provider_placeholder": "選擇一個OCR服務提供商", "provider_placeholder": "選擇一個OCR服務提供商",
"title": "光學字符識別" "title": "OCR 文字識別"
}, },
"preprocess": { "preprocess": {
"provider": "前置處理供應商", "provider": "前置處理供應商",
@ -2455,6 +2456,7 @@
"visualization": "視覺化" "visualization": "視覺化"
}, },
"memory": { "memory": {
"title": "全域記憶",
"add_memory": "新增記憶", "add_memory": "新增記憶",
"edit_memory": "編輯記憶", "edit_memory": "編輯記憶",
"memory_content": "記憶內容", "memory_content": "記憶內容",
@ -2476,7 +2478,6 @@
"user": "使用者", "user": "使用者",
"content": "內容", "content": "內容",
"score": "分數", "score": "分數",
"title": "記憶",
"memories_description": "顯示 {{count}} / {{total}} 條記憶", "memories_description": "顯示 {{count}} / {{total}} 條記憶",
"search_placeholder": "搜尋記憶...", "search_placeholder": "搜尋記憶...",
"start_date": "開始日期", "start_date": "開始日期",
@ -2557,7 +2558,8 @@
"please_select_embedding_model": "請選擇一個嵌入模型", "please_select_embedding_model": "請選擇一個嵌入模型",
"select_embedding_model_placeholder": "選擇嵌入模型", "select_embedding_model_placeholder": "選擇嵌入模型",
"embedding_dimensions": "嵌入維度", "embedding_dimensions": "嵌入維度",
"stored_memories": "儲存的記憶" "stored_memories": "儲存的記憶",
"global_memory_description": "需要開啟助手設定中的全域記憶才能使用"
} }
} }
} }

View File

@ -960,7 +960,7 @@ const InputBarContainer = styled.div`
border: 0.5px solid var(--color-border); border: 0.5px solid var(--color-border);
transition: all 0.2s ease; transition: all 0.2s ease;
position: relative; position: relative;
border-radius: 20px; border-radius: 17px;
padding-top: 8px; // 为拖动手柄留出空间 padding-top: 8px; // 为拖动手柄留出空间
background-color: var(--color-background-opacity); background-color: var(--color-background-opacity);

View File

@ -6,7 +6,7 @@ import { useKnowledge } from '@renderer/hooks/useKnowledge'
import FileItem from '@renderer/pages/files/FileItem' import FileItem from '@renderer/pages/files/FileItem'
import { getProviderName } from '@renderer/services/ProviderService' import { getProviderName } from '@renderer/services/ProviderService'
import { KnowledgeBase, KnowledgeItem } from '@renderer/types' import { KnowledgeBase, KnowledgeItem } from '@renderer/types'
import { Button, Dropdown, message, Tooltip } from 'antd' import { Button, Dropdown, Tooltip } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { Plus } from 'lucide-react' import { Plus } from 'lucide-react'
import { FC } from 'react' import { FC } from 'react'
@ -72,7 +72,7 @@ const KnowledgeUrls: FC<KnowledgeContentProps> = ({ selectedBase }) => {
if (!urlItems.find((item) => item.content === url.trim())) { if (!urlItems.find((item) => item.content === url.trim())) {
addUrl(url.trim()) addUrl(url.trim())
} else { } else {
message.success(t('knowledge.url_added')) window.message.success(t('knowledge.url_added'))
} }
} catch (e) { } catch (e) {
// Skip invalid URLs silently // Skip invalid URLs silently
@ -143,7 +143,7 @@ const KnowledgeUrls: FC<KnowledgeContentProps> = ({ selectedBase }) => {
label: t('common.copy'), label: t('common.copy'),
onClick: () => { onClick: () => {
navigator.clipboard.writeText(item.content as string) navigator.clipboard.writeText(item.content as string)
message.success(t('message.copied')) window.message.success(t('message.copied'))
} }
} }
] ]

View File

@ -539,8 +539,6 @@ const MemoriesPage = () => {
title: t('memory.delete_user_confirm_title'), title: t('memory.delete_user_confirm_title'),
content: t('memory.delete_user_confirm_content', { user: userId }), content: t('memory.delete_user_confirm_content', { user: userId }),
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
okText: t('common.yes'),
cancelText: t('common.no'),
okType: 'danger', okType: 'danger',
onOk: async () => { onOk: async () => {
try { try {

View File

@ -1,10 +1,11 @@
import { InfoCircleOutlined, SettingOutlined } from '@ant-design/icons' import { InfoCircleOutlined } from '@ant-design/icons'
import { Box } from '@renderer/components/Layout' import { Box } from '@renderer/components/Layout'
import MemoryService from '@renderer/services/MemoryService' import MemoryService from '@renderer/services/MemoryService'
import { selectGlobalMemoryEnabled, selectMemoryConfig } from '@renderer/store/memory' import { selectGlobalMemoryEnabled, selectMemoryConfig } from '@renderer/store/memory'
import { Assistant, AssistantSettings } from '@renderer/types' import { Assistant, AssistantSettings } from '@renderer/types'
import { Alert, Button, Card, Space, Switch, Tooltip, Typography } from 'antd' import { Alert, Button, Card, Space, Switch, Tooltip, Typography } from 'antd'
import { useForm } from 'antd/es/form/Form' import { useForm } from 'antd/es/form/Form'
import { Settings2 } from 'lucide-react'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -78,9 +79,7 @@ const AssistantMemorySettings: React.FC<Props> = ({ assistant, updateAssistant,
</Tooltip> </Tooltip>
</Box> </Box>
<Space> <Space>
<Button size="small" icon={<SettingOutlined />} onClick={handleNavigateToMemory}> <Button type="text" icon={<Settings2 size={15} />} onClick={handleNavigateToMemory} />
{t('common.settings')}
</Button>
<Tooltip <Tooltip
title={ title={
!globalMemoryEnabled !globalMemoryEnabled

View File

@ -6,16 +6,18 @@ import {
MoreOutlined, MoreOutlined,
PlusOutlined, PlusOutlined,
ReloadOutlined, ReloadOutlined,
SettingOutlined,
UserAddOutlined, UserAddOutlined,
UserDeleteOutlined, UserDeleteOutlined,
UserOutlined UserOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { useModel } from '@renderer/hooks/useModel'
import MemoryService from '@renderer/services/MemoryService' import MemoryService from '@renderer/services/MemoryService'
import { import {
selectCurrentUserId, selectCurrentUserId,
selectGlobalMemoryEnabled, selectGlobalMemoryEnabled,
selectMemoryConfig,
setCurrentUserId, setCurrentUserId,
setGlobalMemoryEnabled setGlobalMemoryEnabled
} from '@renderer/store/memory' } from '@renderer/store/memory'
@ -37,7 +39,7 @@ import {
} from 'antd' } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { Brain } from 'lucide-react' import { Brain, Settings2 } from 'lucide-react'
import { useCallback, useEffect, useMemo, useState } from 'react' import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
@ -123,10 +125,7 @@ const AddMemoryModal: React.FC<AddMemoryModalProps> = ({ visible, onCancel, onAd
} }
}}> }}>
<Form form={form} layout="vertical" onFinish={handleSubmit}> <Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item <Form.Item name="memory" rules={[{ required: true, message: t('memory.please_enter_memory') }]}>
label={t('memory.memory_content')}
name="memory"
rules={[{ required: true, message: t('memory.please_enter_memory') }]}>
<TextArea <TextArea
rows={5} rows={5}
placeholder={t('memory.memory_placeholder')} placeholder={t('memory.memory_placeholder')}
@ -502,11 +501,16 @@ const MemorySettings = () => {
const handleSettingsSubmit = async () => { const handleSettingsSubmit = async () => {
setSettingsModalVisible(false) setSettingsModalVisible(false)
await memoryService.updateConfig() await memoryService.updateConfig()
if (window.keyv.get('memory.wait.settings')) {
window.keyv.remove('memory.wait.settings')
dispatch(setGlobalMemoryEnabled(true))
}
} }
const handleSettingsCancel = () => { const handleSettingsCancel = () => {
setSettingsModalVisible(false) setSettingsModalVisible(false)
form.resetFields() form.resetFields()
window.keyv.remove('memory.wait.settings')
} }
const handleResetMemories = async (userId: string) => { const handleResetMemories = async (userId: string) => {
@ -544,8 +548,6 @@ const MemorySettings = () => {
title: t('memory.delete_user_confirm_title'), title: t('memory.delete_user_confirm_title'),
content: t('memory.delete_user_confirm_content', { user: userId }), content: t('memory.delete_user_confirm_content', { user: userId }),
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
okText: t('common.yes'),
cancelText: t('common.no'),
okType: 'danger', okType: 'danger',
onOk: async () => { onOk: async () => {
try { try {
@ -569,9 +571,32 @@ const MemorySettings = () => {
}) })
} }
const handleGlobalMemoryToggle = (enabled: boolean) => { const memoryConfig = useSelector(selectMemoryConfig)
const embedderModel = useModel(memoryConfig.embedderApiClient?.model, memoryConfig.embedderApiClient?.provider)
const handleGlobalMemoryToggle = async (enabled: boolean) => {
if (enabled && !embedderModel) {
window.keyv.set('memory.wait.settings', true)
return setSettingsModalVisible(true)
}
dispatch(setGlobalMemoryEnabled(enabled)) dispatch(setGlobalMemoryEnabled(enabled))
window.message.success(enabled ? t('memory.global_memory_enabled') : t('memory.global_memory_disabled_title'))
if (enabled) {
return window.modal.confirm({
centered: true,
title: t('memory.global_memory_enabled'),
content: t('memory.global_memory_description'),
okText: t('common.i_know'),
cancelButtonProps: {
style: {
display: 'none'
}
}
})
}
window.message.success(t('memory.global_memory_disabled_title'))
} }
const { theme } = useTheme() const { theme } = useTheme()
@ -579,33 +604,27 @@ const MemorySettings = () => {
return ( return (
<SettingContainer theme={theme}> <SettingContainer theme={theme}>
{/* Memory Settings */} {/* Memory Settings */}
<SettingGroup theme={theme}> <SettingGroup style={{ justifyContent: 'space-between', alignItems: 'center' }} theme={theme}>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '2px' }}> <HStack style={{ justifyContent: 'space-between', alignItems: 'center' }}>
<SettingTitle>{t('memory.settings')}</SettingTitle> <HStack style={{ alignItems: 'center', gap: '2px' }}>
<span <SettingRowTitle>{t('memory.global_memory')}</SettingRowTitle>
style={{ <span
fontSize: '12px', style={{
color: 'var(--color-primary)', fontSize: '12px',
background: 'var(--color-primary-bg)', color: 'var(--color-primary)',
padding: '2px 6px', background: 'var(--color-primary-bg)',
borderRadius: '4px', padding: '2px 6px',
fontWeight: '500' borderRadius: '4px',
}}> fontWeight: '500'
Beta }}>
</span> Beta
</div> </span>
<SettingDivider /> </HStack>
<SettingRow> <HStack style={{ alignItems: 'center', gap: 10 }}>
<SettingRowTitle>{t('memory.global_memory')}</SettingRowTitle> <Switch checked={globalMemoryEnabled} onChange={handleGlobalMemoryToggle} />
<Switch checked={globalMemoryEnabled} onChange={handleGlobalMemoryToggle} /> <Button icon={<Settings2 size={16} />} onClick={() => setSettingsModalVisible(true)} />
</SettingRow> </HStack>
<SettingDivider /> </HStack>
<SettingRow>
<SettingRowTitle>{t('memory.settings')}</SettingRowTitle>
<Button icon={<SettingOutlined />} onClick={() => setSettingsModalVisible(true)}>
{t('common.settings')}
</Button>
</SettingRow>
</SettingGroup> </SettingGroup>
{/* User Management */} {/* User Management */}
@ -636,32 +655,32 @@ const MemorySettings = () => {
alignItems: 'center', alignItems: 'center',
justifyContent: 'flex-start' justifyContent: 'flex-start'
}}> }}>
<Space align="center"> <HStack alignItems="center" gap={10}>
<UserAddOutlined /> <UserAddOutlined />
<span>{t('memory.add_new_user')}</span> <span>{t('memory.add_new_user')}</span>
</Space> </HStack>
</Button> </Button>
</div> </div>
</> </>
)}> )}>
<Option value={DEFAULT_USER_ID}> <Option value={DEFAULT_USER_ID}>
<Space align="center"> <HStack alignItems="center" gap={10}>
<Avatar size={20} style={{ background: 'var(--color-primary)' }}> <Avatar size={20} style={{ background: 'var(--color-primary)' }}>
{getUserAvatar(DEFAULT_USER_ID)} {getUserAvatar(DEFAULT_USER_ID)}
</Avatar> </Avatar>
<span>{t('memory.default_user')}</span> <span>{t('memory.default_user')}</span>
</Space> </HStack>
</Option> </Option>
{uniqueUsers {uniqueUsers
.filter((user) => user !== DEFAULT_USER_ID) .filter((user) => user !== DEFAULT_USER_ID)
.map((user) => ( .map((user) => (
<Option key={user} value={user}> <Option key={user} value={user}>
<Space align="center"> <HStack alignItems="center" gap={10}>
<Avatar size={20} style={{ background: 'var(--color-primary)' }}> <Avatar size={20} style={{ background: 'var(--color-primary)' }}>
{getUserAvatar(user)} {getUserAvatar(user)}
</Avatar> </Avatar>
<span>{user}</span> <span>{user}</span>
</Space> </HStack>
</Option> </Option>
))} ))}
</Select> </Select>
@ -736,7 +755,8 @@ const MemorySettings = () => {
</Dropdown> </Dropdown>
</Space> </Space>
</div> </div>
<SettingDivider />
<SettingDivider style={{ marginBottom: 15 }} />
{/* Memory Content Area */} {/* Memory Content Area */}
<div style={{ minHeight: 400 }}> <div style={{ minHeight: 400 }}>
@ -867,7 +887,7 @@ const MemorySettings = () => {
const MemoryListContainer = styled.div` const MemoryListContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 15px;
max-height: 500px; max-height: 500px;
overflow-y: auto; overflow-y: auto;
` `
@ -876,7 +896,7 @@ const MemoryItem = styled.div`
padding: 12px; padding: 12px;
background: var(--color-background-soft); background: var(--color-background-soft);
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
border-radius: var(--list-item-border-radius); border-radius: 10px;
transition: all 0.2s ease; transition: all 0.2s ease;
&:hover { &:hover {

View File

@ -590,7 +590,7 @@ const TranslatePage: FC = () => {
<ContentContainer id="content-container" ref={contentContainerRef} $historyDrawerVisible={historyDrawerVisible}> <ContentContainer id="content-container" ref={contentContainerRef} $historyDrawerVisible={historyDrawerVisible}>
<HistoryContainer $historyDrawerVisible={historyDrawerVisible}> <HistoryContainer $historyDrawerVisible={historyDrawerVisible}>
<OperationBar> <OperationBar>
<span style={{ fontSize: 16 }}>{t('translate.history.title')}</span> <span style={{ fontSize: 14 }}>{t('translate.history.title')}</span>
{!isEmpty(translateHistory) && ( {!isEmpty(translateHistory) && (
<Popconfirm <Popconfirm
title={t('translate.history.clear')} title={t('translate.history.clear')}
@ -623,13 +623,8 @@ const TranslatePage: FC = () => {
<Flex justify="space-between" vertical gap={4} style={{ width: '100%' }}> <Flex justify="space-between" vertical gap={4} style={{ width: '100%' }}>
<Flex align="center" justify="space-between" style={{ flex: 1 }}> <Flex align="center" justify="space-between" style={{ flex: 1 }}>
<Flex align="center" gap={6}> <Flex align="center" gap={6}>
<span> <HistoryListItemLanguage>{item._sourceLanguage.label()} </HistoryListItemLanguage>
{item._sourceLanguage.emoji} {item._sourceLanguage.label()} <HistoryListItemLanguage>{item._targetLanguage.label()}</HistoryListItemLanguage>
</span>
<span>
{item._targetLanguage.emoji} {item._targetLanguage.label()}
</span>
</Flex> </Flex>
<HistoryListItemDate>{dayjs(item.createdAt).format('MM/DD HH:mm')}</HistoryListItemDate> <HistoryListItemDate>{dayjs(item.createdAt).format('MM/DD HH:mm')}</HistoryListItemDate>
</Flex> </Flex>
@ -933,4 +928,9 @@ const HistoryListItemDate = styled.div`
color: var(--color-text-3); color: var(--color-text-3);
` `
const HistoryListItemLanguage = styled.div`
font-size: 12px;
color: var(--color-text-3);
`
export default TranslatePage export default TranslatePage