diff --git a/.yarn/patches/antd-npm-5.24.7-356a553ae5.patch b/.yarn/patches/antd-npm-5.26.7-029c5c381a.patch similarity index 69% rename from .yarn/patches/antd-npm-5.24.7-356a553ae5.patch rename to .yarn/patches/antd-npm-5.26.7-029c5c381a.patch index d5f7a89ed..601394efb 100644 --- a/.yarn/patches/antd-npm-5.24.7-356a553ae5.patch +++ b/.yarn/patches/antd-npm-5.26.7-029c5c381a.patch @@ -1,5 +1,5 @@ diff --git a/es/dropdown/dropdown.js b/es/dropdown/dropdown.js -index 986877a762b9ad0aca596a8552732cd12d2eaabb..1f18aa2ea745e68950e4cee16d4d655f5c835fd5 100644 +index 2e45574398ff68450022a0078e213cc81fe7454e..58ba7789939b7805a89f92b93d222f8fb1168bdf 100644 --- a/es/dropdown/dropdown.js +++ b/es/dropdown/dropdown.js @@ -2,7 +2,7 @@ @@ -11,7 +11,7 @@ index 986877a762b9ad0aca596a8552732cd12d2eaabb..1f18aa2ea745e68950e4cee16d4d655f import classNames from 'classnames'; import RcDropdown from 'rc-dropdown'; import useEvent from "rc-util/es/hooks/useEvent"; -@@ -158,8 +158,10 @@ const Dropdown = props => { +@@ -160,8 +160,10 @@ const Dropdown = props => { className: `${prefixCls}-menu-submenu-arrow` }, direction === 'rtl' ? (/*#__PURE__*/React.createElement(LeftOutlined, { className: `${prefixCls}-menu-submenu-arrow-icon` @@ -24,22 +24,8 @@ index 986877a762b9ad0aca596a8552732cd12d2eaabb..1f18aa2ea745e68950e4cee16d4d655f }))), mode: "vertical", selectable: false, -diff --git a/es/dropdown/style/index.js b/es/dropdown/style/index.js -index 768c01783002c6901c85a73061ff6b3e776a60ce..39b1b95a56cdc9fb586a193c3adad5141f5cf213 100644 ---- a/es/dropdown/style/index.js -+++ b/es/dropdown/style/index.js -@@ -240,7 +240,8 @@ const genBaseStyle = token => { - marginInlineEnd: '0 !important', - color: token.colorTextDescription, - fontSize: fontSizeIcon, -- fontStyle: 'normal' -+ fontStyle: 'normal', -+ marginTop: 3, - } - } - }), diff --git a/es/select/useIcons.js b/es/select/useIcons.js -index 959115be936ef8901548af2658c5dcfdc5852723..c812edd52123eb0faf4638b1154fcfa1b05b513b 100644 +index 572aaaa0899f429cbf8a7181f2eeada545f76dcb..4e175c8d7713dd6422f8bcdc74ee671a835de6ce 100644 --- a/es/select/useIcons.js +++ b/es/select/useIcons.js @@ -4,10 +4,10 @@ import * as React from 'react'; @@ -51,10 +37,10 @@ index 959115be936ef8901548af2658c5dcfdc5852723..c812edd52123eb0faf4638b1154fcfa1 import SearchOutlined from "@ant-design/icons/es/icons/SearchOutlined"; import { devUseWarning } from '../_util/warning'; +import { ChevronDown } from 'lucide-react'; - export default function useIcons(_ref) { - let { - suffixIcon, -@@ -56,8 +56,10 @@ export default function useIcons(_ref) { + export default function useIcons({ + suffixIcon, + clearIcon, +@@ -54,8 +54,10 @@ export default function useIcons({ className: iconCls })); } diff --git a/package.json b/package.json index 28561231b..cac7e8cb2 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "@viz-js/lang-dot": "^1.0.5", "@viz-js/viz": "^3.14.0", "@xyflow/react": "^12.4.4", - "antd": "patch:antd@npm%3A5.24.7#~/.yarn/patches/antd-npm-5.24.7-356a553ae5.patch", + "antd": "patch:antd@npm%3A5.26.7#~/.yarn/patches/antd-npm-5.26.7-029c5c381a.patch", "archiver": "^7.0.1", "async-mutex": "^0.5.0", "axios": "^1.7.3", diff --git a/src/renderer/src/assets/styles/ant.scss b/src/renderer/src/assets/styles/ant.scss index d89e3d1d3..7a2a2ce27 100644 --- a/src/renderer/src/assets/styles/ant.scss +++ b/src/renderer/src/assets/styles/ant.scss @@ -12,6 +12,13 @@ outline: none; } +// Align lucide icon in Button +.ant-btn .ant-btn-icon { + display: inline-flex; + align-items: center; + justify-content: center; +} + .ant-tabs-tabpane:focus-visible { outline: none; } @@ -84,6 +91,14 @@ max-height: 50vh; overflow-y: auto; border: 0.5px solid var(--color-border); + + // Align lucide icon in dropdown menu item extra + .ant-dropdown-menu-submenu-expand-icon, + .ant-dropdown-menu-item-extra { + display: inline-flex; + align-items: center; + justify-content: center; + } } .ant-dropdown-arrow + .ant-dropdown-menu { border: none; @@ -96,6 +111,10 @@ background-color: var(--ant-color-bg-elevated); overflow: hidden; border-radius: var(--ant-border-radius-lg); + + .ant-dropdown-menu-submenu-title { + align-items: center; + } } .ant-popover { diff --git a/src/renderer/src/assets/styles/color.scss b/src/renderer/src/assets/styles/color.scss index b0549dd8e..1cb7d030b 100644 --- a/src/renderer/src/assets/styles/color.scss +++ b/src/renderer/src/assets/styles/color.scss @@ -32,7 +32,7 @@ --color-border: #ffffff19; --color-border-soft: #ffffff10; --color-border-mute: #ffffff05; - --color-error: #f44336; + --color-error: #ff4d50; --color-link: #338cff; --color-code-background: #323232; --color-hover: rgba(40, 40, 40, 1); @@ -73,8 +73,8 @@ --list-item-border-radius: 10px; - --color-status-success: #52c41a; - --color-status-error: #ff4d4f; + --color-status-success: green; + --color-status-error: var(--color-error); --color-status-warning: #faad14; } @@ -112,7 +112,7 @@ --color-border: #00000019; --color-border-soft: #00000010; --color-border-mute: #00000005; - --color-error: #f44336; + --color-error: #ff4d50; --color-link: #1677ff; --color-code-background: #e3e3e3; --color-hover: var(--color-white-mute); diff --git a/src/renderer/src/components/CodeBlockView/GraphvizPreview.tsx b/src/renderer/src/components/CodeBlockView/GraphvizPreview.tsx index 452ed1261..48b45bf87 100644 --- a/src/renderer/src/components/CodeBlockView/GraphvizPreview.tsx +++ b/src/renderer/src/components/CodeBlockView/GraphvizPreview.tsx @@ -1,5 +1,5 @@ import { usePreviewToolHandlers, usePreviewTools } from '@renderer/components/CodeToolbar' -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon } from '@renderer/components/Icons' import { AsyncInitializer } from '@renderer/utils/asyncInitializer' import { Flex, Spin } from 'antd' import { debounce } from 'lodash' @@ -86,7 +86,7 @@ const GraphvizPreview: React.FC = ({ children, setTools }) => }, [children, debouncedRender]) return ( - }> + }> {error && {error}} diff --git a/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx b/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx index e636b57e7..b57c4a68a 100644 --- a/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx +++ b/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx @@ -1,6 +1,6 @@ import { nanoid } from '@reduxjs/toolkit' import { usePreviewToolHandlers, usePreviewTools } from '@renderer/components/CodeToolbar' -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon } from '@renderer/components/Icons' import { useMermaid } from '@renderer/hooks/useMermaid' import { Flex, Spin } from 'antd' import { debounce } from 'lodash' @@ -139,7 +139,7 @@ const MermaidPreview: React.FC = ({ children, setTools }) => const isLoading = isLoadingMermaid || isRendering return ( - }> + }> {(mermaidError || error) && {mermaidError || error}} diff --git a/src/renderer/src/components/CodeBlockView/view.tsx b/src/renderer/src/components/CodeBlockView/view.tsx index 4d70cbd32..4a844b7b3 100644 --- a/src/renderer/src/components/CodeBlockView/view.tsx +++ b/src/renderer/src/components/CodeBlockView/view.tsx @@ -1,7 +1,7 @@ -import { LoadingOutlined } from '@ant-design/icons' import { loggerService } from '@logger' import CodeEditor from '@renderer/components/CodeEditor' import { CodeTool, CodeToolbar, TOOL_SPECS, useCodeTool } from '@renderer/components/CodeToolbar' +import { LoadingIcon } from '@renderer/components/Icons' import { useSettings } from '@renderer/hooks/useSettings' import { pyodideService } from '@renderer/services/PyodideService' import { extractTitle } from '@renderer/utils/formats' @@ -173,7 +173,7 @@ export const CodeBlockView: React.FC = memo(({ children, language, onSave registerTool({ ...TOOL_SPECS.run, - icon: isRunning ? : , + icon: isRunning ? : , tooltip: t('code_block.run'), onClick: () => !isRunning && handleRunScript() }) diff --git a/src/renderer/src/components/Icons/CopyIcon.tsx b/src/renderer/src/components/Icons/CopyIcon.tsx index 20a91db47..157f1829a 100644 --- a/src/renderer/src/components/Icons/CopyIcon.tsx +++ b/src/renderer/src/components/Icons/CopyIcon.tsx @@ -1,7 +1,5 @@ -import { FC } from 'react' +import { Copy } from 'lucide-react' -const CopyIcon: FC, HTMLElement>> = (props) => { - return -} +const CopyIcon = (props: React.ComponentProps) => export default CopyIcon diff --git a/src/renderer/src/components/Icons/DeleteIcon.tsx b/src/renderer/src/components/Icons/DeleteIcon.tsx new file mode 100644 index 000000000..a2748f43f --- /dev/null +++ b/src/renderer/src/components/Icons/DeleteIcon.tsx @@ -0,0 +1,5 @@ +import { Trash } from 'lucide-react' + +const DeleteIcon = (props: React.ComponentProps) => + +export default DeleteIcon diff --git a/src/renderer/src/components/Icons/EditIcon.tsx b/src/renderer/src/components/Icons/EditIcon.tsx new file mode 100644 index 000000000..37eab8ce6 --- /dev/null +++ b/src/renderer/src/components/Icons/EditIcon.tsx @@ -0,0 +1,5 @@ +import { Pencil } from 'lucide-react' + +const EditIcon = (props: React.ComponentProps) => + +export default EditIcon diff --git a/src/renderer/src/components/Icons/RefreshIcon.tsx b/src/renderer/src/components/Icons/RefreshIcon.tsx new file mode 100644 index 000000000..71e98355d --- /dev/null +++ b/src/renderer/src/components/Icons/RefreshIcon.tsx @@ -0,0 +1,5 @@ +import { RefreshCw } from 'lucide-react' + +const RefreshIcon = (props: React.ComponentProps) => + +export default RefreshIcon diff --git a/src/renderer/src/components/Icons/ResetIcon.tsx b/src/renderer/src/components/Icons/ResetIcon.tsx new file mode 100644 index 000000000..683e897aa --- /dev/null +++ b/src/renderer/src/components/Icons/ResetIcon.tsx @@ -0,0 +1,5 @@ +import { RotateCcw } from 'lucide-react' + +const ResetIcon = (props: React.ComponentProps) => + +export default ResetIcon diff --git a/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx b/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx index 11a25a48e..355b6cd9c 100644 --- a/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx +++ b/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx @@ -1,6 +1,7 @@ import { SVGProps } from 'react' -export function SvgSpinners180Ring(props: SVGProps) { +export function SvgSpinners180Ring(props: SVGProps & { size?: number | string }) { + const { size = '1em', ...svgProps } = props // 避免与全局样式冲突 const animationClassName = 'svg-spinner-anim-180-ring' @@ -25,11 +26,11 @@ export function SvgSpinners180Ring(props: SVGProps) { + {...svgProps} + className={`${animationClassName} ${svgProps.className || ''}`.trim()}> {/* Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE */} { - it('should match snapshot with props and className', () => { - const onClick = vi.fn() - const { container } = render( - - ) - - expect(container.firstChild).toMatchSnapshot() - }) -}) diff --git a/src/renderer/src/components/Icons/__tests__/__snapshots__/CopyIcon.test.tsx.snap b/src/renderer/src/components/Icons/__tests__/__snapshots__/CopyIcon.test.tsx.snap deleted file mode 100644 index d333ca457..000000000 --- a/src/renderer/src/components/Icons/__tests__/__snapshots__/CopyIcon.test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`CopyIcon > should match snapshot with props and className 1`] = ` - -`; diff --git a/src/renderer/src/components/Icons/index.ts b/src/renderer/src/components/Icons/index.ts new file mode 100644 index 000000000..cc6f4c2b6 --- /dev/null +++ b/src/renderer/src/components/Icons/index.ts @@ -0,0 +1,19 @@ +export { default as CopyIcon } from './CopyIcon' +export { default as DeleteIcon } from './DeleteIcon' +export * from './DownloadIcons' +export { default as EditIcon } from './EditIcon' +export { default as FallbackFavicon } from './FallbackFavicon' +export { default as MinAppIcon } from './MinAppIcon' +export * from './NutstoreIcons' +export { default as OcrIcon } from './OcrIcon' +export { default as ReasoningIcon } from './ReasoningIcon' +export { default as RefreshIcon } from './RefreshIcon' +export { default as ResetIcon } from './ResetIcon' +export * from './SVGIcon' +export { default as LoadingIcon } from './SvgSpinners180Ring' +export { default as ToolIcon } from './ToolIcon' +export { default as ToolsCallingIcon } from './ToolsCallingIcon' +export { default as UnWrapIcon } from './UnWrapIcon' +export { default as VisionIcon } from './VisionIcon' +export { default as WebSearchIcon } from './WebSearchIcon' +export { default as WrapIcon } from './WrapIcon' diff --git a/src/renderer/src/components/InfoTooltip.tsx b/src/renderer/src/components/InfoTooltip.tsx index e1d850a8b..02c64c4d2 100644 --- a/src/renderer/src/components/InfoTooltip.tsx +++ b/src/renderer/src/components/InfoTooltip.tsx @@ -1,17 +1,18 @@ -import { InfoCircleOutlined } from '@ant-design/icons' import { Tooltip, TooltipProps } from 'antd' +import { Info } from 'lucide-react' type InheritedTooltipProps = Omit interface InfoTooltipProps extends InheritedTooltipProps { iconColor?: string + iconSize?: string | number iconStyle?: React.CSSProperties } -const InfoTooltip = ({ iconColor = 'var(--color-text-3)', iconStyle, ...rest }: InfoTooltipProps) => { +const InfoTooltip = ({ iconColor = 'var(--color-text-3)', iconSize = 14, iconStyle, ...rest }: InfoTooltipProps) => { return ( - + ) } diff --git a/src/renderer/src/components/InputEmbeddingDimension.tsx b/src/renderer/src/components/InputEmbeddingDimension.tsx index f70c0222b..12cb941ea 100644 --- a/src/renderer/src/components/InputEmbeddingDimension.tsx +++ b/src/renderer/src/components/InputEmbeddingDimension.tsx @@ -1,10 +1,10 @@ import { loggerService } from '@logger' import AiProvider from '@renderer/aiCore' +import { RefreshIcon } from '@renderer/components/Icons' import { useProvider } from '@renderer/hooks/useProvider' import { Model } from '@renderer/types' import { getErrorMessage } from '@renderer/utils' import { Button, InputNumber, Space, Tooltip } from 'antd' -import { RefreshCw } from 'lucide-react' import { memo, useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -77,7 +77,7 @@ const InputEmbeddingDimension = ({ @@ -210,7 +211,7 @@ const ModelEditContent: FC = ({ provider, model, onUpdate style={{ color: 'var(--color-text-3)' }}> {t('settings.moresetting.label')} - diff --git a/src/renderer/src/components/ModelList/ModelList.tsx b/src/renderer/src/components/ModelList/ModelList.tsx index 133c1e436..c5e160a41 100644 --- a/src/renderer/src/components/ModelList/ModelList.tsx +++ b/src/renderer/src/components/ModelList/ModelList.tsx @@ -1,7 +1,6 @@ import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar' import CustomTag from '@renderer/components/CustomTag' -import { StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons/SVGIcon' -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon, StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons' import { HStack } from '@renderer/components/Layout' import AddModelPopup from '@renderer/components/ModelList/AddModelPopup' import EditModelPopup from '@renderer/components/ModelList/EditModelPopup' @@ -160,7 +159,7 @@ const ModelList: React.FC = ({ providerId }) => { - }> + }> {displayedModelGroups && !isEmpty(displayedModelGroups) ? ( {Object.keys(displayedModelGroups).map((group, i) => ( diff --git a/src/renderer/src/components/ModelList/ModelListItem.tsx b/src/renderer/src/components/ModelList/ModelListItem.tsx index da0059b78..7955f8eaf 100644 --- a/src/renderer/src/components/ModelList/ModelListItem.tsx +++ b/src/renderer/src/components/ModelList/ModelListItem.tsx @@ -1,4 +1,5 @@ import { type HealthResult, HealthStatusIndicator } from '@renderer/components/HealthStatusIndicator' +import { EditIcon } from '@renderer/components/Icons' import { HStack } from '@renderer/components/Layout' import ModelIdWithTags from '@renderer/components/ModelIdWithTags' import { getModelLogo } from '@renderer/config/models' @@ -6,7 +7,7 @@ import { Model } from '@renderer/types' import { ModelWithStatus } from '@renderer/types/healthCheck' import { maskApiKey } from '@renderer/utils/api' import { Avatar, Button, Tooltip } from 'antd' -import { Minus, Pen } from 'lucide-react' +import { Minus } from 'lucide-react' import React, { memo } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -51,7 +52,7 @@ const ModelListItem: React.FC = ({ ref, model, modelStatus, - + ) + + const MockTooltip: React.FC> = ({ children, title }) => ( +
+ {children} +
+ ) + + return { + Button: MockButton, + InputNumber: MockInputNumber, + Space: { Compact: MockSpaceCompact }, + Tooltip: MockTooltip + } }) // Mock dependencies @@ -46,20 +90,10 @@ vi.mock('react-i18next', () => ({ } })) -// Mock logger -vi.mock('@logger', () => ({ - loggerService: { - withContext: () => ({ - warn: vi.fn(), - error: vi.fn() - }) - } -})) - -vi.mock('lucide-react', () => ({ - RefreshCw: (props: React.SVGProps) => ( +vi.mock('@renderer/components/Icons', () => ({ + RefreshIcon: (props: React.SVGProps) => ( - RefreshCw + RefreshIcon ) })) @@ -119,13 +153,11 @@ describe('InputEmbeddingDimension', () => { describe('functionality', () => { it('should call onChange when input value changes', async () => { const handleChange = vi.fn() - const user = userEvent.setup() render() const input = screen.getByPlaceholderText('请输入维度大小') - await user.clear(input) - await user.type(input, '2048') + fireEvent.change(input, { target: { value: '2048' } }) expect(handleChange).toHaveBeenCalledWith(2048) }) @@ -182,7 +214,6 @@ describe('InputEmbeddingDimension', () => { it('should handle null value correctly', async () => { const handleChange = vi.fn() - const user = userEvent.setup() render() @@ -190,7 +221,7 @@ describe('InputEmbeddingDimension', () => { expect(input.value).toBe('') // Should allow typing new value - await user.type(input, '1024') + fireEvent.change(input, { target: { value: '1024' } }) expect(handleChange).toHaveBeenCalledWith(1024) }) }) diff --git a/src/renderer/src/components/__tests__/__snapshots__/InfoTooltip.test.tsx.snap b/src/renderer/src/components/__tests__/__snapshots__/InfoTooltip.test.tsx.snap index 68f5589cd..f6eafa2c8 100644 --- a/src/renderer/src/components/__tests__/__snapshots__/InfoTooltip.test.tsx.snap +++ b/src/renderer/src/components/__tests__/__snapshots__/InfoTooltip.test.tsx.snap @@ -1,28 +1,18 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`InfoTooltip > should match snapshot 1`] = ` - -
- - - - + Info +
+
+ Test tooltip +
+ `; diff --git a/src/renderer/src/components/__tests__/__snapshots__/InputEmbeddingDimension.test.tsx.snap b/src/renderer/src/components/__tests__/__snapshots__/InputEmbeddingDimension.test.tsx.snap index b663328a9..9a29f4f2c 100644 --- a/src/renderer/src/components/__tests__/__snapshots__/InputEmbeddingDimension.test.tsx.snap +++ b/src/renderer/src/components/__tests__/__snapshots__/InputEmbeddingDimension.test.tsx.snap @@ -2,95 +2,24 @@ exports[`InputEmbeddingDimension > basic rendering > should match snapshot with all props 1`] = `
-
+
-
- - - - - - - - - - -
-
- -
-
- + +
`; exports[`InputEmbeddingDimension > basic rendering > should match snapshot with loading state 1`] = `
-
+
-
- - - - - - - - - - -
-
- -
+ Loading... +
-
`; diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 74b9bc9ac..4829ea49c 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -596,7 +596,7 @@ "list": "Topic List", "move_to": "Move to", "new": "New Topic", - "pinned": "Pinned Topics", + "pin": "Pin Topic", "prompt": { "edit": { "title": "Edit Topic Prompts" @@ -605,7 +605,7 @@ "tips": "Topic Prompts: Additional supplementary prompts provided for the current topic" }, "title": "Topics", - "unpinned": "Unpinned Topics" + "unpin": "Unpin Topic" }, "translate": "Translate" }, @@ -1552,6 +1552,7 @@ "mode": { "edit": "Edit", "generate": "Draw", + "merge": "Merge", "remix": "Remix", "upscale": "Upscale" }, diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 41883baf4..b57fc3d26 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -596,7 +596,7 @@ "list": "トピックリスト", "move_to": "移動先", "new": "新しいトピック", - "pinned": "トピックを固定", + "pin": "トピックを固定", "prompt": { "edit": { "title": "トピック提示語を編集する" @@ -605,7 +605,7 @@ "tips": "トピック提示語:現在のトピックに対して追加の補足提示語を提供" }, "title": "トピック", - "unpinned": "固定解除" + "unpin": "固定解除" }, "translate": "翻訳" }, @@ -1552,6 +1552,7 @@ "mode": { "edit": "部分編集", "generate": "画像生成", + "merge": "マージ", "remix": "混合", "upscale": "拡大" }, diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 9b1441fe4..6d8cdfdec 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -596,7 +596,7 @@ "list": "Список топиков", "move_to": "Переместить в", "new": "Новый топик", - "pinned": "Закрепленные темы", + "pin": "Закрепленные темы", "prompt": { "edit": { "title": "Редактировать подсказки темы" @@ -605,7 +605,7 @@ "tips": "Тематические подсказки: Дополнительные подсказки, предоставленные для текущей темы" }, "title": "Топики", - "unpinned": "Открепленные темы" + "unpin": "Открепленные темы" }, "translate": "Перевести" }, @@ -1552,6 +1552,7 @@ "mode": { "edit": "Редактирование", "generate": "Рисование", + "merge": "Слияние", "remix": "Смешивание", "upscale": "Увеличение" }, diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 2148b168c..8d5f7e053 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -596,7 +596,7 @@ "list": "话题列表", "move_to": "移动到", "new": "开始新对话", - "pinned": "固定话题", + "pin": "固定话题", "prompt": { "edit": { "title": "编辑话题提示词" @@ -605,7 +605,7 @@ "tips": "话题提示词:针对当前话题提供额外的补充提示词" }, "title": "话题", - "unpinned": "取消固定" + "unpin": "取消固定" }, "translate": "翻译" }, @@ -1552,6 +1552,7 @@ "mode": { "edit": "编辑", "generate": "绘图", + "merge": "合并", "remix": "混合", "upscale": "高清增强" }, diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 8526f3a30..15aa9ecd8 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -596,7 +596,7 @@ "list": "話題列表", "move_to": "移動到", "new": "開始新對話", - "pinned": "固定話題", + "pin": "固定話題", "prompt": { "edit": { "title": "編輯話題提示詞" @@ -605,7 +605,7 @@ "tips": "話題提示詞:針對目前話題提供額外的補充提示詞" }, "title": "話題", - "unpinned": "取消固定" + "unpin": "取消固定" }, "translate": "翻譯" }, @@ -1552,6 +1552,7 @@ "mode": { "edit": "編輯", "generate": "繪圖", + "merge": "合併", "remix": "混合", "upscale": "放大" }, diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index d126bc8bd..c868ab8b1 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -596,7 +596,7 @@ "list": "Λίστα θεμάτων", "move_to": "Μετακίνηση στο", "new": "Ξεκινήστε νέα συζήτηση", - "pinned": "Σταθερά θέματα", + "pin": "Σταθερά θέματα", "prompt": { "edit": { "title": "Επεξεργασία προσδοκώμενων όριων" @@ -605,7 +605,7 @@ "tips": "Προσδοκώμενα όρια: προσθέτει επιπλέον επιστημονικές προσθήκες για το παρόν θέμα" }, "title": "Θέματα", - "unpinned": "Αποστέλλω" + "unpin": "Ξεκαρφίτσωμα" }, "translate": "Μετάφραση" }, diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 76f5432a6..b6b1a2487 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -596,7 +596,7 @@ "list": "Lista de temas", "move_to": "Mover a", "new": "Iniciar nueva conversación", - "pinned": "Fijar tema", + "pin": "Fijar tema", "prompt": { "edit": { "title": "Editar palabras clave del tema" @@ -605,7 +605,7 @@ "tips": "Palabras clave del tema: proporcionar indicaciones adicionales para el tema actual" }, "title": "Tema", - "unpinned": "Quitar fijación" + "unpin": "Quitar fijación" }, "translate": "Traducir" }, diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index e4c9f5a94..d56d952a5 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -596,7 +596,7 @@ "list": "Liste des sujets", "move_to": "Déplacer vers", "new": "Commencer une nouvelle conversation", - "pinned": "Fixer le sujet", + "pin": "Fixer le sujet", "prompt": { "edit": { "title": "Modifier les indicateurs de sujet" @@ -605,7 +605,7 @@ "tips": "Indicateurs de sujet : fournir des indications supplémentaires pour le sujet actuel" }, "title": "Sujet", - "unpinned": "Annuler le fixage" + "unpin": "Annuler le fixage" }, "translate": "Traduire" }, diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index 876182300..59247634e 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -596,7 +596,7 @@ "list": "Lista de tópicos", "move_to": "Mover para", "new": "Começar nova conversa", - "pinned": "Fixar tópico", + "pin": "Fixar tópico", "prompt": { "edit": { "title": "Editar prompt do tópico" @@ -605,7 +605,7 @@ "tips": "Prompt do tópico: fornecer prompts adicionais para o tópico atual" }, "title": "Tópicos", - "unpinned": "Desfixar" + "unpin": "Desfixar" }, "translate": "Traduzir" }, diff --git a/src/renderer/src/pages/agents/components/AgentCard.tsx b/src/renderer/src/pages/agents/components/AgentCard.tsx index 9e2f08eb1..223987a06 100644 --- a/src/renderer/src/pages/agents/components/AgentCard.tsx +++ b/src/renderer/src/pages/agents/components/AgentCard.tsx @@ -1,12 +1,5 @@ -import { - DeleteOutlined, - EditOutlined, - EllipsisOutlined, - ExportOutlined, - PlusOutlined, - SortAscendingOutlined -} from '@ant-design/icons' import CustomTag from '@renderer/components/CustomTag' +import { DeleteIcon, EditIcon } from '@renderer/components/Icons' import { useAgents } from '@renderer/hooks/useAgents' import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings' import { createAssistantFromAgent } from '@renderer/services/AssistantService' @@ -14,6 +7,7 @@ import type { Agent } from '@renderer/types' import { getLeadingEmoji } from '@renderer/utils' import { Button, Dropdown } from 'antd' import { t } from 'i18next' +import { ArrowDownAZ, Ellipsis, PlusIcon, SquareArrowOutUpRight } from 'lucide-react' import { type FC, memo, useCallback, useEffect, useRef, useState } from 'react' import styled from 'styled-components' @@ -66,7 +60,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa { key: 'edit', label: t('agents.edit.title'), - icon: , + icon: , onClick: (e: any) => { e.domEvent.stopPropagation() AssistantSettingsPopup.show({ assistant: agent }) @@ -75,7 +69,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa { key: 'create', label: t('agents.add.button'), - icon: , + icon: , onClick: (e: any) => { e.domEvent.stopPropagation() createAssistantFromAgent(agent) @@ -84,7 +78,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa { key: 'sort', label: t('agents.sorting.title'), - icon: , + icon: , onClick: (e: any) => { e.domEvent.stopPropagation() ManageAgentsPopup.show() @@ -93,7 +87,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa { key: 'export', label: t('agents.export.agent'), - icon: , + icon: , onClick: (e: any) => { e.domEvent.stopPropagation() exportAgent() @@ -102,7 +96,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa { key: 'delete', label: t('common.delete'), - icon: , + icon: , danger: true, onClick: (e: any) => { e.domEvent.stopPropagation() @@ -173,7 +167,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa color="default" variant="filled" shape="circle" - icon={} + icon={} /> diff --git a/src/renderer/src/pages/files/FileList.tsx b/src/renderer/src/pages/files/FileList.tsx index 3d55c133d..d6ec0d850 100644 --- a/src/renderer/src/pages/files/FileList.tsx +++ b/src/renderer/src/pages/files/FileList.tsx @@ -1,4 +1,5 @@ -import { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons' +import { ExclamationCircleOutlined } from '@ant-design/icons' +import { DeleteIcon } from '@renderer/components/Icons' import { DynamicVirtualList } from '@renderer/components/VirtualList' import { handleDelete } from '@renderer/services/FileAction' import FileManager from '@renderer/services/FileManager' @@ -68,7 +69,7 @@ const FileList: React.FC = ({ id, list, files }) => { icon: }) }}> - + diff --git a/src/renderer/src/pages/files/FilesPage.tsx b/src/renderer/src/pages/files/FilesPage.tsx index 3bd3be3c6..649ff6e18 100644 --- a/src/renderer/src/pages/files/FilesPage.tsx +++ b/src/renderer/src/pages/files/FilesPage.tsx @@ -1,11 +1,6 @@ -import { - DeleteOutlined, - EditOutlined, - ExclamationCircleOutlined, - SortAscendingOutlined, - SortDescendingOutlined -} from '@ant-design/icons' +import { ExclamationCircleOutlined } from '@ant-design/icons' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' +import { DeleteIcon, EditIcon } from '@renderer/components/Icons' import ListItem from '@renderer/components/ListItem' import db from '@renderer/databases' import { getFileFieldLabel } from '@renderer/i18n/label' @@ -16,7 +11,14 @@ import { formatFileSize } from '@renderer/utils' import { Button, Empty, Flex, Popconfirm } from 'antd' import dayjs from 'dayjs' import { useLiveQuery } from 'dexie-react-hooks' -import { File as FileIcon, FileImage, FileText, FileType as FileTypeIcon } from 'lucide-react' +import { + ArrowDownNarrowWide, + ArrowUpWideNarrow, + File as FileIcon, + FileImage, + FileText, + FileType as FileTypeIcon +} from 'lucide-react' import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -54,7 +56,7 @@ const FilesPage: FC = () => { created_at_unix: dayjs(file.created_at).unix(), actions: ( -
diff --git a/src/renderer/src/pages/home/Messages/Blocks/PlaceholderBlock.tsx b/src/renderer/src/pages/home/Messages/Blocks/PlaceholderBlock.tsx index 261ed7f14..bcc8a9685 100644 --- a/src/renderer/src/pages/home/Messages/Blocks/PlaceholderBlock.tsx +++ b/src/renderer/src/pages/home/Messages/Blocks/PlaceholderBlock.tsx @@ -1,4 +1,4 @@ -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon } from '@renderer/components/Icons' import { MessageBlockStatus, MessageBlockType, type PlaceholderMessageBlock } from '@renderer/types/newMessage' import React from 'react' import styled from 'styled-components' @@ -10,7 +10,7 @@ const PlaceholderBlock: React.FC = ({ block }) => { if (block.status === MessageBlockStatus.PROCESSING && block.type === MessageBlockType.UNKNOWN) { return ( - + ) } diff --git a/src/renderer/src/pages/home/Messages/MessageMenubar.tsx b/src/renderer/src/pages/home/Messages/MessageMenubar.tsx index 3fab69218..be637bb2a 100644 --- a/src/renderer/src/pages/home/Messages/MessageMenubar.tsx +++ b/src/renderer/src/pages/home/Messages/MessageMenubar.tsx @@ -1,4 +1,5 @@ -import { CheckOutlined, EditOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons' +import { InfoCircleOutlined } from '@ant-design/icons' +import { CopyIcon, DeleteIcon, EditIcon, RefreshIcon } from '@renderer/components/Icons' import ObsidianExportPopup from '@renderer/components/Popups/ObsidianExportPopup' import SaveToKnowledgePopup from '@renderer/components/Popups/SaveToKnowledgePopup' import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup' @@ -32,20 +33,7 @@ import { removeTrailingDoubleSpaces } from '@renderer/utils/markdown' import { findMainTextBlocks, findTranslationBlocks, getMainTextContent } from '@renderer/utils/messageUtils/find' import { Dropdown, Popconfirm, Tooltip } from 'antd' import dayjs from 'dayjs' -import { - AtSign, - Copy, - FilePenLine, - Languages, - ListChecks, - Menu, - RefreshCw, - Save, - Share, - Split, - ThumbsUp, - Trash -} from 'lucide-react' +import { AtSign, Check, FilePenLine, Languages, ListChecks, Menu, Save, Split, ThumbsUp, Upload } from 'lucide-react' import { FC, memo, useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' @@ -223,7 +211,7 @@ const MessageMenubar: FC = (props) => { { label: t('chat.save.label'), key: 'save', - icon: , + icon: , children: [ { label: t('chat.save.file.title'), @@ -245,7 +233,7 @@ const MessageMenubar: FC = (props) => { { label: t('chat.topics.export.title'), key: 'export', - icon: , + icon: , children: [ exportMenuOptions.plain_text && { label: t('chat.topics.copy.plain_text'), @@ -440,28 +428,28 @@ const MessageMenubar: FC = (props) => { className="message-action-button" onClick={() => handleResendUserMessage()} $softHoverBg={isBubbleStyle}> - +
)} {message.role === 'user' && ( - + )} - {!copied && } - {copied && } + {!copied && } + {copied && } {isAssistantMessage && ( } + icon={} onConfirm={onRegenerate} onOpenChange={(open) => open && setShowRegenerateTooltip(false)}> = (props) => { open={showRegenerateTooltip} onOpenChange={setShowRegenerateTooltip}> - + @@ -571,7 +559,7 @@ const MessageMenubar: FC = (props) => { } + icon={} onOpenChange={(open) => open && setShowDeleteTooltip(false)} onConfirm={() => deleteMessage(message.id, message.traceId, message.model?.name)}> = (props) => { mouseEnterDelay={1} open={showDeleteTooltip} onOpenChange={setShowDeleteTooltip}> - + diff --git a/src/renderer/src/pages/home/Messages/MessageTools.tsx b/src/renderer/src/pages/home/Messages/MessageTools.tsx index 1f53e64fb..ccccec9f5 100644 --- a/src/renderer/src/pages/home/Messages/MessageTools.tsx +++ b/src/renderer/src/pages/home/Messages/MessageTools.tsx @@ -1,5 +1,5 @@ -import { CheckOutlined, CloseOutlined, ExpandOutlined, LoadingOutlined, WarningOutlined } from '@ant-design/icons' import { loggerService } from '@logger' +import { CopyIcon, LoadingIcon } from '@renderer/components/Icons' import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useMCPServers } from '@renderer/hooks/useMCPServers' import { useSettings } from '@renderer/hooks/useSettings' @@ -19,7 +19,18 @@ import { Tooltip } from 'antd' import { message } from 'antd' -import { ChevronDown, ChevronRight, CirclePlay, CircleX, PauseCircle, ShieldCheck } from 'lucide-react' +import { + Check, + ChevronDown, + ChevronRight, + CirclePlay, + CircleX, + Maximize, + PauseCircle, + ShieldCheck, + TriangleAlert, + X +} from 'lucide-react' import { FC, memo, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -191,23 +202,23 @@ const MessageTools: FC = ({ block }) => { switch (status) { case 'pending': label = t('message.tools.pending', 'Awaiting Approval') - icon = + icon = break case 'invoking': label = t('message.tools.invoking') - icon = + icon = break case 'cancelled': label = t('message.tools.cancelled') - icon = + icon = break case 'done': if (hasError) { label = t('message.tools.error') - icon = + icon = } else { label = t('message.tools.completed') - icon = + icon = } break default: @@ -262,7 +273,7 @@ const MessageTools: FC = ({ block }) => { }) }} aria-label={t('common.expand')}> - + {!isPending && !isInvoking && ( @@ -274,8 +285,8 @@ const MessageTools: FC = ({ block }) => { copyContent(JSON.stringify(result, null, 2), id) }} aria-label={t('common.copy')}> - {!copiedMap[id] && } - {copiedMap[id] && } + {!copiedMap[id] && } + {copiedMap[id] && } )} @@ -394,7 +405,7 @@ const MessageTools: FC = ({ block }) => { e.stopPropagation() handleAbortTool() }}> - + {t('chat.input.pause')} ) : ( @@ -572,10 +583,10 @@ const ExpandIcon = styled(ChevronRight)<{ $isActive?: boolean }>` ` const CollapseContainer = styled(Collapse)` - --status-color-warning: var(--color-warning, #faad14); + --status-color-warning: var(--color-status-warning, #faad14); --status-color-invoking: var(--color-primary); - --status-color-error: var(--color-error, #ff4d4f); - --status-color-success: var(--color-success, green); + --status-color-error: var(--color-status-error, #ff4d4f); + --status-color-success: var(--color-primary, green); border-radius: 7px; border: none; background-color: var(--color-background); diff --git a/src/renderer/src/pages/home/Messages/MessageTranslate.tsx b/src/renderer/src/pages/home/Messages/MessageTranslate.tsx index b3639c381..91135ed73 100644 --- a/src/renderer/src/pages/home/Messages/MessageTranslate.tsx +++ b/src/renderer/src/pages/home/Messages/MessageTranslate.tsx @@ -1,5 +1,5 @@ import { TranslationOutlined } from '@ant-design/icons' -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon } from '@renderer/components/Icons' import type { TranslationMessageBlock } from '@renderer/types/newMessage' import { Divider } from 'antd' import { FC, Fragment } from 'react' @@ -20,7 +20,7 @@ const MessageTranslate: FC = ({ block }) => { {!block.content || block.content === t('translate.processing') ? ( - + ) : ( )} diff --git a/src/renderer/src/pages/home/Messages/Messages.tsx b/src/renderer/src/pages/home/Messages/Messages.tsx index 440280483..9207dad35 100644 --- a/src/renderer/src/pages/home/Messages/Messages.tsx +++ b/src/renderer/src/pages/home/Messages/Messages.tsx @@ -1,6 +1,6 @@ import { loggerService } from '@logger' import ContextMenu from '@renderer/components/ContextMenu' -import SvgSpinners180Ring from '@renderer/components/Icons/SvgSpinners180Ring' +import { LoadingIcon } from '@renderer/components/Icons' import Scrollbar from '@renderer/components/Scrollbar' import { LOAD_MORE_COUNT } from '@renderer/config/constant' import { useAssistant } from '@renderer/hooks/useAssistant' @@ -309,7 +309,7 @@ const Messages: React.FC = ({ assistant, topic, setActiveTopic, o ))} {isLoadingMore && ( - + )} diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index e2c758924..5147cbb2c 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -1,4 +1,4 @@ -import { DownOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons' +import { DownOutlined, RightOutlined } from '@ant-design/icons' import { DraggableList } from '@renderer/components/DraggableList' import Scrollbar from '@renderer/components/Scrollbar' import { useAgents } from '@renderer/hooks/useAgents' @@ -6,8 +6,9 @@ import { useAssistants } from '@renderer/hooks/useAssistant' import { useAssistantsTabSortType } from '@renderer/hooks/useStore' import { useTags } from '@renderer/hooks/useTags' import { Assistant, AssistantsSortType } from '@renderer/types' -import { Tooltip } from 'antd' -import { FC, useCallback, useRef, useState } from 'react' +import { Tooltip, Typography } from 'antd' +import { Plus } from 'lucide-react' +import { FC, useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -69,6 +70,19 @@ const Assistants: FC = ({ [assistants, t, updateAssistants] ) + const renderAddAssistantButton = useMemo(() => { + return ( + + + + + {t('chat.add.assistant.title')} + + + + ) + }, [onCreateAssistant, t]) + if (assistantsTabSortType === 'tags') { return ( @@ -117,12 +131,7 @@ const Assistants: FC = ({ ))} - - - - {t('chat.add.assistant.title')} - - + {renderAddAssistantButton} ) } @@ -149,14 +158,7 @@ const Assistants: FC = ({ /> )} - {!dragging && ( - - - - {t('chat.add.assistant.title')} - - - )} + {!dragging && renderAddAssistantButton}
) @@ -224,13 +226,13 @@ const GroupTitleDivider = styled.div` border-top: 1px solid var(--color-border); ` -const AssistantName = styled.div` - color: var(--color-text); - display: -webkit-box; - -webkit-line-clamp: 1; - -webkit-box-orient: vertical; - overflow: hidden; +const AddItemWrapper = styled.div` + color: var(--color-text-2); font-size: 13px; + display: flex; + align-items: center; + white-space: nowrap; + overflow: hidden; ` export default Assistants diff --git a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx index 670cb2638..d5f3346a0 100644 --- a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx @@ -1,17 +1,5 @@ -import { - ClearOutlined, - CloseOutlined, - DeleteOutlined, - EditOutlined, - FolderOutlined, - MenuOutlined, - PlusOutlined, - PushpinOutlined, - QuestionCircleOutlined, - UploadOutlined -} from '@ant-design/icons' import { DraggableVirtualList } from '@renderer/components/DraggableList' -import CopyIcon from '@renderer/components/Icons/CopyIcon' +import { CopyIcon, DeleteIcon, EditIcon } from '@renderer/components/Icons' import ObsidianExportPopup from '@renderer/components/Popups/ObsidianExportPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup' import { isMac } from '@renderer/config/constant' @@ -40,6 +28,19 @@ import { Dropdown, MenuProps, Tooltip } from 'antd' import { ItemType, MenuItemType } from 'antd/es/menu/interface' import dayjs from 'dayjs' import { findIndex } from 'lodash' +import { + BrushCleaning, + FolderOpen, + HelpCircle, + MenuIcon, + PackagePlus, + PinIcon, + PinOffIcon, + PlusIcon, + Sparkles, + UploadIcon, + XIcon +} from 'lucide-react' import { FC, useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' @@ -177,7 +178,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.auto_rename'), key: 'auto-rename', - icon: , + icon: , disabled: isRenaming(topic.id), async onClick() { const messages = await TopicManager.getTopicMessages(topic.id) @@ -200,7 +201,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.edit.title'), key: 'rename', - icon: , + icon: , disabled: isRenaming(topic.id), async onClick() { const name = await PromptPopup.show({ @@ -217,10 +218,10 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.prompt.label'), key: 'topic-prompt', - icon: , + icon: , extra: ( - + ), async onClick() { @@ -243,9 +244,9 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, } }, { - label: topic.pinned ? t('chat.topics.unpinned') : t('chat.topics.pinned'), + label: topic.pinned ? t('chat.topics.unpin') : t('chat.topics.pin'), key: 'pin', - icon: , + icon: topic.pinned ? : , onClick() { onPinTopic(topic) } @@ -253,7 +254,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.clear.title'), key: 'clear-messages', - icon: , + icon: , async onClick() { window.modal.confirm({ title: t('chat.input.clear.content'), @@ -265,7 +266,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('settings.topic.position.label'), key: 'topic-position', - icon: , + icon: , children: [ { label: t('settings.topic.position.left'), @@ -282,7 +283,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.copy.title'), key: 'copy', - icon: , + icon: , children: [ { label: t('chat.topics.copy.image'), @@ -304,7 +305,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, { label: t('chat.topics.export.title'), key: 'export', - icon: , + icon: , children: [ exportMenuOptions.image && { label: t('chat.topics.export.image'), @@ -375,7 +376,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, menus.push({ label: t('chat.topics.move_to'), key: 'move', - icon: , + icon: , children: assistants .filter((a) => a.id !== assistant.id) .map((a) => ({ @@ -392,7 +393,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, label: t('common.delete'), danger: true, key: 'delete', - icon: , + icon: , onClick: () => onDeleteTopic(topic) }) } @@ -446,7 +447,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, itemContainerStyle={{ paddingBottom: '8px' }} header={ EventEmitter.emit(EVENT_NAMES.ADD_NEW_TOPIC)}> - + {t('chat.add.topic.title')} }> @@ -498,16 +499,16 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, } }}> {deletingTopicId === topic.id ? ( - + ) : ( - + )} )} {topic.pinned && ( - + )} @@ -704,10 +705,5 @@ const MenuButton = styled.div` font-size: 12px; } ` -const QuestionIcon = styled(QuestionCircleOutlined)` - font-size: 14px; - cursor: pointer; - color: var(--color-text-3); -` export default Topics diff --git a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx index d33c26c61..238fe5c58 100644 --- a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx @@ -1,17 +1,6 @@ -import { - CheckOutlined, - DeleteOutlined, - EditOutlined, - MinusCircleOutlined, - PlusOutlined, - SaveOutlined, - SmileOutlined, - SortAscendingOutlined, - SortDescendingOutlined -} from '@ant-design/icons' import ModelAvatar from '@renderer/components/Avatar/ModelAvatar' import EmojiIcon from '@renderer/components/EmojiIcon' -import CopyIcon from '@renderer/components/Icons/CopyIcon' +import { CopyIcon, DeleteIcon, EditIcon } from '@renderer/components/Icons' import PromptPopup from '@renderer/components/Popups/PromptPopup' import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant' import { useSettings } from '@renderer/hooks/useSettings' @@ -24,7 +13,19 @@ import { getLeadingEmoji, uuid } from '@renderer/utils' import { hasTopicPendingRequests } from '@renderer/utils/queue' import { Dropdown, MenuProps } from 'antd' import { omit } from 'lodash' -import { AlignJustify, Plus, Settings2, Tag, Tags } from 'lucide-react' +import { + AlignJustify, + ArrowDownAZ, + ArrowUpAZ, + BrushCleaning, + Check, + Plus, + Save, + Settings2, + Smile, + Tag, + Tags +} from 'lucide-react' import { FC, memo, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -198,7 +199,7 @@ const createTagMenuItems = ( const items: MenuProps['items'] = [ ...allTags.map((tag) => ({ label: tag, - icon: assistant.tags?.includes(tag) ? : , + icon: assistant.tags?.includes(tag) ? : , key: `all-tag-${tag}`, onClick: () => handleTagOperation(tag, assistant, assistants, updateAssistants) })) @@ -211,7 +212,7 @@ const createTagMenuItems = ( items.push({ label: t('assistants.tags.add'), key: 'new-tag', - icon: , + icon: , onClick: async () => { const tagName = await PromptPopup.show({ title: t('assistants.tags.add'), @@ -228,7 +229,7 @@ const createTagMenuItems = ( items.push({ label: t('assistants.tags.manage'), key: 'manage-tags', - icon: , + icon: , onClick: () => { AssistantTagsPopup.show({ title: t('assistants.tags.manage') }) } @@ -260,13 +261,13 @@ function getMenuItems({ { label: t('assistants.edit.title'), key: 'edit', - icon: , + icon: , onClick: () => AssistantSettingsPopup.show({ assistant }) }, { label: t('assistants.copy.title'), key: 'duplicate', - icon: , + icon: , onClick: async () => { const _assistant = copyAssistant(assistant) if (_assistant) { @@ -277,7 +278,7 @@ function getMenuItems({ { label: t('assistants.clear.title'), key: 'clear', - icon: , + icon: , onClick: () => { window.modal.confirm({ title: t('assistants.clear.title'), @@ -291,7 +292,7 @@ function getMenuItems({ { label: t('assistants.save.title'), key: 'save-to-agent', - icon: , + icon: , onClick: async () => { const agent = omit(assistant, ['model', 'emoji']) agent.id = uuid() @@ -306,7 +307,7 @@ function getMenuItems({ { label: t('assistants.icon.type'), key: 'icon-type', - icon: , + icon: , children: [ { label: t('settings.assistant.icon.type.model'), @@ -331,7 +332,7 @@ function getMenuItems({ { label: t('assistants.tags.manage'), key: 'all-tags', - icon: , + icon: , children: createTagMenuItems(allTags, assistant, assistants, updateAssistants, t) }, { @@ -345,13 +346,13 @@ function getMenuItems({ { label: t('common.sort.pinyin.asc'), key: 'sort-asc', - icon: , + icon: , onClick: sortByPinyinAsc }, { label: t('common.sort.pinyin.desc'), key: 'sort-desc', - icon: , + icon: , onClick: sortByPinyinDesc }, { @@ -360,7 +361,7 @@ function getMenuItems({ { label: t('common.delete'), key: 'delete', - icon: , + icon: , danger: true, onClick: () => { window.modal.confirm({ diff --git a/src/renderer/src/pages/home/Tabs/components/AssistantTagsPopup.tsx b/src/renderer/src/pages/home/Tabs/components/AssistantTagsPopup.tsx index ad0c6ba9c..89087f5c8 100644 --- a/src/renderer/src/pages/home/Tabs/components/AssistantTagsPopup.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AssistantTagsPopup.tsx @@ -1,11 +1,11 @@ import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd' +import { DeleteIcon } from '@renderer/components/Icons' import { Box } from '@renderer/components/Layout' import { TopView } from '@renderer/components/TopView' import { useAssistants } from '@renderer/hooks/useAssistant' import { useTags } from '@renderer/hooks/useTags' import { Button, Empty, Modal } from 'antd' import { isEmpty } from 'lodash' -import { Trash } from 'lucide-react' import { useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -94,7 +94,7 @@ const PopupContainer: React.FC = ({ title, resolve }) => { {tag}