feat: new inputbar style
This commit is contained in:
parent
34d99b711c
commit
4fc53d7c19
@ -20,12 +20,12 @@ Cherry Studio is a desktop client that supports for multiple LLM providers, avai
|
|||||||
6. Code highlighting.
|
6. Code highlighting.
|
||||||
7. Mermaid chart
|
7. Mermaid chart
|
||||||
|
|
||||||
# 👥 Community
|
|
||||||
|
|
||||||
Join our Telegram group to discuss Cherry Studio's latest developments and features! [Telegram community](https://t.me/CherryStudioAI)
|
|
||||||
|
|
||||||
# 🖥️ Develop
|
# 🖥️ Develop
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
||||||
|
|
||||||
## Project Setup
|
## Project Setup
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4563475 */
|
font-family: "iconfont"; /* Project id 4563475 */
|
||||||
src: url('iconfont.woff2?t=1722242729348') format('woff2'),
|
src: url('iconfont.woff2?t=1723186111414') format('woff2'),
|
||||||
url('iconfont.woff?t=1722242729348') format('woff'),
|
url('iconfont.woff?t=1723186111414') format('woff'),
|
||||||
url('iconfont.ttf?t=1722242729348') format('truetype');
|
url('iconfont.ttf?t=1723186111414') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,14 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-copy:before {
|
||||||
|
content: "\e6ae";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-ic_send:before {
|
||||||
|
content: "\e795";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-dark1:before {
|
.icon-dark1:before {
|
||||||
content: "\e72f";
|
content: "\e72f";
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
--navbar-background: rgba(0, 0, 0, 0.8);
|
--navbar-background: rgba(0, 0, 0, 0.8);
|
||||||
--sidebar-background: rgba(0, 0, 0, 0.8);
|
--sidebar-background: rgba(0, 0, 0, 0.8);
|
||||||
|
--input-bar-background: rgba(255, 255, 255, 0.02);
|
||||||
|
|
||||||
--navbar-height: 42px;
|
--navbar-height: 42px;
|
||||||
--sidebar-width: 55px;
|
--sidebar-width: 55px;
|
||||||
@ -47,7 +48,7 @@
|
|||||||
--topic-list-width: 260px;
|
--topic-list-width: 260px;
|
||||||
--settings-width: var(--assistants-width);
|
--settings-width: var(--assistants-width);
|
||||||
--status-bar-height: 40px;
|
--status-bar-height: 40px;
|
||||||
--input-bar-height: 115px;
|
--input-bar-height: 85px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme-mode='light'] {
|
body[theme-mode='light'] {
|
||||||
@ -87,6 +88,7 @@ body[theme-mode='light'] {
|
|||||||
|
|
||||||
--navbar-background: rgba(255, 255, 255, 0.8);
|
--navbar-background: rgba(255, 255, 255, 0.8);
|
||||||
--sidebar-background: rgba(255, 255, 255, 0.8);
|
--sidebar-background: rgba(255, 255, 255, 0.8);
|
||||||
|
--input-bar-background: rgba(0, 0, 0, 0.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
@ -155,3 +157,7 @@ body,
|
|||||||
position: relative;
|
position: relative;
|
||||||
animation: flash 0.5s ease-out infinite alternate;
|
animation: flash 0.5s ease-out infinite alternate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-segmented-group {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
h1:first-child,
|
h1:first-child,
|
||||||
h2:first-child,
|
h2:first-child,
|
||||||
@ -72,6 +73,9 @@
|
|||||||
|
|
||||||
li {
|
li {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
&::marker {
|
||||||
|
color: var(--color-text-3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
li > ul,
|
li > ul,
|
||||||
@ -103,7 +107,7 @@
|
|||||||
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap !important;
|
white-space: pre-wrap !important;
|
||||||
padding: 1em;
|
padding: 1em 0;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
font-family: 'Fira Code', 'Courier New', Courier, monospace;
|
font-family: 'Fira Code', 'Courier New', Courier, monospace;
|
||||||
|
|||||||
24
src/renderer/src/components/Avatar/ModelAvatar.tsx
Normal file
24
src/renderer/src/components/Avatar/ModelAvatar.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { getModelLogo } from '@renderer/config/provider'
|
||||||
|
import { Model } from '@renderer/types'
|
||||||
|
import { Avatar, AvatarProps } from 'antd'
|
||||||
|
import { first } from 'lodash'
|
||||||
|
import { FC } from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
model: Model
|
||||||
|
size: number
|
||||||
|
props?: AvatarProps
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModelAvatar: FC<Props> = ({ model, size, props }) => {
|
||||||
|
return (
|
||||||
|
<Avatar
|
||||||
|
src={getModelLogo(model?.id || '')}
|
||||||
|
style={{ width: size, height: size, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
|
||||||
|
{...props}>
|
||||||
|
{first(model?.name)}
|
||||||
|
</Avatar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModelAvatar
|
||||||
@ -39,7 +39,6 @@ const TopViewContainer: React.FC<Props> = ({ children }) => {
|
|||||||
}, [messageApi, modal])
|
}, [messageApi, modal])
|
||||||
|
|
||||||
onPop = () => {
|
onPop = () => {
|
||||||
console.debug('[TopView] onPop')
|
|
||||||
const views = [...elementsRef.current]
|
const views = [...elementsRef.current]
|
||||||
views.pop()
|
views.pop()
|
||||||
elementsRef.current = views
|
elementsRef.current = views
|
||||||
@ -47,8 +46,6 @@ const TopViewContainer: React.FC<Props> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onShow = ({ element, id }: ElementItem) => {
|
onShow = ({ element, id }: ElementItem) => {
|
||||||
console.debug('[TopView] onShow', id)
|
|
||||||
|
|
||||||
if (!elementsRef.current.find((el) => el.id === id)) {
|
if (!elementsRef.current.find((el) => el.id === id)) {
|
||||||
elementsRef.current = elementsRef.current.concat([{ element, id }])
|
elementsRef.current = elementsRef.current.concat([{ element, id }])
|
||||||
setElements(elementsRef.current)
|
setElements(elementsRef.current)
|
||||||
@ -56,13 +53,11 @@ const TopViewContainer: React.FC<Props> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onHide = (id: string) => {
|
onHide = (id: string) => {
|
||||||
console.debug('[TopView] onHide', id, elementsRef.current)
|
|
||||||
elementsRef.current = elementsRef.current.filter((el) => el.id !== id)
|
elementsRef.current = elementsRef.current.filter((el) => el.id !== id)
|
||||||
setElements(elementsRef.current)
|
setElements(elementsRef.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
onHideAll = () => {
|
onHideAll = () => {
|
||||||
console.debug('[TopView] onHideAll')
|
|
||||||
setElements([])
|
setElements([])
|
||||||
elementsRef.current = []
|
elementsRef.current = []
|
||||||
}
|
}
|
||||||
@ -76,11 +71,6 @@ const TopViewContainer: React.FC<Props> = ({ children }) => {
|
|||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
console.debug(
|
|
||||||
'[TopView]',
|
|
||||||
elements.map((el) => [el.id, el.element])
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -131,6 +131,7 @@ const resources = {
|
|||||||
'messages.use_serif_font': 'Use serif font',
|
'messages.use_serif_font': 'Use serif font',
|
||||||
'messages.input.title': 'Input Settings',
|
'messages.input.title': 'Input Settings',
|
||||||
'messages.input.show_estimated_tokens': 'Show estimated input tokens',
|
'messages.input.show_estimated_tokens': 'Show estimated input tokens',
|
||||||
|
'messages.input.send_shortcuts': 'Send shortcuts',
|
||||||
'general.title': 'General Settings',
|
'general.title': 'General Settings',
|
||||||
'general.user_name': 'User Name',
|
'general.user_name': 'User Name',
|
||||||
'general.user_name.placeholder': 'Enter your name',
|
'general.user_name.placeholder': 'Enter your name',
|
||||||
@ -345,6 +346,7 @@ const resources = {
|
|||||||
'messages.use_serif_font': '使用衬线字体',
|
'messages.use_serif_font': '使用衬线字体',
|
||||||
'messages.input.title': '输入设置',
|
'messages.input.title': '输入设置',
|
||||||
'messages.input.show_estimated_tokens': '状态显示',
|
'messages.input.show_estimated_tokens': '状态显示',
|
||||||
|
'messages.input.send_shortcuts': '发送快捷键',
|
||||||
'general.title': '常规设置',
|
'general.title': '常规设置',
|
||||||
'general.user_name': '用户名',
|
'general.user_name': '用户名',
|
||||||
'general.user_name.placeholder': '请输入用户名',
|
'general.user_name.placeholder': '请输入用户名',
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
CopyOutlined,
|
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
MenuOutlined,
|
MenuOutlined,
|
||||||
@ -47,6 +46,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
|||||||
const isUserMessage = message.role === 'user'
|
const isUserMessage = message.role === 'user'
|
||||||
const isAssistantMessage = message.role === 'assistant'
|
const isAssistantMessage = message.role === 'assistant'
|
||||||
const canRegenerate = isLastMessage && isAssistantMessage
|
const canRegenerate = isLastMessage && isAssistantMessage
|
||||||
|
const showMetadata = Boolean(message.usage) && !generating
|
||||||
|
|
||||||
const onCopy = useCallback(() => {
|
const onCopy = useCallback(() => {
|
||||||
navigator.clipboard.writeText(message.content)
|
navigator.clipboard.writeText(message.content)
|
||||||
@ -119,15 +119,15 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
|||||||
}, [message])
|
}, [message])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MessageContainer key={message.id} className="message" style={{ border: messageBorder }}>
|
<MessageContainer key={message.id} className="message">
|
||||||
<MessageHeader>
|
<MessageHeader>
|
||||||
<AvatarWrapper>
|
<AvatarWrapper>
|
||||||
{isAssistantMessage ? (
|
{isAssistantMessage ? (
|
||||||
<Avatar src={avatarSource} size={35}>
|
<Avatar src={avatarSource} size={35} style={{ borderRadius: '20%' }}>
|
||||||
{avatarName}
|
{avatarName}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
) : (
|
) : (
|
||||||
<Avatar src={avatar} size={35} />
|
<Avatar src={avatar} size={35} style={{ borderRadius: '20%' }} />
|
||||||
)}
|
)}
|
||||||
<UserWrap>
|
<UserWrap>
|
||||||
<UserName>{username}</UserName>
|
<UserName>{username}</UserName>
|
||||||
@ -137,55 +137,58 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
|||||||
</MessageHeader>
|
</MessageHeader>
|
||||||
<MessageContent style={{ fontFamily }}>
|
<MessageContent style={{ fontFamily }}>
|
||||||
<MessageItem />
|
<MessageItem />
|
||||||
{message.usage && !generating && (
|
<MessageFooter style={{ border: messageBorder }}>
|
||||||
<MessageMetadata>
|
{showMenu && (
|
||||||
Tokens: {message.usage.total_tokens} | ↑{message.usage.prompt_tokens}↓{message.usage.completion_tokens}
|
<MenusBar className={`menubar ${isLastMessage && 'show'} ${(!isLastMessage || isUserMessage) && 'user'}`}>
|
||||||
</MessageMetadata>
|
{message.role === 'user' && (
|
||||||
)}
|
<Tooltip title="Edit" mouseEnterDelay={0.8}>
|
||||||
{showMenu && (
|
<ActionButton onClick={onEdit}>
|
||||||
<MenusBar className={`menubar ${isLastMessage && 'show'} ${(!isLastMessage || isUserMessage) && 'user'}`}>
|
<EditOutlined />
|
||||||
{message.role === 'user' && (
|
|
||||||
<Tooltip title="Edit" mouseEnterDelay={0.8}>
|
|
||||||
<ActionButton onClick={onEdit}>
|
|
||||||
<EditOutlined />
|
|
||||||
</ActionButton>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
|
|
||||||
<ActionButton onClick={onCopy}>
|
|
||||||
{!copied && <CopyOutlined />}
|
|
||||||
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
|
|
||||||
</ActionButton>
|
|
||||||
</Tooltip>
|
|
||||||
{canRegenerate && (
|
|
||||||
<SelectModelDropdown model={model} onSelect={onRegenerate} placement="topRight">
|
|
||||||
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
|
|
||||||
<ActionButton>
|
|
||||||
<SyncOutlined />
|
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</SelectModelDropdown>
|
)}
|
||||||
)}
|
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
|
||||||
<Popconfirm
|
<ActionButton onClick={onCopy}>
|
||||||
title={t('message.message.delete.content')}
|
{!copied && <i className="iconfont icon-copy"></i>}
|
||||||
okButtonProps={{ danger: true }}
|
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
|
||||||
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
|
|
||||||
onConfirm={() => onDeleteMessage?.(message)}>
|
|
||||||
<Tooltip title={t('common.delete')} mouseEnterDelay={1}>
|
|
||||||
<ActionButton>
|
|
||||||
<DeleteOutlined />
|
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Popconfirm>
|
{canRegenerate && (
|
||||||
{!isUserMessage && (
|
<SelectModelDropdown model={model} onSelect={onRegenerate} placement="topRight">
|
||||||
<Dropdown menu={{ items: dropdownItems }} trigger={['click']} placement="topRight" arrow>
|
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
|
||||||
<ActionButton>
|
<ActionButton>
|
||||||
<MenuOutlined />
|
<SyncOutlined />
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</Dropdown>
|
</Tooltip>
|
||||||
)}
|
</SelectModelDropdown>
|
||||||
</MenusBar>
|
)}
|
||||||
)}
|
<Popconfirm
|
||||||
|
title={t('message.message.delete.content')}
|
||||||
|
okButtonProps={{ danger: true }}
|
||||||
|
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
|
||||||
|
onConfirm={() => onDeleteMessage?.(message)}>
|
||||||
|
<Tooltip title={t('common.delete')} mouseEnterDelay={1}>
|
||||||
|
<ActionButton>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</ActionButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Popconfirm>
|
||||||
|
{!isUserMessage && (
|
||||||
|
<Dropdown menu={{ items: dropdownItems }} trigger={['click']} placement="topRight" arrow>
|
||||||
|
<ActionButton>
|
||||||
|
<MenuOutlined />
|
||||||
|
</ActionButton>
|
||||||
|
</Dropdown>
|
||||||
|
)}
|
||||||
|
</MenusBar>
|
||||||
|
)}
|
||||||
|
{showMetadata && (
|
||||||
|
<MessageMetadata>
|
||||||
|
Tokens: {message?.usage?.total_tokens} | ↑{message?.usage?.prompt_tokens} | ↓
|
||||||
|
{message?.usage?.completion_tokens}
|
||||||
|
</MessageMetadata>
|
||||||
|
)}
|
||||||
|
</MessageFooter>
|
||||||
</MessageContent>
|
</MessageContent>
|
||||||
</MessageContainer>
|
</MessageContainer>
|
||||||
)
|
)
|
||||||
@ -194,9 +197,8 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
|||||||
const MessageContainer = styled.div`
|
const MessageContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 10px 20px;
|
padding: 0 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 0.5px dotted var(--color-border);
|
|
||||||
.menubar {
|
.menubar {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
@ -205,7 +207,7 @@ const MessageContainer = styled.div`
|
|||||||
}
|
}
|
||||||
&.user {
|
&.user {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 10px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,6 +259,16 @@ const MessageContent = styled.div`
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const MessageFooter = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 0;
|
||||||
|
margin: 2px 0 8px 0;
|
||||||
|
border-top: 0.5px dashed var(--color-border);
|
||||||
|
`
|
||||||
|
|
||||||
const MessageContentLoading = styled.div`
|
const MessageContentLoading = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -270,17 +282,18 @@ const MenusBar = styled.div`
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
margin-left: -5px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const MessageMetadata = styled.div`
|
const MessageMetadata = styled.div`
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
margin: 2px 0;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ActionButton = styled.div`
|
const ActionButton = styled.div`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -288,7 +301,15 @@ const ActionButton = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
.anticon {
|
transition: all 0.3s ease;
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-background-mute);
|
||||||
|
.anticon {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.anticon,
|
||||||
|
.iconfont {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--color-icon);
|
color: var(--color-icon);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { getModelLogo } from '@renderer/config/provider'
|
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { Assistant } from '@renderer/types'
|
import { Assistant } from '@renderer/types'
|
||||||
import { Avatar, Button } from 'antd'
|
import { Button } from 'antd'
|
||||||
import { upperFirst } from 'lodash'
|
import { upperFirst } from 'lodash'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -20,7 +20,7 @@ const SelectModelButton: FC<Props> = ({ assistant }) => {
|
|||||||
return (
|
return (
|
||||||
<SelectModelDropdown model={model} onSelect={setModel}>
|
<SelectModelDropdown model={model} onSelect={setModel}>
|
||||||
<DropdownButton size="small" type="default">
|
<DropdownButton size="small" type="default">
|
||||||
<Avatar src={getModelLogo(model?.id || '')} style={{ width: 20, height: 20 }} />
|
<ModelAvatar model={model} size={20} />
|
||||||
<ModelName>{model ? upperFirst(model.name) : t('button.select_model')}</ModelName>
|
<ModelName>{model ? upperFirst(model.name) : t('button.select_model')}</ModelName>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
</SelectModelDropdown>
|
</SelectModelDropdown>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { getModelLogo } from '@renderer/config/provider'
|
|||||||
import { useProviders } from '@renderer/hooks/useProvider'
|
import { useProviders } from '@renderer/hooks/useProvider'
|
||||||
import { Model } from '@renderer/types'
|
import { Model } from '@renderer/types'
|
||||||
import { Avatar, Dropdown, DropdownProps, MenuProps } from 'antd'
|
import { Avatar, Dropdown, DropdownProps, MenuProps } from 'antd'
|
||||||
import { first, upperFirst } from 'lodash'
|
import { first, sortBy, upperFirst } from 'lodash'
|
||||||
import { FC, PropsWithChildren } from 'react'
|
import { FC, PropsWithChildren } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -22,7 +22,7 @@ const SelectModelDropdown: FC<Props & PropsWithChildren> = ({ children, model, o
|
|||||||
key: p.id,
|
key: p.id,
|
||||||
label: p.isSystem ? t(`provider.${p.id}`) : p.name,
|
label: p.isSystem ? t(`provider.${p.id}`) : p.name,
|
||||||
type: 'group',
|
type: 'group',
|
||||||
children: p.models.map((m) => ({
|
children: sortBy(p.models, 'name').map((m) => ({
|
||||||
key: m?.id,
|
key: m?.id,
|
||||||
label: upperFirst(m?.name),
|
label: upperFirst(m?.name),
|
||||||
defaultSelectedKeys: [model?.id],
|
defaultSelectedKeys: [model?.id],
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import store, { useAppSelector } from '@renderer/store'
|
|||||||
import { setGenerating } from '@renderer/store/runtime'
|
import { setGenerating } from '@renderer/store/runtime'
|
||||||
import { Assistant, Message, Topic } from '@renderer/types'
|
import { Assistant, Message, Topic } from '@renderer/types'
|
||||||
import { uuid } from '@renderer/utils'
|
import { uuid } from '@renderer/utils'
|
||||||
import { Button, Popconfirm, Tag, Tooltip } from 'antd'
|
import { Button, Divider, Popconfirm, Tag, Tooltip } from 'antd'
|
||||||
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
|
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { debounce, isEmpty } from 'lodash'
|
import { debounce, isEmpty } from 'lodash'
|
||||||
@ -37,6 +37,7 @@ let _text = ''
|
|||||||
|
|
||||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||||
const [text, setText] = useState(_text)
|
const [text, setText] = useState(_text)
|
||||||
|
const [inputFocus, setInputFocus] = useState(false)
|
||||||
const { addTopic } = useAssistant(assistant.id)
|
const { addTopic } = useAssistant(assistant.id)
|
||||||
const { sendMessageShortcut, showInputEstimatedTokens } = useSettings()
|
const { sendMessageShortcut, showInputEstimatedTokens } = useSettings()
|
||||||
const [expended, setExpend] = useState(false)
|
const [expended, setExpend] = useState(false)
|
||||||
@ -141,7 +142,10 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
}, [assistant])
|
}, [assistant])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container id="inputbar" style={{ minHeight: expended ? '80%' : 'var(--input-bar-height)' }}>
|
<Container
|
||||||
|
id="inputbar"
|
||||||
|
style={{ minHeight: expended ? '60%' : 'var(--input-bar-height)' }}
|
||||||
|
className={inputFocus ? 'focus' : ''}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
<Tooltip placement="top" title={t('chat.input.new_topic')} arrow>
|
<Tooltip placement="top" title={t('chat.input.new_topic')} arrow>
|
||||||
@ -179,11 +183,20 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
{showInputEstimatedTokens && (
|
{showInputEstimatedTokens && (
|
||||||
<TextCount>
|
<TextCount>
|
||||||
<Tooltip title={t('chat.input.context_count.tip')}>
|
<Tooltip title={t('chat.input.context_count.tip') + ' | ' + t('chat.input.estimated_tokens.tip')}>
|
||||||
<Tag style={{ cursor: 'pointer' }}>{assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT}</Tag>
|
<Tag
|
||||||
</Tooltip>
|
style={{
|
||||||
<Tooltip title={t('chat.input.estimated_tokens.tip')}>
|
cursor: 'pointer',
|
||||||
<Tag style={{ cursor: 'pointer' }}>↑ {`${inputTokenCount} / ${estimateTokenCount}`}</Tag>
|
borderRadius: '20px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '2px 8px'
|
||||||
|
}}>
|
||||||
|
<i className="iconfont icon-history" style={{ marginRight: '3px' }} />
|
||||||
|
{assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT}
|
||||||
|
<Divider type="vertical" style={{ marginTop: 2, marginLeft: 5, marginRight: 5 }} />↑
|
||||||
|
{`${inputTokenCount} / ${estimateTokenCount}`}
|
||||||
|
</Tag>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TextCount>
|
</TextCount>
|
||||||
)}
|
)}
|
||||||
@ -196,7 +209,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<SendMessageButton sendMessage={sendMessage} />
|
<SendMessageButton sendMessage={sendMessage} disabled={generating || !text} />
|
||||||
</ToolbarMenu>
|
</ToolbarMenu>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<Textarea
|
<Textarea
|
||||||
@ -209,6 +222,8 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
variant="borderless"
|
variant="borderless"
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
styles={{ textarea: { paddingLeft: 0 } }}
|
styles={{ textarea: { paddingLeft: 0 } }}
|
||||||
|
onFocus={() => setInputFocus(true)}
|
||||||
|
onBlur={() => setInputFocus(false)}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
@ -217,10 +232,14 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
height: var(--input-bar-height);
|
||||||
border-top: 0.5px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: 0 20px 15px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
&.focus {
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Textarea = styled(TextArea)`
|
const Textarea = styled(TextArea)`
|
||||||
@ -229,13 +248,16 @@ const Textarea = styled(TextArea)`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin: 0 15px 5px 15px;
|
margin: 0 15px 5px 15px;
|
||||||
|
font-family: Ubuntu;
|
||||||
|
resize: vertical;
|
||||||
|
overflow: auto;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Toolbar = styled.div`
|
const Toolbar = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 3px 10px;
|
padding: 0 10px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ToolbarMenu = styled.div`
|
const ToolbarMenu = styled.div`
|
||||||
|
|||||||
@ -1,44 +1,22 @@
|
|||||||
import { ArrowUpOutlined, EnterOutlined } from '@ant-design/icons'
|
|
||||||
import { SendOutlined } from '@ant-design/icons'
|
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
|
||||||
import { Dropdown, MenuProps } from 'antd'
|
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
disabled: boolean
|
||||||
sendMessage: () => void
|
sendMessage: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const SendMessageButton: FC<Props> = ({ sendMessage }) => {
|
const SendMessageButton: FC<Props> = ({ disabled, sendMessage }) => {
|
||||||
const { sendMessageShortcut, setSendMessageShortcut } = useSettings()
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
const sendSettingItems: MenuProps['items'] = [
|
|
||||||
{
|
|
||||||
label: `Enter ${t('chat.input.send')}`,
|
|
||||||
key: 'Enter',
|
|
||||||
icon: <EnterOutlined />,
|
|
||||||
onClick: () => setSendMessageShortcut('Enter')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: `Shift+Enter ${t('chat.input.send')}`,
|
|
||||||
key: 'Shift+Enter',
|
|
||||||
icon: <ArrowUpOutlined />,
|
|
||||||
onClick: () => setSendMessageShortcut('Shift+Enter')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown.Button
|
<i
|
||||||
size="small"
|
className="iconfont icon-ic_send"
|
||||||
onClick={sendMessage}
|
onClick={sendMessage}
|
||||||
trigger={['click']}
|
style={{
|
||||||
arrow
|
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||||
menu={{ items: sendSettingItems, selectable: true, defaultSelectedKeys: [sendMessageShortcut] }}
|
color: disabled ? 'var(--color-text-3)' : 'var(--color-primary)',
|
||||||
style={{ width: 'auto' }}>
|
fontSize: 22,
|
||||||
{t('chat.input.send')}
|
transition: 'all 0.2s'
|
||||||
<SendOutlined />
|
}}
|
||||||
</Dropdown.Button>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
|
||||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||||
import { Assistant, Topic } from '@renderer/types'
|
import { Assistant, Topic } from '@renderer/types'
|
||||||
|
import { Segmented } from 'antd'
|
||||||
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'
|
||||||
@ -54,14 +56,16 @@ const RightSidebar: FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Tabs>
|
<Segmented
|
||||||
<Tab className={tab === 'topic' ? 'active' : ''} onClick={() => setTab('topic')}>
|
value={tab}
|
||||||
{t('common.topics')}
|
style={{ borderRadius: 0, padding: '10px', gap: 5, borderBottom: '0.5px solid var(--color-border)' }}
|
||||||
</Tab>
|
options={[
|
||||||
<Tab className={tab === 'settings' ? 'active' : ''} onClick={() => setTab('settings')}>
|
{ label: t('common.topics'), value: 'topic', icon: <BarsOutlined /> },
|
||||||
{t('settings.title')}
|
{ label: t('settings.title'), value: 'settings', icon: <SettingOutlined /> }
|
||||||
</Tab>
|
]}
|
||||||
</Tabs>
|
block
|
||||||
|
onChange={(value) => setTab(value as 'topic' | 'settings')}
|
||||||
|
/>
|
||||||
<TabContent>
|
<TabContent>
|
||||||
{tab === 'topic' && <TopicsTab {...props} />}
|
{tab === 'topic' && <TopicsTab {...props} />}
|
||||||
{tab === 'settings' && <SettingsTab assistant={props.assistant} />}
|
{tab === 'settings' && <SettingsTab assistant={props.assistant} />}
|
||||||
@ -82,29 +86,6 @@ const Container = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Tabs = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
border-bottom: 0.5px solid var(--color-border);
|
|
||||||
padding: 0 10px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const Tab = styled.div`
|
|
||||||
padding: 8px 0;
|
|
||||||
font-weight: 500;
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
&.active {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const TabContent = styled.div`
|
const TabContent = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
|
import { CheckOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
import { DEFAULT_CONEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
import { DEFAULT_CONEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
@ -7,7 +7,7 @@ import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@r
|
|||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setMessageFont, setShowInputEstimatedTokens, setShowMessageDivider } from '@renderer/store/settings'
|
import { setMessageFont, setShowInputEstimatedTokens, setShowMessageDivider } from '@renderer/store/settings'
|
||||||
import { Assistant, AssistantSettings } from '@renderer/types'
|
import { Assistant, AssistantSettings } from '@renderer/types'
|
||||||
import { Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
|
import { Col, Row, Select, Slider, Switch, Tooltip } from 'antd'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { FC, useCallback, useEffect, useState } from 'react'
|
import { FC, useCallback, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -27,7 +27,8 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const { showMessageDivider, messageFont, showInputEstimatedTokens } = useSettings()
|
const { showMessageDivider, messageFont, showInputEstimatedTokens, sendMessageShortcut, setSendMessageShortcut } =
|
||||||
|
useSettings()
|
||||||
|
|
||||||
const onUpdateAssistantSettings = useCallback(
|
const onUpdateAssistantSettings = useCallback(
|
||||||
debounce(
|
debounce(
|
||||||
@ -104,27 +105,15 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Row>
|
</Row>
|
||||||
<Row align="middle" gutter={10}>
|
<Row align="middle" gutter={10}>
|
||||||
<Col span={18}>
|
<Col span={24}>
|
||||||
<Slider
|
<Slider
|
||||||
min={0}
|
min={0}
|
||||||
max={1.2}
|
max={1.2}
|
||||||
onChange={onTemperatureChange}
|
onChange={onTemperatureChange}
|
||||||
value={typeof temperature === 'number' ? temperature : 0}
|
value={typeof temperature === 'number' ? temperature : 0}
|
||||||
marks={{ 0: '0', 0.7: '0.7', 1.2: '1.2' }}
|
|
||||||
step={0.1}
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
|
||||||
<InputNumberic
|
|
||||||
min={0}
|
|
||||||
max={1.2}
|
|
||||||
step={0.1}
|
|
||||||
value={temperature}
|
|
||||||
onChange={onTemperatureChange}
|
|
||||||
controls={false}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
<Row align="middle">
|
<Row align="middle">
|
||||||
<Label>{t('chat.settings.conext_count')}</Label>
|
<Label>{t('chat.settings.conext_count')}</Label>
|
||||||
@ -133,27 +122,15 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Row>
|
</Row>
|
||||||
<Row align="middle" gutter={10}>
|
<Row align="middle" gutter={10}>
|
||||||
<Col span={18}>
|
<Col span={24}>
|
||||||
<Slider
|
<Slider
|
||||||
min={0}
|
min={0}
|
||||||
max={20}
|
max={20}
|
||||||
marks={{ 0: '0', 10: '10', 20: t('chat.settings.max') }}
|
|
||||||
onChange={onConextCountChange}
|
onChange={onConextCountChange}
|
||||||
value={typeof contextCount === 'number' ? contextCount : 0}
|
value={typeof contextCount === 'number' ? contextCount : 0}
|
||||||
step={1}
|
step={1}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
|
||||||
<InputNumberic
|
|
||||||
min={0}
|
|
||||||
max={20}
|
|
||||||
step={1}
|
|
||||||
value={contextCount}
|
|
||||||
onChange={onConextCountChange}
|
|
||||||
controls={false}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
<Row align="middle" justify="space-between" style={{ marginBottom: 8 }}>
|
<Row align="middle" justify="space-between" style={{ marginBottom: 8 }}>
|
||||||
<HStack alignItems="center">
|
<HStack alignItems="center">
|
||||||
@ -173,7 +150,7 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</Row>
|
</Row>
|
||||||
{enableMaxTokens && (
|
{enableMaxTokens && (
|
||||||
<Row align="middle" gutter={10}>
|
<Row align="middle" gutter={10}>
|
||||||
<Col span={16}>
|
<Col span={24}>
|
||||||
<Slider
|
<Slider
|
||||||
min={0}
|
min={0}
|
||||||
max={32000}
|
max={32000}
|
||||||
@ -182,18 +159,6 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
step={100}
|
step={100}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
|
||||||
<InputNumberic
|
|
||||||
min={0}
|
|
||||||
max={32000}
|
|
||||||
step={100}
|
|
||||||
value={maxTokens}
|
|
||||||
onChange={onMaxTokensChange}
|
|
||||||
controls={true}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
<SettingSubtitle>{t('settings.messages.title')}</SettingSubtitle>
|
<SettingSubtitle>{t('settings.messages.title')}</SettingSubtitle>
|
||||||
@ -227,6 +192,19 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitleSmall>{t('settings.messages.input.send_shortcuts')}</SettingRowTitleSmall>
|
||||||
|
</SettingRow>
|
||||||
|
<Select
|
||||||
|
value={sendMessageShortcut}
|
||||||
|
menuItemSelectedIcon={<CheckOutlined />}
|
||||||
|
options={[
|
||||||
|
{ value: 'Enter', label: `Enter ${t('chat.input.send')}` },
|
||||||
|
{ value: 'Shift+Enter', label: `Shift + Enter ${t('chat.input.send')}` }
|
||||||
|
]}
|
||||||
|
onChange={(value) => setSendMessageShortcut(value)}
|
||||||
|
style={{ width: '100%', marginTop: 10 }}
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -238,16 +216,6 @@ const Container = styled.div`
|
|||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const InputNumberic = styled(InputNumber)`
|
|
||||||
width: 45px;
|
|
||||||
padding: 0;
|
|
||||||
margin-left: 5px;
|
|
||||||
text-align: center;
|
|
||||||
.ant-input-number-input {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Label = styled.p`
|
const Label = styled.p`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@ -136,7 +136,7 @@ const Container = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 15px 10px;
|
padding: 10px 10px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const TopicListItem = styled.div`
|
const TopicListItem = styled.div`
|
||||||
|
|||||||
@ -8,12 +8,20 @@ import { useTheme } from './ThemeProvider'
|
|||||||
const AntdProvider: FC<PropsWithChildren> = ({ children }) => {
|
const AntdProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const { language } = useSettings()
|
const { language } = useSettings()
|
||||||
const { theme: _theme } = useTheme()
|
const { theme: _theme } = useTheme()
|
||||||
|
const isDarkTheme = _theme === 'dark'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
locale={getAntdLocale(language)}
|
locale={getAntdLocale(language)}
|
||||||
theme={{
|
theme={{
|
||||||
algorithm: [_theme === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm],
|
algorithm: [_theme === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm],
|
||||||
|
components: {
|
||||||
|
Segmented: {
|
||||||
|
trackBg: 'transparent',
|
||||||
|
itemSelectedBg: isDarkTheme ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)',
|
||||||
|
boxShadowTertiary: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
token: {
|
token: {
|
||||||
colorPrimary: '#00b96b',
|
colorPrimary: '#00b96b',
|
||||||
borderRadius: 8
|
borderRadius: 8
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user