feat: new icon style

This commit is contained in:
kangfenmao 2025-04-13 15:35:37 +08:00
parent 39c614e4db
commit 5f7d8652bc
44 changed files with 310 additions and 289 deletions

View File

@ -87,12 +87,10 @@
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"got-scraping": "^4.1.1", "got-scraping": "^4.1.1",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
"lucide-react": "^0.487.0",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"officeparser": "^4.1.1", "officeparser": "^4.1.1",
"proxy-agent": "^6.5.0", "proxy-agent": "^6.5.0",
"tar": "^7.4.3", "tar": "^7.4.3",
"tiny-pinyin": "^1.3.2",
"turndown": "^7.2.0", "turndown": "^7.2.0",
"turndown-plugin-gfm": "^1.0.2", "turndown-plugin-gfm": "^1.0.2",
"undici": "^7.4.0", "undici": "^7.4.0",
@ -161,6 +159,7 @@
"lint-staged": "^15.5.0", "lint-staged": "^15.5.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lru-cache": "^11.1.0", "lru-cache": "^11.1.0",
"lucide-react": "^0.487.0",
"mime": "^4.0.4", "mime": "^4.0.4",
"npx-scope-finder": "^1.2.0", "npx-scope-finder": "^1.2.0",
"openai": "patch:openai@npm%3A4.87.3#~/.yarn/patches/openai-npm-4.87.3-2b30a7685f.patch", "openai": "patch:openai@npm%3A4.87.3#~/.yarn/patches/openai-npm-4.87.3-2b30a7685f.patch",
@ -190,6 +189,7 @@
"shiki": "^3.2.1", "shiki": "^3.2.1",
"string-width": "^7.2.0", "string-width": "^7.2.0",
"styled-components": "^6.1.11", "styled-components": "^6.1.11",
"tiny-pinyin": "^1.3.2",
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
"tokenx": "^0.4.1", "tokenx": "^0.4.1",
"typescript": "^5.6.2", "typescript": "^5.6.2",

View File

@ -281,3 +281,7 @@ body,
color: var(--color-text); color: var(--color-text);
} }
} }
.lucide {
color: var(--color-icon);
}

View File

@ -52,7 +52,7 @@ const ListItemContainer = styled.div`
const ListItemContent = styled.div` const ListItemContent = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 2px;
overflow: hidden; overflow: hidden;
font-size: 13px; font-size: 13px;
` `

View File

@ -1,4 +1,3 @@
import { SearchOutlined } from '@ant-design/icons'
import { TopView } from '@renderer/components/TopView' import { TopView } from '@renderer/components/TopView'
import { useAgents } from '@renderer/hooks/useAgents' import { useAgents } from '@renderer/hooks/useAgents'
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
@ -9,6 +8,7 @@ import { Agent, Assistant } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { Divider, Input, InputRef, Modal, Tag } from 'antd' import { Divider, Input, InputRef, Modal, Tag } from 'antd'
import { take } from 'lodash' import { take } from 'lodash'
import { Search } from 'lucide-react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -163,7 +163,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
<Input <Input
prefix={ prefix={
<SearchIcon> <SearchIcon>
<SearchOutlined /> <Search size={14} />
</SearchIcon> </SearchIcon>
} }
ref={inputRef} ref={inputRef}
@ -177,7 +177,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
size="middle" size="middle"
/> />
</HStack> </HStack>
<Divider style={{ margin: 0, borderBlockStartWidth: 0.5 }} /> <Divider style={{ margin: 0, marginTop: 4, borderBlockStartWidth: 0.5 }} />
<Container ref={containerRef}> <Container ref={containerRef}>
{take(agents, 100).map((agent, index) => ( {take(agents, 100).map((agent, index) => (
<AgentItem <AgentItem
@ -237,8 +237,8 @@ const AgentItem = styled.div`
` `
const SearchIcon = styled.div` const SearchIcon = styled.div`
width: 36px; width: 32px;
height: 36px; height: 32px;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -1,4 +1,4 @@
import { PushpinOutlined, SearchOutlined } from '@ant-design/icons' import { PushpinOutlined } from '@ant-design/icons'
import { TopView } from '@renderer/components/TopView' import { TopView } from '@renderer/components/TopView'
import { getModelLogo, isEmbeddingModel, isRerankModel } from '@renderer/config/models' import { getModelLogo, isEmbeddingModel, isRerankModel } from '@renderer/config/models'
import db from '@renderer/databases' import db from '@renderer/databases'
@ -7,6 +7,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
import { Model } from '@renderer/types' import { Model } from '@renderer/types'
import { Avatar, Divider, Empty, Input, InputRef, Menu, MenuProps, Modal } from 'antd' import { Avatar, Divider, Empty, Input, InputRef, Menu, MenuProps, Modal } from 'antd'
import { first, sortBy } from 'lodash' import { first, sortBy } from 'lodash'
import { Search } from 'lucide-react'
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -383,7 +384,7 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ model, resolve }) => {
<Input <Input
prefix={ prefix={
<SearchIcon> <SearchIcon>
<SearchOutlined /> <Search size={15} />
</SearchIcon> </SearchIcon>
} }
ref={inputRef} ref={inputRef}
@ -403,7 +404,7 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ model, resolve }) => {
}} }}
/> />
</HStack> </HStack>
<Divider style={{ margin: 0, borderBlockStartWidth: 0.5 }} /> <Divider style={{ margin: 0, marginTop: 4, borderBlockStartWidth: 0.5 }} />
<Scrollbar style={{ height: '50vh' }} ref={scrollContainerRef}> <Scrollbar style={{ height: '50vh' }} ref={scrollContainerRef}>
<Container> <Container>
{processedItems.length > 0 ? ( {processedItems.length > 0 ? (
@ -510,8 +511,8 @@ const EmptyState = styled.div`
` `
const SearchIcon = styled.div` const SearchIcon = styled.div`
width: 36px; width: 32px;
height: 36px; height: 32px;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -603,6 +603,7 @@ const QuickPanelItem = styled.div`
cursor: pointer; cursor: pointer;
transition: background-color 0.1s ease; transition: background-color 0.1s ease;
margin-bottom: 1px; margin-bottom: 1px;
font-family: Ubuntu;
&.selected { &.selected {
background-color: var(--selected-color); background-color: var(--selected-color);
&.focused { &.focused {

View File

@ -1,10 +1,11 @@
import { LoadingOutlined, TranslationOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import { useDefaultModel } from '@renderer/hooks/useAssistant' import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { fetchTranslate } from '@renderer/services/ApiService' import { fetchTranslate } from '@renderer/services/ApiService'
import { getDefaultTopic, getDefaultTranslateAssistant } from '@renderer/services/AssistantService' import { getDefaultTopic, getDefaultTranslateAssistant } from '@renderer/services/AssistantService'
import { getUserMessage } from '@renderer/services/MessagesService' import { getUserMessage } from '@renderer/services/MessagesService'
import { Button, Tooltip } from 'antd' import { Button, Tooltip } from 'antd'
import { Languages } from 'lucide-react'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -82,7 +83,7 @@ const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoa
title={t('chat.input.translate', { target_language: t(`languages.${targetLanguage.toString()}`) })} title={t('chat.input.translate', { target_language: t(`languages.${targetLanguage.toString()}`) })}
arrow> arrow>
<ToolbarButton onClick={handleTranslate} disabled={disabled || isTranslating} style={style} type="text"> <ToolbarButton onClick={handleTranslate} disabled={disabled || isTranslating} style={style} type="text">
{isTranslating ? <LoadingOutlined spin /> : <TranslationOutlined />} {isTranslating ? <LoadingOutlined spin /> : <Languages size={18} />}
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -1,10 +1,3 @@
import {
FileSearchOutlined,
FolderOutlined,
PictureOutlined,
QuestionCircleOutlined,
TranslationOutlined
} from '@ant-design/icons'
import { isMac } from '@renderer/config/constant' import { isMac } from '@renderer/config/constant'
import { AppLogo, UserAvatar } from '@renderer/config/env' import { AppLogo, UserAvatar } from '@renderer/config/env'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
@ -17,6 +10,19 @@ import { useSettings } from '@renderer/hooks/useSettings'
import { isEmoji } from '@renderer/utils' import { isEmoji } from '@renderer/utils'
import type { MenuProps } from 'antd' import type { MenuProps } from 'antd'
import { Avatar, Dropdown, Tooltip } from 'antd' import { Avatar, Dropdown, Tooltip } from 'antd'
import {
CircleHelp,
Folder,
Languages,
LayoutGrid,
LibraryBig,
MessageSquareQuote,
Moon,
Palette,
Settings,
Sparkle,
Sun
} from 'lucide-react'
import { FC, useEffect } from 'react' import { FC, useEffect } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
@ -84,7 +90,7 @@ const Sidebar: FC = () => {
<Menus> <Menus>
<Tooltip title={t('docs.title')} mouseEnterDelay={0.8} placement="right"> <Tooltip title={t('docs.title')} mouseEnterDelay={0.8} placement="right">
<Icon theme={theme} onClick={onOpenDocs} className={minappShow && currentMinappId === docsId ? 'active' : ''}> <Icon theme={theme} onClick={onOpenDocs} className={minappShow && currentMinappId === docsId ? 'active' : ''}>
<QuestionCircleOutlined /> <CircleHelp size={20} />
</Icon> </Icon>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
@ -92,22 +98,17 @@ const Sidebar: FC = () => {
mouseEnterDelay={0.8} mouseEnterDelay={0.8}
placement="right"> placement="right">
<Icon theme={theme} onClick={() => toggleTheme()}> <Icon theme={theme} onClick={() => toggleTheme()}>
{theme === 'dark' ? ( {theme === 'dark' ? <Moon size={20} /> : <Sun size={20} />}
<i className="iconfont icon-theme icon-dark1" />
) : (
<i className="iconfont icon-theme icon-theme-light" />
)}
</Icon> </Icon>
</Tooltip> </Tooltip>
<Tooltip title={t('settings.title')} mouseEnterDelay={0.8} placement="right"> <Tooltip title={t('settings.title')} mouseEnterDelay={0.8} placement="right">
<StyledLink <StyledLink
onClick={async () => { onClick={async () => {
hideMinappPopup() hideMinappPopup()
await modelGenerating()
await to('/settings/provider') await to('/settings/provider')
}}> }}>
<Icon theme={theme} className={pathname.startsWith('/settings') && !minappShow ? 'active' : ''}> <Icon theme={theme} className={pathname.startsWith('/settings') && !minappShow ? 'active' : ''}>
<i className="iconfont icon-setting" /> <Settings size={20} />
</Icon> </Icon>
</StyledLink> </StyledLink>
</Tooltip> </Tooltip>
@ -129,13 +130,13 @@ const MainMenus: FC = () => {
const isRoutes = (path: string): string => (pathname.startsWith(path) && !minappShow ? 'active' : '') const isRoutes = (path: string): string => (pathname.startsWith(path) && !minappShow ? 'active' : '')
const iconMap = { const iconMap = {
assistants: <i className="iconfont icon-chat" />, assistants: <MessageSquareQuote size={18} />,
agents: <i className="iconfont icon-business-smart-assistant" />, agents: <Sparkle size={18} />,
paintings: <PictureOutlined style={{ fontSize: 16 }} />, paintings: <Palette size={18} />,
translate: <TranslationOutlined />, translate: <Languages size={18} />,
minapp: <i className="iconfont icon-appstore" />, minapp: <LayoutGrid size={18} />,
knowledge: <FileSearchOutlined />, knowledge: <LibraryBig size={18} />,
files: <FolderOutlined /> files: <Folder size={17} />
} }
const pathMap = { const pathMap = {

View File

@ -33,7 +33,11 @@ const AntdProvider: FC<PropsWithChildren> = ({ children }) => {
boxShadowSecondary: 'none', boxShadowSecondary: 'none',
defaultShadow: 'none', defaultShadow: 'none',
dangerShadow: 'none', dangerShadow: 'none',
primaryShadow: 'none' primaryShadow: 'none',
borderRadius: 20
},
Select: {
borderRadius: 20
} }
}, },
token: { token: {

View File

@ -1,4 +1,4 @@
import { PlusOutlined, SearchOutlined } from '@ant-design/icons' import { PlusOutlined } from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import CustomTag from '@renderer/components/CustomTag' import CustomTag from '@renderer/components/CustomTag'
import ListItem from '@renderer/components/ListItem' import ListItem from '@renderer/components/ListItem'
@ -9,6 +9,7 @@ import { Agent } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { Button, Empty, Flex, Input } from 'antd' import { Button, Empty, Flex, Input } from 'antd'
import { omit } from 'lodash' import { omit } from 'lodash'
import { Search } from 'lucide-react'
import { FC, useCallback, useEffect, useMemo, useState } from 'react' import { FC, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import ReactMarkdown from 'react-markdown' import ReactMarkdown from 'react-markdown'
@ -150,7 +151,7 @@ const AgentsPage: FC = () => {
variant="filled" variant="filled"
allowClear allowClear
onClear={handleSearchClear} onClear={handleSearchClear}
suffix={<SearchOutlined onClick={handleSearch} />} suffix={<Search size={14} color="var(--color-icon)" onClick={handleSearch} />}
value={searchInput} value={searchInput}
maxLength={50} maxLength={50}
onChange={(e) => setSearchInput(e.target.value)} onChange={(e) => setSearchInput(e.target.value)}

View File

@ -1,9 +1,9 @@
import { SearchOutlined } from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { Center } from '@renderer/components/Layout' import { Center } from '@renderer/components/Layout'
import { useMinapps } from '@renderer/hooks/useMinapps' import { useMinapps } from '@renderer/hooks/useMinapps'
import { Empty, Input } from 'antd' import { Empty, Input } from 'antd'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { Search } from 'lucide-react'
import React, { FC, useState } from 'react' import React, { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -40,10 +40,10 @@ const AppsPage: FC = () => {
<Input <Input
placeholder={t('common.search')} placeholder={t('common.search')}
className="nodrag" className="nodrag"
style={{ width: '30%', height: 28 }} style={{ width: '30%', height: 28, borderRadius: 15 }}
size="small" size="small"
variant="filled" variant="filled"
suffix={<SearchOutlined />} suffix={<Search size={18} />}
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
/> />

View File

@ -2,24 +2,21 @@ import {
DeleteOutlined, DeleteOutlined,
EditOutlined, EditOutlined,
ExclamationCircleOutlined, ExclamationCircleOutlined,
FileImageOutlined,
FilePdfOutlined,
FileTextOutlined,
SortAscendingOutlined, SortAscendingOutlined,
SortDescendingOutlined SortDescendingOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import ListItem from '@renderer/components/ListItem'
import TextEditPopup from '@renderer/components/Popups/TextEditPopup' import TextEditPopup from '@renderer/components/Popups/TextEditPopup'
import db from '@renderer/databases' import db from '@renderer/databases'
import { useProviders } from '@renderer/hooks/useProvider'
import FileManager from '@renderer/services/FileManager' import FileManager from '@renderer/services/FileManager'
import store from '@renderer/store' import store from '@renderer/store'
import { FileType, FileTypes } from '@renderer/types' import { FileType, FileTypes } from '@renderer/types'
import { formatFileSize } from '@renderer/utils' import { formatFileSize } from '@renderer/utils'
import type { MenuProps } from 'antd' import { Button, Empty, Flex, Popconfirm } from 'antd'
import { Button, Empty, Flex, Menu, Popconfirm } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useLiveQuery } from 'dexie-react-hooks' import { useLiveQuery } from 'dexie-react-hooks'
import { File as FileIcon, FileImage, FileText, FileType as FileTypeIcon } from 'lucide-react'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -34,9 +31,6 @@ const FilesPage: FC = () => {
const [fileType, setFileType] = useState<string>('document') const [fileType, setFileType] = useState<string>('document')
const [sortField, setSortField] = useState<SortField>('created_at') const [sortField, setSortField] = useState<SortField>('created_at')
const [sortOrder, setSortOrder] = useState<SortOrder>('desc') const [sortOrder, setSortOrder] = useState<SortOrder>('desc')
const { providers } = useProviders()
const geminiProviders = providers.filter((provider) => provider.type === 'gemini')
const tempFilesSort = (files: FileType[]) => { const tempFilesSort = (files: FileType[]) => {
return files.sort((a, b) => { return files.sort((a, b) => {
@ -144,16 +138,11 @@ const FilesPage: FC = () => {
}) })
const menuItems = [ const menuItems = [
{ key: FileTypes.DOCUMENT, label: t('files.document'), icon: <FilePdfOutlined /> }, { key: FileTypes.DOCUMENT, label: t('files.document'), icon: <FileIcon size={16} /> },
{ key: FileTypes.IMAGE, label: t('files.image'), icon: <FileImageOutlined /> }, { key: FileTypes.IMAGE, label: t('files.image'), icon: <FileImage size={16} /> },
{ key: FileTypes.TEXT, label: t('files.text'), icon: <FileTextOutlined /> }, { key: FileTypes.TEXT, label: t('files.text'), icon: <FileTypeIcon size={16} /> },
...geminiProviders.map((provider) => ({ { key: 'all', label: t('files.all'), icon: <FileText size={16} /> }
key: 'gemini_' + provider.id, ]
label: provider.name,
icon: <FilePdfOutlined />
})),
{ key: 'all', label: t('files.all'), icon: <FileTextOutlined /> }
].filter(Boolean) as MenuProps['items']
return ( return (
<Container> <Container>
@ -162,7 +151,15 @@ const FilesPage: FC = () => {
</Navbar> </Navbar>
<ContentContainer id="content-container"> <ContentContainer id="content-container">
<SideNav> <SideNav>
<Menu selectedKeys={[fileType]} items={menuItems} onSelect={({ key }) => setFileType(key as FileTypes)} /> {menuItems.map((item) => (
<ListItem
key={item.key}
icon={item.icon}
title={item.label}
active={fileType === item.key}
onClick={() => setFileType(item.key as FileTypes)}
/>
))}
</SideNav> </SideNav>
<MainContent> <MainContent>
<SortContainer> <SortContainer>
@ -223,10 +220,13 @@ const ContentContainer = styled.div`
` `
const SideNav = styled.div` const SideNav = styled.div`
display: flex;
flex-direction: column;
width: var(--settings-width); width: var(--settings-width);
border-right: 0.5px solid var(--color-border); border-right: 0.5px solid var(--color-border);
padding: 7px 12px; padding: 12px 10px;
user-select: none; user-select: none;
gap: 6px;
.ant-menu { .ant-menu {
border-inline-end: none !important; border-inline-end: none !important;

View File

@ -1,7 +1,8 @@
import { ArrowLeftOutlined, EnterOutlined, SearchOutlined } from '@ant-design/icons' import { ArrowLeftOutlined, EnterOutlined } from '@ant-design/icons'
import { Message, Topic } from '@renderer/types' import { Message, Topic } from '@renderer/types'
import { Input, InputRef } from 'antd' import { Input, InputRef } from 'antd'
import { last } from 'lodash' import { last } from 'lodash'
import { Search } from 'lucide-react'
import { FC, useEffect, useRef, useState } from 'react' import { FC, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -83,7 +84,7 @@ const TopicsPage: FC = () => {
allowClear allowClear
ref={inputRef} ref={inputRef}
onChange={(e) => setSearch(e.target.value.trimStart())} onChange={(e) => setSearch(e.target.value.trimStart())}
suffix={search.length >= 2 ? <EnterOutlined /> : <SearchOutlined />} suffix={search.length >= 2 ? <EnterOutlined /> : <Search size={16} />}
onPressEnter={onSearch} onPressEnter={onSearch}
/> />
</Header> </Header>

View File

@ -1,8 +1,8 @@
import { PaperClipOutlined } from '@ant-design/icons'
import { isVisionModel } from '@renderer/config/models' import { isVisionModel } from '@renderer/config/models'
import { FileType, Model } from '@renderer/types' import { FileType, Model } from '@renderer/types'
import { documentExts, imageExts, textExts } from '@shared/config/constant' import { documentExts, imageExts, textExts } from '@shared/config/constant'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { Paperclip } from 'lucide-react'
import { FC, useCallback, useImperativeHandle, useMemo } from 'react' import { FC, useCallback, useImperativeHandle, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -57,9 +57,7 @@ const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButto
title={isVisionModel(model) ? t('chat.input.upload') : t('chat.input.upload.document')} title={isVisionModel(model) ? t('chat.input.upload') : t('chat.input.upload.document')}
arrow> arrow>
<ToolbarButton type="text" onClick={onSelectFile} disabled={disabled}> <ToolbarButton type="text" onClick={onSelectFile} disabled={disabled}>
<PaperClipOutlined <Paperclip size={18} style={{ color: files.length ? 'var(--color-primary)' : 'var(--color-icon)' }} />
style={{ fontSize: 17, color: files.length ? 'var(--color-primary)' : 'var(--color-icon)' }}
/>
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -1,7 +1,7 @@
import { PictureOutlined } from '@ant-design/icons'
import { isGenerateImageModel } from '@renderer/config/models' import { isGenerateImageModel } from '@renderer/config/models'
import { Assistant, Model } from '@renderer/types' import { Assistant, Model } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { Image } from 'lucide-react'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -27,7 +27,7 @@ const GenerateImageButton: FC<Props> = ({ model, ToolbarButton, assistant, onEna
} }
arrow> arrow>
<ToolbarButton type="text" disabled={!isGenerateImageModel(model)} onClick={onEnableGenerateImage}> <ToolbarButton type="text" disabled={!isGenerateImageModel(model)} onClick={onEnableGenerateImage}>
<PictureOutlined style={{ color: assistant.enableGenerateImage ? 'var(--color-link)' : 'var(--color-icon)' }} /> <Image size={18} color={assistant.enableGenerateImage ? 'var(--color-link)' : 'var(--color-icon)'} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -1,11 +1,6 @@
import { import {
ClearOutlined,
CodeOutlined, CodeOutlined,
FileSearchOutlined, FileSearchOutlined,
FormOutlined,
FullscreenExitOutlined,
FullscreenOutlined,
GlobalOutlined,
HolderOutlined, HolderOutlined,
PaperClipOutlined, PaperClipOutlined,
PauseCircleOutlined, PauseCircleOutlined,
@ -44,6 +39,7 @@ import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import Logger from 'electron-log/renderer' import Logger from 'electron-log/renderer'
import { debounce, isEmpty } from 'lodash' import { debounce, isEmpty } from 'lodash'
import { Globe, Maximize, MessageSquareDiff, Minimize, PaintbrushVertical } from 'lucide-react'
import React, { CSSProperties, FC, useCallback, useEffect, useMemo, useRef, useState } from 'react' import React, { CSSProperties, FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
@ -935,7 +931,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
<ToolbarMenu> <ToolbarMenu>
<Tooltip placement="top" title={t('chat.input.new_topic', { Command: newTopicShortcut })} arrow> <Tooltip placement="top" title={t('chat.input.new_topic', { Command: newTopicShortcut })} arrow>
<ToolbarButton type="text" onClick={addNewTopic}> <ToolbarButton type="text" onClick={addNewTopic}>
<FormOutlined /> <MessageSquareDiff size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
<AttachmentButton <AttachmentButton
@ -947,7 +943,8 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
/> />
<Tooltip placement="top" title={t('chat.input.web_search')} arrow> <Tooltip placement="top" title={t('chat.input.web_search')} arrow>
<ToolbarButton type="text" onClick={onEnableWebSearch}> <ToolbarButton type="text" onClick={onEnableWebSearch}>
<GlobalOutlined <Globe
size={18}
style={{ color: assistant.enableWebSearch ? 'var(--color-link)' : 'var(--color-icon)' }} style={{ color: assistant.enableWebSearch ? 'var(--color-link)' : 'var(--color-icon)' }}
/> />
</ToolbarButton> </ToolbarButton>
@ -989,12 +986,12 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
/> />
<Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow> <Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow>
<ToolbarButton type="text" onClick={clearTopic}> <ToolbarButton type="text" onClick={clearTopic}>
<ClearOutlined style={{ fontSize: 17 }} /> <PaintbrushVertical size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
<Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow> <Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
<ToolbarButton type="text" onClick={onToggleExpended}> <ToolbarButton type="text" onClick={onToggleExpended}>
{isExpended ? <FullscreenExitOutlined /> : <FullscreenOutlined />} {isExpended ? <Minimize size={18} /> : <Maximize size={18} />}
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
<NewContextButton onNewContext={onNewContext} ToolbarButton={ToolbarButton} /> <NewContextButton onNewContext={onNewContext} ToolbarButton={ToolbarButton} />

View File

@ -4,6 +4,7 @@ import { QuickPanelListItem, useQuickPanel } from '@renderer/components/QuickPan
import { useAppSelector } from '@renderer/store' import { useAppSelector } from '@renderer/store'
import { KnowledgeBase } from '@renderer/types' import { KnowledgeBase } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { LibraryBig } from 'lucide-react'
import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react' import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@ -88,7 +89,7 @@ const KnowledgeBaseButton: FC<Props> = ({ ref, selectedBases, onSelect, disabled
return ( return (
<Tooltip placement="top" title={t('chat.input.knowledge_base')} arrow> <Tooltip placement="top" title={t('chat.input.knowledge_base')} arrow>
<ToolbarButton type="text" onClick={handleOpenQuickPanel} disabled={disabled}> <ToolbarButton type="text" onClick={handleOpenQuickPanel} disabled={disabled}>
<FileSearchOutlined /> <LibraryBig size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -3,6 +3,7 @@ import { QuickPanelListItem, useQuickPanel } from '@renderer/components/QuickPan
import { useMCPServers } from '@renderer/hooks/useMCPServers' import { useMCPServers } from '@renderer/hooks/useMCPServers'
import { MCPPrompt, MCPServer } from '@renderer/types' import { MCPPrompt, MCPServer } from '@renderer/types'
import { Form, Input, Modal, Tooltip } from 'antd' import { Form, Input, Modal, Tooltip } from 'antd'
import { SquareTerminal } from 'lucide-react'
import { FC, useCallback, useImperativeHandle, useMemo } from 'react' import { FC, useCallback, useImperativeHandle, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@ -303,7 +304,7 @@ const MCPToolsButton: FC<Props> = ({
return ( return (
<Tooltip placement="top" title={t('settings.mcp.title')} arrow> <Tooltip placement="top" title={t('settings.mcp.title')} arrow>
<ToolbarButton type="text" onClick={handleOpenQuickPanel}> <ToolbarButton type="text" onClick={handleOpenQuickPanel}>
<CodeOutlined style={{ color: buttonEnabled ? 'var(--color-primary)' : 'var(--color-icon)' }} /> <SquareTerminal size={18} color={buttonEnabled ? 'var(--color-primary)' : 'var(--color-icon)'} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -9,6 +9,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
import { Model } from '@renderer/types' import { Model } from '@renderer/types'
import { Avatar, Tooltip } from 'antd' import { Avatar, Tooltip } from 'antd'
import { first, sortBy } from 'lodash' import { first, sortBy } from 'lodash'
import { AtSign } from 'lucide-react'
import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react' import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@ -104,7 +105,7 @@ const MentionModelsButton: FC<Props> = ({ ref, mentionModels, onMentionModel, To
return ( return (
<Tooltip placement="top" title={t('agents.edit.model.select.title')} arrow> <Tooltip placement="top" title={t('agents.edit.model.select.title')} arrow>
<ToolbarButton type="text" onClick={handleOpenQuickPanel}> <ToolbarButton type="text" onClick={handleOpenQuickPanel}>
<i className="iconfont icon-at" style={{ fontSize: 18 }}></i> <AtSign size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -1,6 +1,6 @@
import { PicCenterOutlined } from '@ant-design/icons'
import { useShortcut, useShortcutDisplay } from '@renderer/hooks/useShortcuts' import { useShortcut, useShortcutDisplay } from '@renderer/hooks/useShortcuts'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { CircleFadingPlus } from 'lucide-react'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -20,7 +20,7 @@ const NewContextButton: FC<Props> = ({ onNewContext, ToolbarButton }) => {
<Container> <Container>
<Tooltip placement="top" title={t('chat.input.new.context', { Command: newContextShortcut })} arrow> <Tooltip placement="top" title={t('chat.input.new.context', { Command: newContextShortcut })} arrow>
<ToolbarButton type="text" onClick={onNewContext}> <ToolbarButton type="text" onClick={onNewContext}>
<PicCenterOutlined /> <CircleFadingPlus size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
</Container> </Container>

View File

@ -4,6 +4,7 @@ import { QuickPanelListItem, QuickPanelOpenOptions } from '@renderer/components/
import QuickPhraseService from '@renderer/services/QuickPhraseService' import QuickPhraseService from '@renderer/services/QuickPhraseService'
import { QuickPhrase } from '@renderer/types' import { QuickPhrase } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { Zap } from 'lucide-react'
import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react' import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@ -99,7 +100,7 @@ const QuickPhrasesButton = ({ ref, setInputValue, resizeTextArea, ToolbarButton
return ( return (
<Tooltip placement="top" title={t('settings.quickPhrase.title')} arrow> <Tooltip placement="top" title={t('settings.quickPhrase.title')} arrow>
<ToolbarButton type="text" onClick={handleOpenQuickPanel}> <ToolbarButton type="text" onClick={handleOpenQuickPanel}>
<ThunderboltOutlined /> <Zap size={18} />
</ToolbarButton> </ToolbarButton>
</Tooltip> </Tooltip>
) )

View File

@ -1,4 +1,4 @@
import { SearchOutlined, SyncOutlined, TranslationOutlined } from '@ant-design/icons' import { SyncOutlined, TranslationOutlined } from '@ant-design/icons'
import { isOpenAIWebSearch } from '@renderer/config/models' import { isOpenAIWebSearch } from '@renderer/config/models'
import { getModelUniqId } from '@renderer/services/ModelService' import { getModelUniqId } from '@renderer/services/ModelService'
import { Message, Model } from '@renderer/types' import { Message, Model } from '@renderer/types'
@ -6,6 +6,7 @@ import { getBriefInfo } from '@renderer/utils'
import { withMessageThought } from '@renderer/utils/formats' import { withMessageThought } from '@renderer/utils/formats'
import { Divider, Flex } from 'antd' import { Divider, Flex } from 'antd'
import { clone } from 'lodash' import { clone } from 'lodash'
import { Search } from 'lucide-react'
import React, { Fragment, useMemo } from 'react' import React, { Fragment, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import BarLoader from 'react-spinners/BarLoader' import BarLoader from 'react-spinners/BarLoader'
@ -182,7 +183,7 @@ const MessageContent: React.FC<Props> = ({ message: _message, model }) => {
if (message.status === 'searching') { if (message.status === 'searching') {
return ( return (
<SearchingContainer> <SearchingContainer>
<SearchOutlined size={24} /> <Search size={24} />
<SearchingText>{t('message.searching')}</SearchingText> <SearchingText>{t('message.searching')}</SearchingText>
<BarLoader color="#1677ff" /> <BarLoader color="#1677ff" />
</SearchingContainer> </SearchingContainer>

View File

@ -1,17 +1,4 @@
import { import { CheckOutlined, EditOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons'
CheckOutlined,
DeleteOutlined,
EditOutlined,
ForkOutlined,
LikeFilled,
LikeOutlined,
MenuOutlined,
QuestionCircleOutlined,
SaveOutlined,
SyncOutlined,
TranslationOutlined
} from '@ant-design/icons'
import { UploadOutlined } from '@ant-design/icons'
import ObsidianExportPopup from '@renderer/components/Popups/ObsidianExportPopup' import ObsidianExportPopup from '@renderer/components/Popups/ObsidianExportPopup'
import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup' import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
import TextEditPopup from '@renderer/components/Popups/TextEditPopup' import TextEditPopup from '@renderer/components/Popups/TextEditPopup'
@ -37,6 +24,20 @@ import { withMessageThought } from '@renderer/utils/formats'
import { Button, Dropdown, Popconfirm, Tooltip } from 'antd' import { Button, Dropdown, Popconfirm, Tooltip } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { clone } from 'lodash' import { clone } from 'lodash'
import {
AtSign,
Copy,
FilePenLine,
Languages,
Menu,
RefreshCw,
Save,
Share,
Split,
ThumbsDown,
ThumbsUp,
Trash
} from 'lucide-react'
import { FC, memo, useCallback, useMemo, useState } from 'react' import { FC, memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -159,24 +160,31 @@ const MessageMenubar: FC<Props> = (props) => {
content: content.trim(), content: content.trim(),
metadata: { metadata: {
...message.metadata, ...message.metadata,
generateImage: imageUrls.length > 0 ? { generateImage:
type: 'url', imageUrls.length > 0
images: imageUrls ? {
} : undefined type: 'url',
images: imageUrls
}
: undefined
} }
}) })
resendMessage && handleResendUserMessage({ resendMessage &&
...message, handleResendUserMessage({
content: content.trim(), ...message,
metadata: { content: content.trim(),
...message.metadata, metadata: {
generateImage: imageUrls.length > 0 ? { ...message.metadata,
type: 'url', generateImage:
images: imageUrls imageUrls.length > 0
} : undefined ? {
} type: 'url',
}) images: imageUrls
}
: undefined
}
})
} }
}, [message, editMessage, handleResendUserMessage, t]) }, [message, editMessage, handleResendUserMessage, t])
@ -213,18 +221,28 @@ const MessageMenubar: FC<Props> = (props) => {
{ {
label: t('chat.save'), label: t('chat.save'),
key: 'save', key: 'save',
icon: <SaveOutlined />, icon: <Save size={16} />,
onClick: () => { onClick: () => {
const fileName = dayjs(message.createdAt).format('YYYYMMDDHHmm') + '.md' const fileName = dayjs(message.createdAt).format('YYYYMMDDHHmm') + '.md'
window.api.file.save(fileName, message.content) window.api.file.save(fileName, message.content)
} }
}, },
{ label: t('common.edit'), key: 'edit', icon: <EditOutlined />, onClick: onEdit }, {
{ label: t('chat.message.new.branch'), key: 'new-branch', icon: <ForkOutlined />, onClick: onNewBranch }, label: t('common.edit'),
key: 'edit',
icon: <FilePenLine size={16} />,
onClick: onEdit
},
{
label: t('chat.message.new.branch'),
key: 'new-branch',
icon: <Split size={16} />,
onClick: onNewBranch
},
{ {
label: t('chat.topics.export.title'), label: t('chat.topics.export.title'),
key: 'export', key: 'export',
icon: <UploadOutlined />, icon: <Share size={16} color="var(--color-icon)" style={{ marginTop: 3 }} />,
children: [ children: [
exportMenuOptions.image && { exportMenuOptions.image && {
label: t('chat.topics.copy.image'), label: t('chat.topics.copy.image'),
@ -361,7 +379,7 @@ const MessageMenubar: FC<Props> = (props) => {
)} )}
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}> <Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onCopy}> <ActionButton className="message-action-button" onClick={onCopy}>
{!copied && <i className="iconfont icon-copy"></i>} {!copied && <Copy size={16} />}
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />} {copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
@ -378,7 +396,7 @@ const MessageMenubar: FC<Props> = (props) => {
open={showRegenerateTooltip} open={showRegenerateTooltip}
onOpenChange={setShowRegenerateTooltip}> onOpenChange={setShowRegenerateTooltip}>
<ActionButton className="message-action-button"> <ActionButton className="message-action-button">
<SyncOutlined /> <RefreshCw size={16} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
</Popconfirm> </Popconfirm>
@ -386,7 +404,7 @@ const MessageMenubar: FC<Props> = (props) => {
{isAssistantMessage && ( {isAssistantMessage && (
<Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}> <Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onMentionModel}> <ActionButton className="message-action-button" onClick={onMentionModel}>
<i className="iconfont icon-at" style={{ fontSize: 16 }}></i> <AtSign size={16} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} )}
@ -412,7 +430,7 @@ const MessageMenubar: FC<Props> = (props) => {
arrow> arrow>
<Tooltip title={t('chat.translate')} mouseEnterDelay={1.2}> <Tooltip title={t('chat.translate')} mouseEnterDelay={1.2}>
<ActionButton className="message-action-button" onClick={(e) => e.stopPropagation()}> <ActionButton className="message-action-button" onClick={(e) => e.stopPropagation()}>
<TranslationOutlined /> <Languages size={16} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
</Dropdown> </Dropdown>
@ -420,7 +438,7 @@ const MessageMenubar: FC<Props> = (props) => {
{isAssistantMessage && isGrouped && ( {isAssistantMessage && isGrouped && (
<Tooltip title={t('chat.message.useful')} mouseEnterDelay={0.8}> <Tooltip title={t('chat.message.useful')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onUseful}> <ActionButton className="message-action-button" onClick={onUseful}>
{message.useful ? <LikeFilled /> : <LikeOutlined />} {message.useful ? <ThumbsUp size={16} /> : <ThumbsDown size={16} />}
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} )}
@ -436,7 +454,7 @@ const MessageMenubar: FC<Props> = (props) => {
mouseEnterDelay={1} mouseEnterDelay={1}
open={showDeleteTooltip} open={showDeleteTooltip}
onOpenChange={setShowDeleteTooltip}> onOpenChange={setShowDeleteTooltip}>
<DeleteOutlined /> <Trash size={16} />
</Tooltip> </Tooltip>
</ActionButton> </ActionButton>
</Popconfirm> </Popconfirm>
@ -447,7 +465,7 @@ const MessageMenubar: FC<Props> = (props) => {
placement="topRight" placement="topRight"
arrow> arrow>
<ActionButton className="message-action-button" onClick={(e) => e.stopPropagation()}> <ActionButton className="message-action-button" onClick={(e) => e.stopPropagation()}>
<MenuOutlined /> <Menu size={19} />
</ActionButton> </ActionButton>
</Dropdown> </Dropdown>
)} )}

View File

@ -29,7 +29,6 @@ import ChatNavigation from './ChatNavigation'
import MessageAnchorLine from './MessageAnchorLine' import MessageAnchorLine from './MessageAnchorLine'
import MessageGroup from './MessageGroup' import MessageGroup from './MessageGroup'
import NarrowLayout from './NarrowLayout' import NarrowLayout from './NarrowLayout'
import NewTopicButton from './NewTopicButton'
import Prompt from './Prompt' import Prompt from './Prompt'
interface MessagesProps { interface MessagesProps {
@ -225,7 +224,6 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
ref={containerRef} ref={containerRef}
$right={topicPosition === 'left'}> $right={topicPosition === 'left'}>
<NarrowLayout style={{ display: 'flex', flexDirection: 'column-reverse' }}> <NarrowLayout style={{ display: 'flex', flexDirection: 'column-reverse' }}>
{messages.length >= 2 && !loading && <NewTopicButton />}
<InfiniteScroll <InfiniteScroll
dataLength={displayMessages.length} dataLength={displayMessages.length}
next={loadMoreMessages} next={loadMoreMessages}

View File

@ -1,4 +1,3 @@
import { FormOutlined, SearchOutlined } from '@ant-design/icons'
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar' import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import MinAppsPopover from '@renderer/components/Popups/MinAppsPopover' import MinAppsPopover from '@renderer/components/Popups/MinAppsPopover'
@ -15,6 +14,7 @@ import { setNarrowMode } from '@renderer/store/settings'
import { Assistant, Topic } from '@renderer/types' import { Assistant, Topic } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { t } from 'i18next' import { t } from 'i18next'
import { LayoutGrid, MessageSquareDiff, PanelLeftClose, PanelRightClose, Search } from 'lucide-react'
import { FC } from 'react' import { FC } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
@ -61,12 +61,12 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: 0 }}> <NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: 0 }}>
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={0.8}> <Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={0.8}>
<NavbarIcon onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 16 : 0 }}> <NavbarIcon onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 16 : 0 }}>
<i className="iconfont icon-hide-sidebar" /> <PanelLeftClose size={18} />
</NavbarIcon> </NavbarIcon>
</Tooltip> </Tooltip>
<Tooltip title={t('settings.shortcuts.new_topic')} mouseEnterDelay={0.8}> <Tooltip title={t('settings.shortcuts.new_topic')} mouseEnterDelay={0.8}>
<NavbarIcon onClick={() => EventEmitter.emit(EVENT_NAMES.ADD_NEW_TOPIC)}> <NavbarIcon onClick={() => EventEmitter.emit(EVENT_NAMES.ADD_NEW_TOPIC)} style={{ marginRight: 5 }}>
<FormOutlined /> <MessageSquareDiff size={18} />
</NavbarIcon> </NavbarIcon>
</Tooltip> </Tooltip>
</NavbarLeft> </NavbarLeft>
@ -78,7 +78,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
<NavbarIcon <NavbarIcon
onClick={() => toggleShowAssistants()} onClick={() => toggleShowAssistants()}
style={{ marginRight: 8, marginLeft: isMac ? 4 : -12 }}> style={{ marginRight: 8, marginLeft: isMac ? 4 : -12 }}>
<i className="iconfont icon-show-sidebar" /> <PanelRightClose size={18} />
</NavbarIcon> </NavbarIcon>
</Tooltip> </Tooltip>
)} )}
@ -88,7 +88,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
<UpdateAppButton /> <UpdateAppButton />
<Tooltip title={t('chat.assistant.search.placeholder')} mouseEnterDelay={0.8}> <Tooltip title={t('chat.assistant.search.placeholder')} mouseEnterDelay={0.8}>
<NarrowIcon onClick={() => SearchPopup.show()}> <NarrowIcon onClick={() => SearchPopup.show()}>
<SearchOutlined /> <Search size={18} />
</NarrowIcon> </NarrowIcon>
</Tooltip> </Tooltip>
<Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}> <Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}>
@ -100,14 +100,14 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
<MinAppsPopover> <MinAppsPopover>
<Tooltip title={t('minapp.title')} mouseEnterDelay={0.8}> <Tooltip title={t('minapp.title')} mouseEnterDelay={0.8}>
<NarrowIcon> <NarrowIcon>
<i className="iconfont icon-appstore" /> <LayoutGrid size={18} />
</NarrowIcon> </NarrowIcon>
</Tooltip> </Tooltip>
</MinAppsPopover> </MinAppsPopover>
)} )}
{topicPosition === 'right' && ( {topicPosition === 'right' && (
<NarrowIcon onClick={toggleShowTopics}> <NarrowIcon onClick={toggleShowTopics}>
<i className={`iconfont icon-${showTopics ? 'show' : 'hide'}-sidebar`} /> {showTopics ? <PanelRightClose size={18} /> : <PanelLeftClose size={18} />}
</NarrowIcon> </NarrowIcon>
)} )}
</HStack> </HStack>

View File

@ -1,4 +1,4 @@
import { CheckOutlined, QuestionCircleOutlined, ReloadOutlined, SettingOutlined } from '@ant-design/icons' import { CheckOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import { import {
@ -44,6 +44,7 @@ import {
import { Assistant, AssistantSettings, CodeStyleVarious, ThemeMode, TranslateLanguageVarious } from '@renderer/types' import { Assistant, AssistantSettings, CodeStyleVarious, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
import { modalConfirm } from '@renderer/utils' import { modalConfirm } from '@renderer/utils'
import { Button, Col, InputNumber, Row, Segmented, Select, Slider, Switch, Tooltip } from 'antd' import { Button, Col, InputNumber, Row, Segmented, Select, Slider, Switch, Tooltip } from 'antd'
import { CircleHelp, RotateCcw, Settings2 } from 'lucide-react'
import { FC, useCallback, useEffect, useState } from 'react' import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -179,13 +180,13 @@ const SettingsTab: FC<Props> = (props) => {
<HStack alignItems="center"> <HStack alignItems="center">
{t('assistants.settings.title')}{' '} {t('assistants.settings.title')}{' '}
<Tooltip title={t('chat.settings.reset')}> <Tooltip title={t('chat.settings.reset')}>
<ReloadOutlined onClick={onReset} style={{ cursor: 'pointer', fontSize: 12, padding: '0 3px' }} /> <RotateCcw size={20} onClick={onReset} style={{ cursor: 'pointer', padding: '0 3px' }} />
</Tooltip> </Tooltip>
</HStack> </HStack>
<Button <Button
type="text" type="text"
size="small" size="small"
icon={<SettingOutlined />} icon={<Settings2 size={16} />}
onClick={() => AssistantSettingsPopup.show({ assistant, tab: 'model' })} onClick={() => AssistantSettingsPopup.show({ assistant, tab: 'model' })}
/> />
</SettingSubtitle> </SettingSubtitle>
@ -193,7 +194,7 @@ const SettingsTab: FC<Props> = (props) => {
<Row align="middle"> <Row align="middle">
<Label>{t('chat.settings.temperature')}</Label> <Label>{t('chat.settings.temperature')}</Label>
<Tooltip title={t('chat.settings.temperature.tip')}> <Tooltip title={t('chat.settings.temperature.tip')}>
<QuestionIcon /> <CircleHelp size={14} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</Row> </Row>
<Row align="middle" gutter={10}> <Row align="middle" gutter={10}>
@ -211,7 +212,7 @@ const SettingsTab: FC<Props> = (props) => {
<Row align="middle"> <Row align="middle">
<Label>{t('chat.settings.context_count')}</Label> <Label>{t('chat.settings.context_count')}</Label>
<Tooltip title={t('chat.settings.context_count.tip')}> <Tooltip title={t('chat.settings.context_count.tip')}>
<QuestionIcon /> <CircleHelp size={14} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</Row> </Row>
<Row align="middle" gutter={10}> <Row align="middle" gutter={10}>
@ -243,7 +244,7 @@ const SettingsTab: FC<Props> = (props) => {
<HStack alignItems="center"> <HStack alignItems="center">
<Label>{t('chat.settings.max_tokens')}</Label> <Label>{t('chat.settings.max_tokens')}</Label>
<Tooltip title={t('chat.settings.max_tokens.tip')}> <Tooltip title={t('chat.settings.max_tokens.tip')}>
<QuestionIcon /> <CircleHelp size={14} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</HStack> </HStack>
<Switch <Switch
@ -288,7 +289,7 @@ const SettingsTab: FC<Props> = (props) => {
<Row align="middle"> <Row align="middle">
<Label>{t('assistants.settings.reasoning_effort')}</Label> <Label>{t('assistants.settings.reasoning_effort')}</Label>
<Tooltip title={t('assistants.settings.reasoning_effort.tip')}> <Tooltip title={t('assistants.settings.reasoning_effort.tip')}>
<QuestionIcon /> <CircleHelp size={14} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</Row> </Row>
<Row align="middle" gutter={10}> <Row align="middle" gutter={10}>
@ -371,7 +372,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.code_cacheable')}{' '} {t('chat.settings.code_cacheable')}{' '}
<Tooltip title={t('chat.settings.code_cacheable.tip')}> <Tooltip title={t('chat.settings.code_cacheable.tip')}>
<QuestionIcon style={{ marginLeft: 4 }} /> <CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</SettingRowTitleSmall> </SettingRowTitleSmall>
<Switch size="small" checked={codeCacheable} onChange={(checked) => dispatch(setCodeCacheable(checked))} /> <Switch size="small" checked={codeCacheable} onChange={(checked) => dispatch(setCodeCacheable(checked))} />
@ -383,7 +384,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.code_cache_max_size')} {t('chat.settings.code_cache_max_size')}
<Tooltip title={t('chat.settings.code_cache_max_size.tip')}> <Tooltip title={t('chat.settings.code_cache_max_size.tip')}>
<QuestionIcon style={{ marginLeft: 4 }} /> <CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</SettingRowTitleSmall> </SettingRowTitleSmall>
<InputNumber <InputNumber
@ -401,7 +402,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.code_cache_ttl')} {t('chat.settings.code_cache_ttl')}
<Tooltip title={t('chat.settings.code_cache_ttl.tip')}> <Tooltip title={t('chat.settings.code_cache_ttl.tip')}>
<QuestionIcon style={{ marginLeft: 4 }} /> <CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</SettingRowTitleSmall> </SettingRowTitleSmall>
<InputNumber <InputNumber
@ -419,7 +420,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.code_cache_threshold')} {t('chat.settings.code_cache_threshold')}
<Tooltip title={t('chat.settings.code_cache_threshold.tip')}> <Tooltip title={t('chat.settings.code_cache_threshold.tip')}>
<QuestionIcon style={{ marginLeft: 4 }} /> <CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</SettingRowTitleSmall> </SettingRowTitleSmall>
<InputNumber <InputNumber
@ -439,7 +440,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.thought_auto_collapse')} {t('chat.settings.thought_auto_collapse')}
<Tooltip title={t('chat.settings.thought_auto_collapse.tip')}> <Tooltip title={t('chat.settings.thought_auto_collapse.tip')}>
<QuestionIcon style={{ marginLeft: 4 }} /> <CircleHelp size={14} style={{ marginLeft: 4 }} color="var(--color-text-2)" />
</Tooltip> </Tooltip>
</SettingRowTitleSmall> </SettingRowTitleSmall>
<Switch <Switch
@ -663,12 +664,6 @@ const Label = styled.p`
margin-right: 5px; margin-right: 5px;
` `
const QuestionIcon = styled(QuestionCircleOutlined)`
font-size: 12px;
cursor: pointer;
color: var(--color-text-3);
`
const SettingRowTitleSmall = styled(SettingRowTitle)` const SettingRowTitleSmall = styled(SettingRowTitle)`
font-size: 13px; font-size: 13px;
` `

View File

@ -1,4 +1,3 @@
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup' import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
@ -48,8 +47,7 @@ const HomeTabs: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssistant,
const assistantTab = { const assistantTab = {
label: t('assistants.abbr'), label: t('assistants.abbr'),
value: 'assistants', value: 'assistants'
icon: <i className="iconfont icon-business-smart-assistant" />
} }
const onCreateAssistant = async () => { const onCreateAssistant = async () => {
@ -104,13 +102,11 @@ const HomeTabs: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssistant,
position === 'left' && topicPosition === 'left' ? assistantTab : undefined, position === 'left' && topicPosition === 'left' ? assistantTab : undefined,
{ {
label: t('common.topics'), label: t('common.topics'),
value: 'topic', value: 'topic'
icon: <BarsOutlined />
}, },
{ {
label: t('settings.title'), label: t('settings.title'),
value: 'settings', value: 'settings'
icon: <SettingOutlined />
} }
].filter(Boolean) as SegmentedProps['options'] ].filter(Boolean) as SegmentedProps['options']
} }

View File

@ -1,14 +1,4 @@
import { import { CopyOutlined, DeleteOutlined, EditOutlined, RedoOutlined } from '@ant-design/icons'
ColumnHeightOutlined,
CopyOutlined,
DeleteOutlined,
EditOutlined,
PlusOutlined,
RedoOutlined,
SearchOutlined,
SettingOutlined,
VerticalAlignMiddleOutlined
} from '@ant-design/icons'
import CustomTag from '@renderer/components/CustomTag' import CustomTag from '@renderer/components/CustomTag'
import Ellipsis from '@renderer/components/Ellipsis' import Ellipsis from '@renderer/components/Ellipsis'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
@ -23,6 +13,7 @@ import { formatFileSize } from '@renderer/utils'
import { bookExts, documentExts, textExts, thirdPartyApplicationExts } from '@shared/config/constant' import { bookExts, documentExts, textExts, thirdPartyApplicationExts } from '@shared/config/constant'
import { Alert, Button, Dropdown, Empty, message, Tag, Tooltip, Upload } from 'antd' import { Alert, Button, Dropdown, Empty, message, Tag, Tooltip, Upload } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { ChevronsDown, ChevronsUp, Plus, Search, Settings2 } from 'lucide-react'
import VirtualList from 'rc-virtual-list' import VirtualList from 'rc-virtual-list'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -238,7 +229,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
<ModelInfo> <ModelInfo>
<Button <Button
type="text" type="text"
icon={<SettingOutlined />} icon={<Settings2 size={18} color="var(--color-icon)" />}
onClick={() => KnowledgeSettingsPopup.show({ base })} onClick={() => KnowledgeSettingsPopup.show({ base })}
size="small" size="small"
/> />
@ -277,7 +268,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
size="small" size="small"
shape="round" shape="round"
onClick={() => KnowledgeSearchPopup.show({ base })} onClick={() => KnowledgeSearchPopup.show({ base })}
icon={<SearchOutlined />} icon={<Search size={14} />}
disabled={disabled}> disabled={disabled}>
{t('knowledge.search')} {t('knowledge.search')}
</Button> </Button>
@ -286,7 +277,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
size="small" size="small"
shape="circle" shape="circle"
onClick={() => setExpandAll(!expandAll)} onClick={() => setExpandAll(!expandAll)}
icon={expandAll ? <VerticalAlignMiddleOutlined /> : <ColumnHeightOutlined />} icon={expandAll ? <ChevronsUp size={14} /> : <ChevronsDown size={14} />}
disabled={disabled} disabled={disabled}
/> />
</Tooltip> </Tooltip>
@ -306,7 +297,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
extra={ extra={
<Button <Button
type="text" type="text"
icon={<PlusOutlined />} icon={<Plus size={16} />}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleAddFile() handleAddFile()
@ -393,7 +384,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
extra={ extra={
<Button <Button
type="text" type="text"
icon={<PlusOutlined />} icon={<Plus size={16} />}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleAddDirectory() handleAddDirectory()
@ -445,7 +436,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
extra={ extra={
<Button <Button
type="text" type="text"
icon={<PlusOutlined />} icon={<Plus size={16} />}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleAddUrl() handleAddUrl()
@ -522,7 +513,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
extra={ extra={
<Button <Button
type="text" type="text"
icon={<PlusOutlined />} icon={<Plus size={16} />}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleAddSitemap() handleAddSitemap()
@ -577,7 +568,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
extra={ extra={
<Button <Button
type="text" type="text"
icon={<PlusOutlined />} icon={<Plus size={16} />}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleAddNote() handleAddNote()

View File

@ -1,11 +1,4 @@
import { import { DeleteOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
DeleteOutlined,
EditOutlined,
FileTextOutlined,
PlusOutlined,
SearchOutlined,
SettingOutlined
} from '@ant-design/icons'
import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar'
import DragableList from '@renderer/components/DragableList' import DragableList from '@renderer/components/DragableList'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
@ -18,6 +11,7 @@ import { NavbarIcon } from '@renderer/pages/home/Navbar'
import KnowledgeSearchPopup from '@renderer/pages/knowledge/components/KnowledgeSearchPopup' import KnowledgeSearchPopup from '@renderer/pages/knowledge/components/KnowledgeSearchPopup'
import { KnowledgeBase } from '@renderer/types' import { KnowledgeBase } from '@renderer/types'
import { Dropdown, Empty, MenuProps } from 'antd' import { Dropdown, Empty, MenuProps } from 'antd'
import { Book, Plus, Search } from 'lucide-react'
import { FC, useCallback, useEffect, useState } from 'react' import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -105,7 +99,7 @@ const KnowledgePage: FC = () => {
<NavbarRight> <NavbarRight>
<HStack alignItems="center"> <HStack alignItems="center">
<NarrowIcon onClick={() => selectedBase && KnowledgeSearchPopup.show({ base: selectedBase })}> <NarrowIcon onClick={() => selectedBase && KnowledgeSearchPopup.show({ base: selectedBase })}>
<SearchOutlined /> <Search size={18} />
</NarrowIcon> </NarrowIcon>
</HStack> </HStack>
</NavbarRight> </NavbarRight>
@ -124,7 +118,7 @@ const KnowledgePage: FC = () => {
<div> <div>
<ListItem <ListItem
active={selectedBase?.id === base.id} active={selectedBase?.id === base.id}
icon={<FileTextOutlined />} icon={<Book size={16} />}
title={base.name} title={base.name}
onClick={() => setSelectedBase(base)} onClick={() => setSelectedBase(base)}
/> />
@ -135,7 +129,7 @@ const KnowledgePage: FC = () => {
{!isDragging && ( {!isDragging && (
<AddKnowledgeItem onClick={handleAddKnowledge}> <AddKnowledgeItem onClick={handleAddKnowledge}>
<AddKnowledgeName> <AddKnowledgeName>
<PlusOutlined style={{ color: 'var(--color-text-2)', marginRight: 4 }} /> <Plus size={18} />
{t('button.add')} {t('button.add')}
</AddKnowledgeName> </AddKnowledgeName>
</AddKnowledgeItem> </AddKnowledgeItem>
@ -243,6 +237,10 @@ const AddKnowledgeName = styled.div`
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
font-size: 13px; font-size: 13px;
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
` `
const NarrowIcon = styled(NavbarIcon)` const NarrowIcon = styled(NavbarIcon)`

View File

@ -1,5 +1,4 @@
import { GithubOutlined } from '@ant-design/icons' import { GithubOutlined } from '@ant-design/icons'
import { FileProtectOutlined, GlobalOutlined, MailOutlined, SoundOutlined } from '@ant-design/icons'
import IndicatorLight from '@renderer/components/IndicatorLight' import IndicatorLight from '@renderer/components/IndicatorLight'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import { isWindows } from '@renderer/config/constant' import { isWindows } from '@renderer/config/constant'
@ -15,6 +14,7 @@ import { ThemeMode } from '@renderer/types'
import { compareVersions, runAsyncFunction } from '@renderer/utils' import { compareVersions, runAsyncFunction } from '@renderer/utils'
import { Avatar, Button, Progress, Row, Switch, Tag } from 'antd' import { Avatar, Button, Progress, Row, Switch, Tag } from 'antd'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import { FileCheck, Github, Globe, Mail, Rss } from 'lucide-react'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Markdown from 'react-markdown' import Markdown from 'react-markdown'
@ -181,7 +181,7 @@ const AboutSettings: FC = () => {
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingRow> <SettingRow>
<SettingRowTitle> <SettingRowTitle>
<SoundOutlined /> <Rss size={18} />
{t('settings.about.releases.title')} {t('settings.about.releases.title')}
</SettingRowTitle> </SettingRowTitle>
<Button onClick={showReleases}>{t('settings.about.releases.button')}</Button> <Button onClick={showReleases}>{t('settings.about.releases.button')}</Button>
@ -189,7 +189,7 @@ const AboutSettings: FC = () => {
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle> <SettingRowTitle>
<GlobalOutlined /> <Globe size={18} />
{t('settings.about.website.title')} {t('settings.about.website.title')}
</SettingRowTitle> </SettingRowTitle>
<Button onClick={() => onOpenWebsite('https://cherry-ai.com')}>{t('settings.about.website.button')}</Button> <Button onClick={() => onOpenWebsite('https://cherry-ai.com')}>{t('settings.about.website.button')}</Button>
@ -197,7 +197,7 @@ const AboutSettings: FC = () => {
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle> <SettingRowTitle>
<GithubOutlined /> <Github size={18} />
{t('settings.about.feedback.title')} {t('settings.about.feedback.title')}
</SettingRowTitle> </SettingRowTitle>
<Button onClick={() => onOpenWebsite('https://github.com/CherryHQ/cherry-studio/issues/new/choose')}> <Button onClick={() => onOpenWebsite('https://github.com/CherryHQ/cherry-studio/issues/new/choose')}>
@ -207,7 +207,7 @@ const AboutSettings: FC = () => {
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle> <SettingRowTitle>
<FileProtectOutlined /> <FileCheck size={18} />
{t('settings.about.license.title')} {t('settings.about.license.title')}
</SettingRowTitle> </SettingRowTitle>
<Button onClick={showLicense}>{t('settings.about.license.button')}</Button> <Button onClick={showLicense}>{t('settings.about.license.button')}</Button>
@ -215,7 +215,8 @@ const AboutSettings: FC = () => {
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle> <SettingRowTitle>
<MailOutlined /> {t('settings.about.contact.title')} <Mail size={18} />
{t('settings.about.contact.title')}
</SettingRowTitle> </SettingRowTitle>
<Button onClick={mailto}>{t('settings.about.contact.button')}</Button> <Button onClick={mailto}>{t('settings.about.contact.button')}</Button>
</SettingRow> </SettingRow>

View File

@ -1,5 +1,4 @@
import { CloseOutlined } from '@ant-design/icons' import { CloseOutlined } from '@ant-design/icons'
import { FileSearchOutlined, FolderOutlined, PictureOutlined, TranslationOutlined } from '@ant-design/icons'
import { import {
DragDropContext, DragDropContext,
Draggable, Draggable,
@ -11,6 +10,7 @@ import {
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { setSidebarIcons } from '@renderer/store/settings' import { setSidebarIcons } from '@renderer/store/settings'
import { message } from 'antd' import { message } from 'antd'
import { Folder, Languages, LayoutGrid, LibraryBig, MessageSquareQuote, Palette, Sparkle } from 'lucide-react'
import { FC, useCallback, useMemo } from 'react' import { FC, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -109,13 +109,13 @@ const SidebarIconsManager: FC<SidebarIconsManagerProps> = ({
// 使用useMemo缓存图标映射 // 使用useMemo缓存图标映射
const iconMap = useMemo( const iconMap = useMemo(
() => ({ () => ({
assistants: <i className="iconfont icon-chat" />, assistants: <MessageSquareQuote size={16} />,
agents: <i className="iconfont icon-business-smart-assistant" />, agents: <Sparkle size={16} />,
paintings: <PictureOutlined style={{ fontSize: 14 }} />, paintings: <Palette size={16} />,
translate: <TranslationOutlined />, translate: <Languages size={16} />,
minapp: <i className="iconfont icon-appstore" />, minapp: <LayoutGrid size={16} />,
knowledge: <FileSearchOutlined />, knowledge: <LibraryBig size={16} />,
files: <FolderOutlined /> files: <Folder size={15} />
}), }),
[] []
) )

View File

@ -1,8 +1,9 @@
import { EditOutlined, ExportOutlined, SearchOutlined } from '@ant-design/icons' import { EditOutlined, ExportOutlined } from '@ant-design/icons'
import { NavbarRight } from '@renderer/components/app/Navbar' import { NavbarRight } from '@renderer/components/app/Navbar'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import { isWindows } from '@renderer/config/constant' import { isWindows } from '@renderer/config/constant'
import { Button } from 'antd' import { Button } from 'antd'
import { Search } from 'lucide-react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@ -21,7 +22,7 @@ export const McpSettingsNavbar = () => {
size="small" size="small"
type="text" type="text"
onClick={() => navigate('/settings/mcp/npx-search')} onClick={() => navigate('/settings/mcp/npx-search')}
icon={<SearchOutlined />} icon={<Search size={14} />}
className="nodrag" className="nodrag"
style={{ fontSize: 13, height: 28, borderRadius: 20 }}> style={{ fontSize: 13, height: 28, borderRadius: 20 }}>
{t('settings.mcp.searchNpx')} {t('settings.mcp.searchNpx')}

View File

@ -1,4 +1,4 @@
import { EditOutlined, MessageOutlined, RedoOutlined, SettingOutlined, TranslationOutlined } from '@ant-design/icons' import { RedoOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import PromptPopup from '@renderer/components/Popups/PromptPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { isEmbeddingModel } from '@renderer/config/models' import { isEmbeddingModel } from '@renderer/config/models'
@ -13,6 +13,7 @@ import { setTranslateModelPrompt } from '@renderer/store/settings'
import { Model } from '@renderer/types' import { Model } from '@renderer/types'
import { Button, Select, Tooltip } from 'antd' import { Button, Select, Tooltip } from 'antd'
import { find, sortBy } from 'lodash' import { find, sortBy } from 'lodash'
import { FolderPen, Languages, MessageSquareMore, Settings2 } from 'lucide-react'
import { FC, useMemo } from 'react' import { FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -82,10 +83,10 @@ const ModelSettings: FC = () => {
<SettingContainer theme={theme}> <SettingContainer theme={theme}>
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingTitle style={{ marginBottom: 12 }}> <SettingTitle style={{ marginBottom: 12 }}>
<div> <HStack alignItems="center" gap={10}>
<MessageOutlined style={iconStyle} /> <MessageSquareMore size={18} color="var(--color-text)" />
{t('settings.models.default_assistant_model')} {t('settings.models.default_assistant_model')}
</div> </HStack>
</SettingTitle> </SettingTitle>
<HStack alignItems="center"> <HStack alignItems="center">
<Select <Select
@ -97,16 +98,16 @@ const ModelSettings: FC = () => {
showSearch showSearch
placeholder={t('settings.models.empty')} placeholder={t('settings.models.empty')}
/> />
<Button icon={<SettingOutlined />} style={{ marginLeft: 8 }} onClick={DefaultAssistantSettings.show} /> <Button icon={<Settings2 size={16} />} style={{ marginLeft: 8 }} onClick={DefaultAssistantSettings.show} />
</HStack> </HStack>
<SettingDescription>{t('settings.models.default_assistant_model_description')}</SettingDescription> <SettingDescription>{t('settings.models.default_assistant_model_description')}</SettingDescription>
</SettingGroup> </SettingGroup>
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingTitle style={{ marginBottom: 12 }}> <SettingTitle style={{ marginBottom: 12 }}>
<div> <HStack alignItems="center" gap={10}>
<EditOutlined style={iconStyle} /> <FolderPen size={18} color="var(--color-text)" />
{t('settings.models.topic_naming_model')} {t('settings.models.topic_naming_model')}
</div> </HStack>
</SettingTitle> </SettingTitle>
<HStack alignItems="center"> <HStack alignItems="center">
<Select <Select
@ -118,16 +119,16 @@ const ModelSettings: FC = () => {
showSearch showSearch
placeholder={t('settings.models.empty')} placeholder={t('settings.models.empty')}
/> />
<Button icon={<SettingOutlined />} style={{ marginLeft: 8 }} onClick={TopicNamingModalPopup.show} /> <Button icon={<Settings2 size={16} />} style={{ marginLeft: 8 }} onClick={TopicNamingModalPopup.show} />
</HStack> </HStack>
<SettingDescription>{t('settings.models.topic_naming_model_description')}</SettingDescription> <SettingDescription>{t('settings.models.topic_naming_model_description')}</SettingDescription>
</SettingGroup> </SettingGroup>
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingTitle style={{ marginBottom: 12 }}> <SettingTitle style={{ marginBottom: 12 }}>
<div> <HStack alignItems="center" gap={10}>
<TranslationOutlined style={iconStyle} /> <Languages size={18} color="var(--color-text)" />
{t('settings.models.translate_model')} {t('settings.models.translate_model')}
</div> </HStack>
</SettingTitle> </SettingTitle>
<HStack alignItems="center"> <HStack alignItems="center">
<Select <Select
@ -139,7 +140,7 @@ const ModelSettings: FC = () => {
showSearch showSearch
placeholder={t('settings.models.empty')} placeholder={t('settings.models.empty')}
/> />
<Button icon={<SettingOutlined />} style={{ marginLeft: 8 }} onClick={onUpdateTranslateModel} /> <Button icon={<Settings2 size={16} />} style={{ marginLeft: 8 }} onClick={onUpdateTranslateModel} />
{translateModelPrompt !== TRANSLATE_PROMPT && ( {translateModelPrompt !== TRANSLATE_PROMPT && (
<Tooltip title={t('common.reset')}> <Tooltip title={t('common.reset')}>
<Button icon={<RedoOutlined />} style={{ marginLeft: 8 }} onClick={onResetTranslatePrompt}></Button> <Button icon={<RedoOutlined />} style={{ marginLeft: 8 }} onClick={onResetTranslatePrompt}></Button>

View File

@ -1,4 +1,4 @@
import { LoadingOutlined, MinusOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons' import { LoadingOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons'
import CustomCollapse from '@renderer/components/CustomCollapse' import CustomCollapse from '@renderer/components/CustomCollapse'
import CustomTag from '@renderer/components/CustomTag' import CustomTag from '@renderer/components/CustomTag'
import ModelTagsWithLabel from '@renderer/components/ModelTagsWithLabel' import ModelTagsWithLabel from '@renderer/components/ModelTagsWithLabel'
@ -21,6 +21,7 @@ import { getDefaultGroupName, isFreeModel, runAsyncFunction } from '@renderer/ut
import { Avatar, Button, Empty, Flex, Modal, Tabs, Tooltip, Typography } from 'antd' import { Avatar, Button, Empty, Flex, Modal, Tabs, Tooltip, Typography } from 'antd'
import Input from 'antd/es/input/Input' import Input from 'antd/es/input/Input'
import { groupBy, isEmpty, uniqBy } from 'lodash' import { groupBy, isEmpty, uniqBy } from 'lodash'
import { Search } from 'lucide-react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -180,7 +181,7 @@ const PopupContainer: React.FC<Props> = ({ provider: _provider, resolve }) => {
centered> centered>
<SearchContainer> <SearchContainer>
<Input <Input
prefix={<SearchOutlined />} prefix={<Search size={14} />}
size="large" size="large"
ref={searchInputRef} ref={searchInputRef}
placeholder={t('settings.provider.search_placeholder')} placeholder={t('settings.provider.search_placeholder')}

View File

@ -1,7 +1,6 @@
import { import {
CheckCircleFilled, CheckCircleFilled,
CloseCircleFilled, CloseCircleFilled,
EditOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
LoadingOutlined, LoadingOutlined,
MinusCircleOutlined, MinusCircleOutlined,
@ -23,6 +22,7 @@ import { Model } from '@renderer/types'
import { maskApiKey } from '@renderer/utils/api' import { maskApiKey } from '@renderer/utils/api'
import { Avatar, Button, Flex, Tooltip, Typography } from 'antd' import { Avatar, Button, Flex, Tooltip, Typography } from 'antd'
import { groupBy, sortBy, toPairs } from 'lodash' import { groupBy, sortBy, toPairs } from 'lodash'
import { ListCheck } from 'lucide-react'
import React, { memo, useCallback, useMemo, useState } from 'react' import React, { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -333,7 +333,7 @@ const ModelList: React.FC<ModelListProps> = ({ providerId, modelStatuses = [], s
)} )}
</Flex> </Flex>
<Flex gap={10} style={{ marginTop: '10px' }}> <Flex gap={10} style={{ marginTop: '10px' }}>
<Button type="primary" onClick={onManageModel} icon={<EditOutlined />}> <Button type="primary" onClick={onManageModel} icon={<ListCheck size={18} />}>
{t('button.manage')} {t('button.manage')}
</Button> </Button>
<Button type="default" onClick={onAddModel} icon={<PlusOutlined />}> <Button type="default" onClick={onAddModel} icon={<PlusOutlined />}>

View File

@ -1,5 +1,5 @@
import { SearchOutlined } from '@ant-design/icons'
import { Input, Tooltip } from 'antd' import { Input, Tooltip } from 'antd'
import { Search } from 'lucide-react'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -33,7 +33,7 @@ const ModelListSearchBar: React.FC<ModelListSearchBarProps> = ({ onSearch }) =>
placeholder={t('models.search')} placeholder={t('models.search')}
size="small" size="small"
style={{ width: '160px' }} style={{ width: '160px' }}
suffix={<SearchOutlined style={{ color: 'var(--color-text-3)' }} />} suffix={<Search size={14} />}
onChange={(e) => handleTextChange(e.target.value)} onChange={(e) => handleTextChange(e.target.value)}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
@ -50,7 +50,12 @@ const ModelListSearchBar: React.FC<ModelListSearchBarProps> = ({ onSearch }) =>
/> />
) : ( ) : (
<Tooltip title={t('models.search')} mouseEnterDelay={0.5}> <Tooltip title={t('models.search')} mouseEnterDelay={0.5}>
<SearchOutlined onClick={() => setSearchVisible(true)} /> <Search
size={14}
color="var(--color-icon)"
onClick={() => setSearchVisible(true)}
style={{ cursor: 'pointer' }}
/>
</Tooltip> </Tooltip>
) )
} }

View File

@ -1,4 +1,4 @@
import { CheckOutlined, ExportOutlined, LoadingOutlined, SettingOutlined } from '@ant-design/icons' import { CheckOutlined, LoadingOutlined, SettingOutlined } from '@ant-design/icons'
import { StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons/SVGIcon' import { StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons/SVGIcon'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import OAuthButton from '@renderer/components/OAuth/OAuthButton' import OAuthButton from '@renderer/components/OAuth/OAuthButton'
@ -17,6 +17,7 @@ import { providerCharge } from '@renderer/utils/oauth'
import { Button, Divider, Flex, Input, Space, Switch, Tooltip } from 'antd' import { Button, Divider, Flex, Input, Space, Switch, Tooltip } from 'antd'
import Link from 'antd/es/typography/Link' import Link from 'antd/es/typography/Link'
import { debounce, isEmpty } from 'lodash' import { debounce, isEmpty } from 'lodash'
import { SquareArrowOutUpRight } from 'lucide-react'
import { FC, useCallback, useDeferredValue, useEffect, useState } from 'react' import { FC, useCallback, useDeferredValue, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -279,8 +280,8 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
<Flex align="center" gap={8}> <Flex align="center" gap={8}>
<ProviderName>{provider.isSystem ? t(`provider.${provider.id}`) : provider.name}</ProviderName> <ProviderName>{provider.isSystem ? t(`provider.${provider.id}`) : provider.name}</ProviderName>
{officialWebsite! && ( {officialWebsite! && (
<Link target="_blank" href={providerConfig.websites.official}> <Link target="_blank" href={providerConfig.websites.official} style={{ display: 'flex' }}>
<ExportOutlined style={{ color: 'var(--color-text)', fontSize: '12px' }} /> <SquareArrowOutUpRight size={14} color="var(--color-text)" />
</Link> </Link>
)} )}
{!provider.isSystem && ( {!provider.isSystem && (
@ -383,10 +384,10 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
{provider.id === 'copilot' && <GithubCopilotSettings provider={provider} setApiKey={setApiKey} />} {provider.id === 'copilot' && <GithubCopilotSettings provider={provider} setApiKey={setApiKey} />}
<SettingSubtitle style={{ marginBottom: 5 }}> <SettingSubtitle style={{ marginBottom: 5 }}>
<Space align="center" style={{ width: '100%', justifyContent: 'space-between' }}> <Space align="center" style={{ width: '100%', justifyContent: 'space-between' }}>
<Space> <HStack alignItems="center" gap={5}>
<SettingSubtitle style={{ marginTop: 0 }}>{t('common.models')}</SettingSubtitle> <SettingSubtitle style={{ marginTop: 0 }}>{t('common.models')}</SettingSubtitle>
{!isEmpty(models) && <ModelListSearchBar onSearch={setModelSearchText} />} {!isEmpty(models) && <ModelListSearchBar onSearch={setModelSearchText} />}
</Space> </HStack>
{!isEmpty(models) && ( {!isEmpty(models) && (
<Tooltip title={t('settings.models.check.button_caption')} mouseEnterDelay={0.5}> <Tooltip title={t('settings.models.check.button_caption')} mouseEnterDelay={0.5}>
<Button <Button

View File

@ -1,4 +1,4 @@
import { DeleteOutlined, EditOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons' import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd' import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import { getProviderLogo } from '@renderer/config/providers' import { getProviderLogo } from '@renderer/config/providers'
@ -7,6 +7,7 @@ import ImageStorage from '@renderer/services/ImageStorage'
import { Provider } from '@renderer/types' import { Provider } from '@renderer/types'
import { droppableReorder, generateColorFromChar, getFirstCharacter, uuid } from '@renderer/utils' import { droppableReorder, generateColorFromChar, getFirstCharacter, uuid } from '@renderer/utils'
import { Avatar, Button, Dropdown, Input, MenuProps, Tag } from 'antd' import { Avatar, Button, Dropdown, Input, MenuProps, Tag } from 'antd'
import { Search } from 'lucide-react'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -178,7 +179,7 @@ const ProvidersList: FC = () => {
const getProviderAvatar = (provider: Provider) => { const getProviderAvatar = (provider: Provider) => {
if (provider.isSystem) { if (provider.isSystem) {
return <ProviderLogo shape="square" src={getProviderLogo(provider.id)} size={25} /> return <ProviderLogo shape="circle" src={getProviderLogo(provider.id)} size={25} />
} }
const customLogo = providerLogos[provider.id] const customLogo = providerLogos[provider.id]
@ -222,7 +223,7 @@ const ProvidersList: FC = () => {
placeholder={t('settings.provider.search')} placeholder={t('settings.provider.search')}
value={searchText} value={searchText}
style={{ borderRadius: 'var(--list-item-border-radius)', height: 35 }} style={{ borderRadius: 'var(--list-item-border-radius)', height: 35 }}
suffix={<SearchOutlined style={{ color: 'var(--color-text-3)' }} />} suffix={<Search size={14} />}
onChange={(e) => setSearchText(e.target.value)} onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {

View File

@ -1,19 +1,20 @@
import {
AppstoreOutlined,
CloudOutlined,
CodeOutlined,
GlobalOutlined,
InfoCircleOutlined,
LayoutOutlined,
MacCommandOutlined,
RocketOutlined,
SaveOutlined,
SettingOutlined,
ThunderboltOutlined
} from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon' import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon'
import ModelSettings from '@renderer/pages/settings/ModelSettings/ModelSettings' import ModelSettings from '@renderer/pages/settings/ModelSettings/ModelSettings'
import {
Cloud,
Command,
Globe,
HardDrive,
Info,
LayoutGrid,
MonitorCog,
Package,
Rocket,
Settings2,
SquareTerminal,
Zap
} from 'lucide-react'
// 导入useAppSelector // 导入useAppSelector
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -51,75 +52,75 @@ const SettingsPage: FC = () => {
<SettingMenus> <SettingMenus>
<MenuItemLink to="/settings/provider"> <MenuItemLink to="/settings/provider">
<MenuItem className={isRoute('/settings/provider')}> <MenuItem className={isRoute('/settings/provider')}>
<CloudOutlined /> <Cloud size={18} />
{t('settings.provider.title')} {t('settings.provider.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/model"> <MenuItemLink to="/settings/model">
<MenuItem className={isRoute('/settings/model')}> <MenuItem className={isRoute('/settings/model')}>
<i className="iconfont icon-ai-model" /> <Package size={18} />
{t('settings.model')} {t('settings.model')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/web-search"> <MenuItemLink to="/settings/web-search">
<MenuItem className={isRoute('/settings/web-search')}> <MenuItem className={isRoute('/settings/web-search')}>
<GlobalOutlined /> <Globe size={18} />
{t('settings.websearch.title')} {t('settings.websearch.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/mcp"> <MenuItemLink to="/settings/mcp">
<MenuItem className={isRoute('/settings/mcp')}> <MenuItem className={isRoute('/settings/mcp')}>
<CodeOutlined /> <SquareTerminal size={18} />
{t('settings.mcp.title')} {t('settings.mcp.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/general"> <MenuItemLink to="/settings/general">
<MenuItem className={isRoute('/settings/general')}> <MenuItem className={isRoute('/settings/general')}>
<SettingOutlined /> <Settings2 size={18} />
{t('settings.general')} {t('settings.general')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/display"> <MenuItemLink to="/settings/display">
<MenuItem className={isRoute('/settings/display')}> <MenuItem className={isRoute('/settings/display')}>
<LayoutOutlined /> <MonitorCog size={18} />
{t('settings.display.title')} {t('settings.display.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
{showMiniAppSettings && ( {showMiniAppSettings && (
<MenuItemLink to="/settings/miniapps"> <MenuItemLink to="/settings/miniapps">
<MenuItem className={isRoute('/settings/miniapps')}> <MenuItem className={isRoute('/settings/miniapps')}>
<AppstoreOutlined /> <LayoutGrid size={18} />
{t('settings.miniapps.title')} {t('settings.miniapps.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
)} )}
<MenuItemLink to="/settings/shortcut"> <MenuItemLink to="/settings/shortcut">
<MenuItem className={isRoute('/settings/shortcut')}> <MenuItem className={isRoute('/settings/shortcut')}>
<MacCommandOutlined /> <Command size={18} />
{t('settings.shortcuts.title')} {t('settings.shortcuts.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/quickAssistant"> <MenuItemLink to="/settings/quickAssistant">
<MenuItem className={isRoute('/settings/quickAssistant')}> <MenuItem className={isRoute('/settings/quickAssistant')}>
<RocketOutlined /> <Rocket size={18} />
{t('settings.quickAssistant.title')} {t('settings.quickAssistant.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/quickPhrase"> <MenuItemLink to="/settings/quickPhrase">
<MenuItem className={isRoute('/settings/quickPhrase')}> <MenuItem className={isRoute('/settings/quickPhrase')}>
<ThunderboltOutlined /> <Zap size={18} />
{t('settings.quickPhrase.title')} {t('settings.quickPhrase.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/data"> <MenuItemLink to="/settings/data">
<MenuItem className={isRoute('/settings/data')}> <MenuItem className={isRoute('/settings/data')}>
<SaveOutlined /> <HardDrive size={18} />
{t('settings.data.title')} {t('settings.data.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/about"> <MenuItemLink to="/settings/about">
<MenuItem className={isRoute('/settings/about')}> <MenuItem className={isRoute('/settings/about')}>
<InfoCircleOutlined /> <Info size={18} />
{t('settings.about')} {t('settings.about')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>

View File

@ -316,6 +316,7 @@ const ShortcutSettings: FC = () => {
<Button <Button
icon={<UndoOutlined />} icon={<UndoOutlined />}
size="small" size="small"
shape="circle"
onClick={() => handleResetShortcut(record)} onClick={() => handleResetShortcut(record)}
disabled={!isShortcutModified(record)} disabled={!isShortcutModified(record)}
/> />
@ -324,6 +325,7 @@ const ShortcutSettings: FC = () => {
<Button <Button
icon={<ClearOutlined />} icon={<ClearOutlined />}
size="small" size="small"
shape="circle"
onClick={() => handleClear(record)} onClick={() => handleClear(record)}
disabled={record.shortcut.length === 0 || !record.editable} disabled={record.shortcut.length === 0 || !record.editable}
/> />

View File

@ -1,9 +1,9 @@
import { InfoCircleOutlined } from '@ant-design/icons'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch, useAppSelector } from '@renderer/store'
import { setEnhanceMode, setMaxResult, setOverwrite, setSearchWithTime } from '@renderer/store/websearch' import { setEnhanceMode, setMaxResult, setOverwrite, setSearchWithTime } from '@renderer/store/websearch'
import { Slider, Switch, Tooltip } from 'antd' import { Slider, Switch, Tooltip } from 'antd'
import { t } from 'i18next' import { t } from 'i18next'
import { Info } from 'lucide-react'
import { FC } from 'react' import { FC } from 'react'
import { SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..' import { SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..'
@ -31,7 +31,7 @@ const BasicSettings: FC = () => {
<SettingRowTitle> <SettingRowTitle>
{t('settings.websearch.overwrite')} {t('settings.websearch.overwrite')}
<Tooltip title={t('settings.websearch.overwrite_tooltip')} placement="right"> <Tooltip title={t('settings.websearch.overwrite_tooltip')} placement="right">
<InfoCircleOutlined style={{ marginLeft: 5, color: 'var(--color-icon)', cursor: 'pointer' }} /> <Info size={16} color="var(--color-icon)" style={{ marginLeft: 5, cursor: 'pointer' }} />
</Tooltip> </Tooltip>
</SettingRowTitle> </SettingRowTitle>
<Switch checked={overwrite} onChange={(checked) => dispatch(setOverwrite(checked))} /> <Switch checked={overwrite} onChange={(checked) => dispatch(setOverwrite(checked))} />
@ -41,7 +41,7 @@ const BasicSettings: FC = () => {
<SettingRowTitle> <SettingRowTitle>
{t('settings.websearch.enhance_mode')} {t('settings.websearch.enhance_mode')}
<Tooltip title={t('settings.websearch.enhance_mode_tooltip')} placement="right"> <Tooltip title={t('settings.websearch.enhance_mode_tooltip')} placement="right">
<InfoCircleOutlined style={{ marginLeft: 5, color: 'var(--color-icon)', cursor: 'pointer' }} /> <Info size={16} color="var(--color-icon)" style={{ marginLeft: 5, cursor: 'pointer' }} />
</Tooltip> </Tooltip>
</SettingRowTitle> </SettingRowTitle>
<Switch checked={enhanceMode} onChange={(checked) => dispatch(setEnhanceMode(checked))} /> <Switch checked={enhanceMode} onChange={(checked) => dispatch(setEnhanceMode(checked))} />

View File

@ -1,4 +1,4 @@
import { CheckOutlined, ExportOutlined, InfoCircleOutlined, LoadingOutlined } from '@ant-design/icons' import { CheckOutlined, ExportOutlined, LoadingOutlined } from '@ant-design/icons'
import { getWebSearchProviderLogo, WEB_SEARCH_PROVIDER_CONFIG } from '@renderer/config/webSearchProviders' import { getWebSearchProviderLogo, WEB_SEARCH_PROVIDER_CONFIG } from '@renderer/config/webSearchProviders'
import { useWebSearchProvider } from '@renderer/hooks/useWebSearchProviders' import { useWebSearchProvider } from '@renderer/hooks/useWebSearchProviders'
import { formatApiKeys } from '@renderer/services/ApiService' import { formatApiKeys } from '@renderer/services/ApiService'
@ -7,6 +7,7 @@ import { WebSearchProvider } from '@renderer/types'
import { hasObjectKey } from '@renderer/utils' import { hasObjectKey } from '@renderer/utils'
import { Avatar, Button, Divider, Flex, Input } from 'antd' import { Avatar, Button, Divider, Flex, Input } from 'antd'
import Link from 'antd/es/typography/Link' import Link from 'antd/es/typography/Link'
import { Info } from 'lucide-react'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -53,7 +54,7 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
window.message.error({ window.message.error({
content: t('settings.websearch.no_provider_selected'), content: t('settings.websearch.no_provider_selected'),
duration: 3, duration: 3,
icon: <InfoCircleOutlined />, icon: <Info size={18} />,
key: 'no-provider-selected' key: 'no-provider-selected'
}) })
return return

View File

@ -61,6 +61,9 @@ export const SettingRowTitle = styled.div`
font-size: 14px; font-size: 14px;
line-height: 18px; line-height: 18px;
color: var(--color-text-1); color: var(--color-text-1);
display: flex;
flex-direction: row;
align-items: center;
` `
export const SettingHelpTextRow = styled.div` export const SettingHelpTextRow = styled.div`

View File

@ -1,12 +1,4 @@
import { import { CheckOutlined, DeleteOutlined, HistoryOutlined, SendOutlined } from '@ant-design/icons'
CheckOutlined,
DeleteOutlined,
HistoryOutlined,
SendOutlined,
SettingOutlined,
SyncOutlined,
WarningOutlined
} from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import CopyIcon from '@renderer/components/Icons/CopyIcon' import CopyIcon from '@renderer/components/Icons/CopyIcon'
import { isLocalAi } from '@renderer/config/env' import { isLocalAi } from '@renderer/config/env'
@ -22,6 +14,7 @@ import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useLiveQuery } from 'dexie-react-hooks' import { useLiveQuery } from 'dexie-react-hooks'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { Mouse, Settings2, TriangleAlert } from 'lucide-react'
import { FC, useEffect, useRef, useState } from 'react' import { FC, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
@ -167,18 +160,18 @@ const TranslatePage: FC = () => {
if (translateModel) { if (translateModel) {
return ( return (
<Link to="/settings/model" style={{ color: 'var(--color-text-2)' }}> <Link to="/settings/model" style={{ color: 'var(--color-text-2)', display: 'flex' }}>
<SettingOutlined /> <Settings2 size={18} />
</Link> </Link>
) )
} }
return ( return (
<Link to="/settings/model" style={{ marginLeft: -10 }}> <Link to="/settings/model" style={{ marginLeft: -10, display: 'flex' }}>
<Button <Button
type="link" type="link"
style={{ color: 'var(--color-error)', textDecoration: 'underline' }} style={{ color: 'var(--color-error)', textDecoration: 'underline' }}
icon={<WarningOutlined />}> icon={<TriangleAlert size={16} />}>
{t('translate.error.not_configured')} {t('translate.error.not_configured')}
</Button> </Button>
</Link> </Link>
@ -304,11 +297,11 @@ const TranslatePage: FC = () => {
<Tooltip <Tooltip
mouseEnterDelay={0.5} mouseEnterDelay={0.5}
title={isScrollSyncEnabled ? t('translate.scroll_sync.disable') : t('translate.scroll_sync.enable')}> title={isScrollSyncEnabled ? t('translate.scroll_sync.disable') : t('translate.scroll_sync.enable')}>
<SyncOutlined <Mouse
style={{ size={16}
color: isScrollSyncEnabled ? 'var(--color-primary)' : 'var(--color-text-2)'
}}
onClick={toggleScrollSync} onClick={toggleScrollSync}
style={{ cursor: 'pointer' }}
color={isScrollSyncEnabled ? 'var(--color-primary)' : 'var(--color-icon)'}
/> />
</Tooltip> </Tooltip>
</Flex> </Flex>