feat: enhance styling and icon consistency across components
This commit is contained in:
parent
24e46efa0c
commit
0e8c053cee
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
BIN
src/renderer/src/assets/images/providers/aihubmix.webp
Normal file
BIN
src/renderer/src/assets/images/providers/aihubmix.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
@ -199,3 +199,11 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-collapse {
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-collapse-content {
|
||||||
|
border-top: 1px solid var(--color-border) !important;
|
||||||
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
--color-border-soft: #ffffff10;
|
--color-border-soft: #ffffff10;
|
||||||
--color-border-mute: #ffffff05;
|
--color-border-mute: #ffffff05;
|
||||||
--color-error: #f44336;
|
--color-error: #f44336;
|
||||||
--color-link: #1677ff;
|
--color-link: #338cff;
|
||||||
--color-code-background: #323232;
|
--color-code-background: #323232;
|
||||||
--color-hover: rgba(40, 40, 40, 1);
|
--color-hover: rgba(40, 40, 40, 1);
|
||||||
--color-active: rgba(55, 55, 55, 1);
|
--color-active: rgba(55, 55, 55, 1);
|
||||||
|
|||||||
@ -44,7 +44,7 @@ const CustomCollapse: FC<CustomCollapseProps> = ({
|
|||||||
borderTopRightRadius: '8px'
|
borderTopRightRadius: '8px'
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
borderTop: '0.5px solid var(--color-border)'
|
borderTop: 'none'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
src/renderer/src/components/EmojiIcon.tsx
Normal file
32
src/renderer/src/components/EmojiIcon.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { getLeadingEmoji } from '@renderer/utils'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const EmojiIcon = styled.div<{ $emoji: string }>`
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border-radius: 13px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 3px;
|
||||||
|
&:before {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: ${({ $emoji }) => `'${getLeadingEmoji($emoji || ' ')}'`};
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 200%;
|
||||||
|
transform: scale(1.5);
|
||||||
|
filter: blur(5px);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default EmojiIcon
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { EyeOutlined } from '@ant-design/icons'
|
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
|
import { ImageIcon } from 'lucide-react'
|
||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -10,7 +10,7 @@ const VisionIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>,
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Tooltip title={t('models.type.vision')} placement="top">
|
<Tooltip title={t('models.type.vision')} placement="top">
|
||||||
<Icon {...(props as any)} />
|
<Icon size={15} {...(props as any)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
@ -22,9 +22,8 @@ const Container = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Icon = styled(EyeOutlined)`
|
const Icon = styled(ImageIcon)`
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
font-size: 15px;
|
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ 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'
|
||||||
|
|
||||||
|
import EmojiIcon from '../EmojiIcon'
|
||||||
import { HStack } from '../Layout'
|
import { HStack } from '../Layout'
|
||||||
import Scrollbar from '../Scrollbar'
|
import Scrollbar from '../Scrollbar'
|
||||||
|
|
||||||
@ -186,12 +187,9 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
|||||||
onClick={() => onCreateAssistant(agent)}
|
onClick={() => onCreateAssistant(agent)}
|
||||||
className={`agent-item ${agent.id === 'default' ? 'default' : ''} ${index === selectedIndex ? 'keyboard-selected' : ''}`}
|
className={`agent-item ${agent.id === 'default' ? 'default' : ''} ${index === selectedIndex ? 'keyboard-selected' : ''}`}
|
||||||
onMouseEnter={() => setSelectedIndex(index)}>
|
onMouseEnter={() => setSelectedIndex(index)}>
|
||||||
<HStack
|
<HStack alignItems="center" gap={5} style={{ overflow: 'hidden', maxWidth: '100%' }}>
|
||||||
alignItems="center"
|
<EmojiIcon $emoji={agent.emoji || ''}>{agent.emoji}</EmojiIcon>
|
||||||
gap={5}
|
<span className="text-nowrap">{agent.name}</span>
|
||||||
style={{ overflow: 'hidden', maxWidth: '100%' }}
|
|
||||||
className="text-nowrap">
|
|
||||||
{agent.emoji} {agent.name}
|
|
||||||
</HStack>
|
</HStack>
|
||||||
{agent.id === 'default' && <Tag color="green">{t('agents.tag.system')}</Tag>}
|
{agent.id === 'default' && <Tag color="green">{t('agents.tag.system')}</Tag>}
|
||||||
{agent.type === 'agent' && <Tag color="orange">{t('agents.tag.agent')}</Tag>}
|
{agent.type === 'agent' && <Tag color="orange">{t('agents.tag.agent')}</Tag>}
|
||||||
@ -220,13 +218,11 @@ const AgentItem = styled.div`
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid transparent;
|
|
||||||
&.default {
|
&.default {
|
||||||
background-color: var(--color-background-mute);
|
background-color: var(--color-background-mute);
|
||||||
}
|
}
|
||||||
&.keyboard-selected {
|
&.keyboard-selected {
|
||||||
background-color: var(--color-background-mute);
|
background-color: var(--color-background-mute);
|
||||||
border: 1px solid var(--color-primary);
|
|
||||||
}
|
}
|
||||||
.anticon {
|
.anticon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|||||||
@ -12,15 +12,15 @@ import type { MenuProps } from 'antd'
|
|||||||
import { Avatar, Dropdown, Tooltip } from 'antd'
|
import { Avatar, Dropdown, Tooltip } from 'antd'
|
||||||
import {
|
import {
|
||||||
CircleHelp,
|
CircleHelp,
|
||||||
|
FileSearch,
|
||||||
Folder,
|
Folder,
|
||||||
Languages,
|
Languages,
|
||||||
LayoutGrid,
|
LayoutGrid,
|
||||||
LibraryBig,
|
|
||||||
MessageSquareQuote,
|
MessageSquareQuote,
|
||||||
Moon,
|
Moon,
|
||||||
Palette,
|
Palette,
|
||||||
Settings,
|
Settings,
|
||||||
Sparkles,
|
Sparkle,
|
||||||
Sun
|
Sun
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { FC, useEffect } from 'react'
|
import { FC, useEffect } from 'react'
|
||||||
@ -131,11 +131,11 @@ const MainMenus: FC = () => {
|
|||||||
|
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
assistants: <MessageSquareQuote size={18} className="icon" />,
|
assistants: <MessageSquareQuote size={18} className="icon" />,
|
||||||
agents: <Sparkles size={18} className="icon" />,
|
agents: <Sparkle size={18} className="icon" />,
|
||||||
paintings: <Palette size={18} className="icon" />,
|
paintings: <Palette size={18} className="icon" />,
|
||||||
translate: <Languages size={18} className="icon" />,
|
translate: <Languages size={18} className="icon" />,
|
||||||
minapp: <LayoutGrid size={18} className="icon" />,
|
minapp: <LayoutGrid size={18} className="icon" />,
|
||||||
knowledge: <LibraryBig size={18} className="icon" />,
|
knowledge: <FileSearch size={18} className="icon" />,
|
||||||
files: <Folder size={17} className="icon" />
|
files: <Folder size={17} className="icon" />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import ZhinaoProviderLogo from '@renderer/assets/images/models/360.png'
|
import ZhinaoProviderLogo from '@renderer/assets/images/models/360.png'
|
||||||
import HunyuanProviderLogo from '@renderer/assets/images/models/hunyuan.png'
|
import HunyuanProviderLogo from '@renderer/assets/images/models/hunyuan.png'
|
||||||
import AzureProviderLogo from '@renderer/assets/images/models/microsoft.png'
|
import AzureProviderLogo from '@renderer/assets/images/models/microsoft.png'
|
||||||
import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.jpg'
|
import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.webp'
|
||||||
import AlayaNewProviderLogo from '@renderer/assets/images/providers/alayanew.webp'
|
import AlayaNewProviderLogo from '@renderer/assets/images/providers/alayanew.webp'
|
||||||
import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.png'
|
import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.png'
|
||||||
import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png'
|
import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png'
|
||||||
|
|||||||
@ -33,11 +33,10 @@ const AntdProvider: FC<PropsWithChildren> = ({ children }) => {
|
|||||||
boxShadowSecondary: 'none',
|
boxShadowSecondary: 'none',
|
||||||
defaultShadow: 'none',
|
defaultShadow: 'none',
|
||||||
dangerShadow: 'none',
|
dangerShadow: 'none',
|
||||||
primaryShadow: 'none',
|
primaryShadow: 'none'
|
||||||
borderRadius: 20
|
|
||||||
},
|
},
|
||||||
Select: {
|
Collapse: {
|
||||||
borderRadius: 20
|
headerBg: 'transparent'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
token: {
|
token: {
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"assistants": {
|
"assistants": {
|
||||||
"title": "Assistants",
|
"title": "Assistants",
|
||||||
"abbr": "Assistant",
|
"abbr": "Assistants",
|
||||||
"settings.title": "Assistant Settings",
|
"settings.title": "Assistant Settings",
|
||||||
"clear.content": "Clearing the topic will delete all topics and files in the assistant. Are you sure you want to continue?",
|
"clear.content": "Clearing the topic will delete all topics and files in the assistant. Are you sure you want to continue?",
|
||||||
"clear.title": "Clear topics",
|
"clear.title": "Clear topics",
|
||||||
|
|||||||
@ -932,7 +932,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}>
|
||||||
<MessageSquareDiff size={18} />
|
<MessageSquareDiff size={19} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<AttachmentButton
|
<AttachmentButton
|
||||||
|
|||||||
@ -4,7 +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 { FileSearch } 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'
|
||||||
@ -89,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}>
|
||||||
<LibraryBig size={18} />
|
<FileSearch size={18} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -34,7 +34,7 @@ const CitationsList: React.FC<CitationsListProps> = ({ citations }) => {
|
|||||||
{citation.showFavicon && citation.url && (
|
{citation.showFavicon && citation.url && (
|
||||||
<Favicon hostname={new URL(citation.url).hostname} alt={citation.title || citation.hostname || ''} />
|
<Favicon hostname={new URL(citation.url).hostname} alt={citation.title || citation.hostname || ''} />
|
||||||
)}
|
)}
|
||||||
<CitationLink href={citation.url} target="_blank" rel="noopener noreferrer">
|
<CitationLink href={citation.url} className="text-nowrap" target="_blank" rel="noopener noreferrer">
|
||||||
{citation.title ? citation.title : <span className="hostname">{citation.hostname}</span>}
|
{citation.title ? citation.title : <span className="hostname">{citation.hostname}</span>}
|
||||||
</CitationLink>
|
</CitationLink>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@ -263,7 +263,7 @@ const ToolResponseContainer = styled.div`
|
|||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
border-top: 1px solid var(--color-border);
|
border-top: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -32,10 +32,9 @@ const Prompt: FC<Props> = ({ assistant, topic }) => {
|
|||||||
const Container = styled.div<{ $isDark: boolean }>`
|
const Container = styled.div<{ $isDark: boolean }>`
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 5px 20px 0 20px;
|
margin: 5px 20px 0 20px;
|
||||||
border-radius: 6px;
|
border-radius: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 0.5px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
background-color: ${({ $isDark }) => ($isDark ? 'var(--color-background-opacity)' : 'transparent')};
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const Text = styled.div`
|
const Text = styled.div`
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
SortDescendingOutlined
|
SortDescendingOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
||||||
|
import EmojiIcon from '@renderer/components/EmojiIcon'
|
||||||
import CopyIcon from '@renderer/components/Icons/CopyIcon'
|
import CopyIcon from '@renderer/components/Icons/CopyIcon'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useAssistants } from '@renderer/hooks/useAssistant'
|
import { useAssistants } from '@renderer/hooks/useAssistant'
|
||||||
@ -215,11 +216,11 @@ const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch,
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
assistantIconType === 'emoji' && (
|
assistantIconType === 'emoji' && (
|
||||||
<AssistantEmoji
|
<EmojiIcon
|
||||||
$emoji={assistant.emoji || assistantName.slice(0, 1)}
|
$emoji={assistant.emoji || assistantName.slice(0, 1)}
|
||||||
className={isPending && !isActive ? 'animation-pulse' : ''}>
|
className={isPending && !isActive ? 'animation-pulse' : ''}>
|
||||||
{assistant.emoji || assistantName.slice(0, 1)}
|
{assistant.emoji || assistantName.slice(0, 1)}
|
||||||
</AssistantEmoji>
|
</EmojiIcon>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
|
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
|
||||||
@ -270,34 +271,6 @@ const AssistantNameRow = styled.div`
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const AssistantEmoji = styled.div<{ $emoji: string }>`
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
border-radius: 13px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
font-size: 15px;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-right: 3px;
|
|
||||||
&:before {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
content: ${({ $emoji }) => `'${$emoji || ' '}'`};
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 200%;
|
|
||||||
transform: scale(1.5);
|
|
||||||
filter: blur(5px);
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const AssistantName = styled.div`
|
const AssistantName = styled.div`
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
`
|
`
|
||||||
|
|||||||
@ -184,6 +184,9 @@ const Segmented = styled(AntSegmented)`
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.ant-segmented-item-label[aria-selected='true'] {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
@ -204,6 +207,11 @@ const Segmented = styled(AntSegmented)`
|
|||||||
border-radius: var(--list-item-border-radius);
|
border-radius: var(--list-item-border-radius);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
.ant-segmented-item-label,
|
||||||
|
.ant-segmented-item-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
/* These styles ensure the same appearance as before */
|
/* These styles ensure the same appearance as before */
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
||||||
import ModelTags from '@renderer/components/ModelTags'
|
|
||||||
import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
|
import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
|
||||||
import { isLocalAi } from '@renderer/config/env'
|
import { isLocalAi } from '@renderer/config/env'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
@ -33,13 +32,12 @@ const SelectModelButton: FC<Props> = ({ assistant }) => {
|
|||||||
const providerName = getProviderName(model?.provider)
|
const providerName = getProviderName(model?.provider)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownButton size="small" type="default" onClick={onSelectModel}>
|
<DropdownButton size="small" type="text" onClick={onSelectModel}>
|
||||||
<ButtonContent>
|
<ButtonContent>
|
||||||
<ModelAvatar model={model} size={20} />
|
<ModelAvatar model={model} size={20} />
|
||||||
<ModelName>
|
<ModelName>
|
||||||
{model ? model.name : t('button.select_model')} {providerName ? '| ' + providerName : ''}
|
{model ? model.name : t('button.select_model')} {providerName ? '| ' + providerName : ''}
|
||||||
</ModelName>
|
</ModelName>
|
||||||
<ModelTags model={model} showFree={false} showReasoning={false} showToolsCalling={false} />
|
|
||||||
</ButtonContent>
|
</ButtonContent>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -13,7 +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 { ChevronsDown, ChevronsUp, Plus, 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'
|
||||||
@ -21,7 +21,6 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import CustomCollapse from '../../components/CustomCollapse'
|
import CustomCollapse from '../../components/CustomCollapse'
|
||||||
import FileItem from '../files/FileItem'
|
import FileItem from '../files/FileItem'
|
||||||
import KnowledgeSearchPopup from './components/KnowledgeSearchPopup'
|
|
||||||
import KnowledgeSettingsPopup from './components/KnowledgeSettingsPopup'
|
import KnowledgeSettingsPopup from './components/KnowledgeSettingsPopup'
|
||||||
import StatusIcon from './components/StatusIcon'
|
import StatusIcon from './components/StatusIcon'
|
||||||
|
|
||||||
@ -58,7 +57,6 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
} = useKnowledge(selectedBase.id || '')
|
} = useKnowledge(selectedBase.id || '')
|
||||||
|
|
||||||
const providerName = getProviderName(base?.model.provider || '')
|
const providerName = getProviderName(base?.model.provider || '')
|
||||||
const rerankModelProviderName = getProviderName(base?.rerankModel?.provider || '')
|
|
||||||
const disabled = !base?.version || !providerName
|
const disabled = !base?.version || !providerName
|
||||||
|
|
||||||
if (!base) {
|
if (!base) {
|
||||||
@ -239,7 +237,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
</div>
|
</div>
|
||||||
<Tooltip title={providerName} placement="bottom">
|
<Tooltip title={providerName} placement="bottom">
|
||||||
<div className="tag-column">
|
<div className="tag-column">
|
||||||
<Tag color="geekblue" style={{ borderRadius: 20, margin: 0 }}>
|
<Tag color="green" style={{ borderRadius: 20, margin: 0 }}>
|
||||||
{base.model.name}
|
{base.model.name}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
@ -248,30 +246,8 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
{t('models.dimensions', { dimensions: base.dimensions || 0 })}
|
{t('models.dimensions', { dimensions: base.dimensions || 0 })}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
{base.rerankModel && (
|
|
||||||
<div className="model-row">
|
|
||||||
<div className="label-column">
|
|
||||||
<label>{t('models.rerank_model')}</label>
|
|
||||||
</div>
|
|
||||||
<Tooltip title={rerankModelProviderName} placement="bottom">
|
|
||||||
<div className="tag-column">
|
|
||||||
<Tag color="green" style={{ borderRadius: 20, margin: 0 }}>
|
|
||||||
{base.rerankModel?.name}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</ModelInfo>
|
</ModelInfo>
|
||||||
<HStack gap={8} alignItems="center">
|
<HStack gap={8} alignItems="center">
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
shape="round"
|
|
||||||
onClick={() => KnowledgeSearchPopup.show({ base })}
|
|
||||||
icon={<Search size={14} />}
|
|
||||||
disabled={disabled}>
|
|
||||||
{t('knowledge.search')}
|
|
||||||
</Button>
|
|
||||||
<Tooltip title={expandAll ? t('common.collapse') : t('common.expand')}>
|
<Tooltip title={expandAll ? t('common.collapse') : t('common.expand')}>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CloudSyncOutlined,
|
CloudSyncOutlined,
|
||||||
DatabaseOutlined,
|
|
||||||
FileMarkdownOutlined,
|
|
||||||
FileSearchOutlined,
|
FileSearchOutlined,
|
||||||
FolderOpenOutlined,
|
FolderOpenOutlined,
|
||||||
MenuOutlined,
|
|
||||||
SaveOutlined,
|
SaveOutlined,
|
||||||
YuqueOutlined
|
YuqueOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
@ -20,6 +17,7 @@ import { reset } from '@renderer/services/BackupService'
|
|||||||
import { AppInfo } from '@renderer/types'
|
import { AppInfo } from '@renderer/types'
|
||||||
import { formatFileSize } from '@renderer/utils'
|
import { formatFileSize } from '@renderer/utils'
|
||||||
import { Button, Typography } from 'antd'
|
import { Button, Typography } from 'antd'
|
||||||
|
import { FileText, FolderCog, FolderInput } 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'
|
||||||
@ -44,7 +42,7 @@ const DataSettings: FC = () => {
|
|||||||
|
|
||||||
//joplin icon needs to be updated into iconfont
|
//joplin icon needs to be updated into iconfont
|
||||||
const JoplinIcon = () => (
|
const JoplinIcon = () => (
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16" fill="grey" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="var(--color-icon)" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M20.97 0h-8.9a.15.15 0 00-.16.15v2.83c0 .1.08.17.18.17h1.22c.49 0 .89.38.93.86V17.4l-.01.36-.05.29-.04.13a2.06 2.06 0 01-.38.7l-.02.03a2.08 2.08 0 01-.37.34c-.5.35-1.17.5-1.92.43a4.66 4.66 0 01-2.67-1.22 3.96 3.96 0 01-1.34-2.42c-.1-.78.14-1.47.65-1.93l.07-.05c.37-.31.84-.5 1.39-.55a.09.09 0 00.01 0l.3-.01.35.01h.02a4.39 4.39 0 011.5.44c.15.08.17 0 .18-.06V9.63a.26.26 0 00-.2-.26 7.5 7.5 0 00-6.76 1.61 6.37 6.37 0 00-2.03 5.5 8.18 8.18 0 002.71 5.08A9.35 9.35 0 0011.81 24c1.88 0 3.62-.64 4.9-1.81a6.32 6.32 0 002.06-4.3l.01-10.86V4.08a.95.95 0 01.95-.93h1.22a.17.17 0 00.17-.17V.15a.15.15 0 00-.15-.15z" />
|
<path d="M20.97 0h-8.9a.15.15 0 00-.16.15v2.83c0 .1.08.17.18.17h1.22c.49 0 .89.38.93.86V17.4l-.01.36-.05.29-.04.13a2.06 2.06 0 01-.38.7l-.02.03a2.08 2.08 0 01-.37.34c-.5.35-1.17.5-1.92.43a4.66 4.66 0 01-2.67-1.22 3.96 3.96 0 01-1.34-2.42c-.1-.78.14-1.47.65-1.93l.07-.05c.37-.31.84-.5 1.39-.55a.09.09 0 00.01 0l.3-.01.35.01h.02a4.39 4.39 0 011.5.44c.15.08.17 0 .18-.06V9.63a.26.26 0 00-.2-.26 7.5 7.5 0 00-6.76 1.61 6.37 6.37 0 00-2.03 5.5 8.18 8.18 0 002.71 5.08A9.35 9.35 0 0011.81 24c1.88 0 3.62-.64 4.9-1.81a6.32 6.32 0 002.06-4.3l.01-10.86V4.08a.95.95 0 01.95-.93h1.22a.17.17 0 00.17-.17V.15a.15.15 0 00-.15-.15z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
@ -67,7 +65,7 @@ const DataSettings: FC = () => {
|
|||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ key: 'divider_0', isDivider: true, text: t('settings.data.divider.basic') },
|
{ key: 'divider_0', isDivider: true, text: t('settings.data.divider.basic') },
|
||||||
{ key: 'data', title: 'settings.data.data.title', icon: <DatabaseOutlined style={{ fontSize: 16 }} /> },
|
{ key: 'data', title: 'settings.data.data.title', icon: <FolderCog size={16} /> },
|
||||||
{ key: 'divider_1', isDivider: true, text: t('settings.data.divider.cloud_storage') },
|
{ key: 'divider_1', isDivider: true, text: t('settings.data.divider.cloud_storage') },
|
||||||
{ key: 'webdav', title: 'settings.data.webdav.title', icon: <CloudSyncOutlined style={{ fontSize: 16 }} /> },
|
{ key: 'webdav', title: 'settings.data.webdav.title', icon: <CloudSyncOutlined style={{ fontSize: 16 }} /> },
|
||||||
{ key: 'nutstore', title: 'settings.data.nutstore.title', icon: <NutstoreIcon /> },
|
{ key: 'nutstore', title: 'settings.data.nutstore.title', icon: <NutstoreIcon /> },
|
||||||
@ -75,12 +73,12 @@ const DataSettings: FC = () => {
|
|||||||
{
|
{
|
||||||
key: 'export_menu',
|
key: 'export_menu',
|
||||||
title: 'settings.data.export_menu.title',
|
title: 'settings.data.export_menu.title',
|
||||||
icon: <MenuOutlined style={{ fontSize: 16 }} />
|
icon: <FolderInput size={16} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'markdown_export',
|
key: 'markdown_export',
|
||||||
title: 'settings.data.markdown_export.title',
|
title: 'settings.data.markdown_export.title',
|
||||||
icon: <FileMarkdownOutlined style={{ fontSize: 16 }} />
|
icon: <FileText size={16} />
|
||||||
},
|
},
|
||||||
{ key: 'divider_3', isDivider: true, text: t('settings.data.divider.third_party') },
|
{ key: 'divider_3', isDivider: true, text: t('settings.data.divider.third_party') },
|
||||||
{ key: 'notion', title: 'settings.data.notion.title', icon: <i className="iconfont icon-notion" /> },
|
{ key: 'notion', title: 'settings.data.notion.title', icon: <i className="iconfont icon-notion" /> },
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import {
|
|||||||
LoadingOutlined,
|
LoadingOutlined,
|
||||||
MinusCircleOutlined,
|
MinusCircleOutlined,
|
||||||
MinusOutlined,
|
MinusOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined
|
||||||
SettingOutlined
|
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import CustomCollapse from '@renderer/components/CustomCollapse'
|
import CustomCollapse from '@renderer/components/CustomCollapse'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
@ -22,7 +21,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 { Bolt, 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'
|
||||||
@ -302,7 +301,7 @@ const ModelList: React.FC<ModelListProps> = ({ providerId, modelStatuses = [], s
|
|||||||
type="text"
|
type="text"
|
||||||
onClick={() => !isChecking && onEditModel(model)}
|
onClick={() => !isChecking && onEditModel(model)}
|
||||||
disabled={isChecking}
|
disabled={isChecking}
|
||||||
icon={<SettingOutlined />}
|
icon={<Bolt size={16} />}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { CheckOutlined, LoadingOutlined, SettingOutlined } from '@ant-design/icons'
|
import { CheckOutlined, LoadingOutlined } 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,7 +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 { Settings, 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'
|
||||||
@ -285,9 +285,10 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
|||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{!provider.isSystem && (
|
{!provider.isSystem && (
|
||||||
<SettingOutlined
|
<Settings
|
||||||
type="text"
|
type="text"
|
||||||
style={{ width: 30 }}
|
size={16}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
onClick={() => ProviderSettingsPopup.show({ provider })}
|
onClick={() => ProviderSettingsPopup.show({ provider })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export function getDefaultAssistant(): Assistant {
|
|||||||
return {
|
return {
|
||||||
id: 'default',
|
id: 'default',
|
||||||
name: i18n.t('chat.default.name'),
|
name: i18n.t('chat.default.name'),
|
||||||
emoji: '⭐️',
|
emoji: '😀',
|
||||||
prompt: '',
|
prompt: '',
|
||||||
topics: [getDefaultTopic('default')],
|
topics: [getDefaultTopic('default')],
|
||||||
messages: [],
|
messages: [],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user