feat: new icon style
This commit is contained in:
parent
39c614e4db
commit
5f7d8652bc
@ -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",
|
||||||
|
|||||||
@ -281,3 +281,7 @@ body,
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lucide {
|
||||||
|
color: var(--color-icon);
|
||||||
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
`
|
`
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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 = {
|
||||||
|
|||||||
@ -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: {
|
||||||
|
|||||||
@ -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)}
|
||||||
|
|||||||
@ -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)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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} />
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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,22 +160,29 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
content: content.trim(),
|
content: content.trim(),
|
||||||
metadata: {
|
metadata: {
|
||||||
...message.metadata,
|
...message.metadata,
|
||||||
generateImage: imageUrls.length > 0 ? {
|
generateImage:
|
||||||
|
imageUrls.length > 0
|
||||||
|
? {
|
||||||
type: 'url',
|
type: 'url',
|
||||||
images: imageUrls
|
images: imageUrls
|
||||||
} : undefined
|
}
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
resendMessage && handleResendUserMessage({
|
resendMessage &&
|
||||||
|
handleResendUserMessage({
|
||||||
...message,
|
...message,
|
||||||
content: content.trim(),
|
content: content.trim(),
|
||||||
metadata: {
|
metadata: {
|
||||||
...message.metadata,
|
...message.metadata,
|
||||||
generateImage: imageUrls.length > 0 ? {
|
generateImage:
|
||||||
|
imageUrls.length > 0
|
||||||
|
? {
|
||||||
type: 'url',
|
type: 'url',
|
||||||
images: imageUrls
|
images: imageUrls
|
||||||
} : undefined
|
}
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
`
|
`
|
||||||
|
|||||||
@ -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']
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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)`
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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} />
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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')}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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')}
|
||||||
|
|||||||
@ -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 />}>
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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') {
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -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))} />
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user