revert: fold topics
This commit is contained in:
parent
563472f3a9
commit
ce830b692b
@ -36,8 +36,8 @@
|
||||
--color-error: #f44336;
|
||||
--color-link: #1677ff;
|
||||
--color-code-background: #323232;
|
||||
--color-scrollbar-thumb: rgba(255, 255, 255, 0.15);
|
||||
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.3);
|
||||
--color-scrollbar-thumb: rgba(255, 255, 255, 0.08);
|
||||
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.15);
|
||||
|
||||
--navbar-background-mac: rgba(30, 30, 30, 0.8);
|
||||
--navbar-background: rgba(30, 30, 30);
|
||||
@ -48,8 +48,8 @@
|
||||
--status-bar-height: 40px;
|
||||
--input-bar-height: 85px;
|
||||
|
||||
--assistants-width: 280px;
|
||||
--topic-list-width: 280px;
|
||||
--assistants-width: 250px;
|
||||
--topic-list-width: 250px;
|
||||
--settings-width: var(--assistants-width);
|
||||
}
|
||||
|
||||
@ -86,8 +86,8 @@ body[theme-mode='light'] {
|
||||
--color-error: #f44336;
|
||||
--color-link: #1677ff;
|
||||
--color-code-background: #e3e3e3;
|
||||
--color-scrollbar-thumb: rgba(0, 0, 0, 0.15);
|
||||
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.3);
|
||||
--color-scrollbar-thumb: rgba(0, 0, 0, 0.08);
|
||||
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.15);
|
||||
|
||||
--navbar-background-mac: rgba(255, 255, 255, 0.75);
|
||||
--navbar-background: rgba(255, 255, 255);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* 全局初始化滚动条样式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
@ -10,7 +10,6 @@
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-scrollbar-thumb);
|
||||
border-radius: 5px;
|
||||
&:hover {
|
||||
background: var(--color-scrollbar-thumb-hover);
|
||||
}
|
||||
|
||||
@ -4,13 +4,14 @@ import { FC } from 'react'
|
||||
|
||||
interface Props<T> {
|
||||
list: T[]
|
||||
style?: React.CSSProperties
|
||||
children: (item: T, index: number) => React.ReactNode
|
||||
onUpdate: (list: T[]) => void
|
||||
onDragStart?: () => void
|
||||
onDragEnd?: () => void
|
||||
}
|
||||
|
||||
const DragableList: FC<Props<any>> = ({ children, list, onDragStart, onUpdate, onDragEnd }) => {
|
||||
const DragableList: FC<Props<any>> = ({ children, list, style, onDragStart, onUpdate, onDragEnd }) => {
|
||||
const _onDragEnd = (result: DropResult) => {
|
||||
onDragEnd?.()
|
||||
if (result.destination) {
|
||||
@ -33,7 +34,7 @@ const DragableList: FC<Props<any>> = ({ children, list, onDragStart, onUpdate, o
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
style={{ ...provided.draggableProps.style, marginBottom: 8 }}>
|
||||
style={{ ...provided.draggableProps.style, marginBottom: 8, ...style }}>
|
||||
{children(item, index)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -34,7 +34,14 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ assistant, resolve })
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal title={assistant.name} open={open} onOk={onOk} onCancel={handleCancel} afterClose={onClose}>
|
||||
<Modal
|
||||
title={assistant.name}
|
||||
open={open}
|
||||
onOk={onOk}
|
||||
onCancel={handleCancel}
|
||||
afterClose={onClose}
|
||||
transitionName="ant-move-down"
|
||||
maskTransitionName="ant-fade">
|
||||
<Box mb={8}>{t('common.name')}</Box>
|
||||
<Input
|
||||
placeholder={t('common.assistant') + t('common.name')}
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { toggleShowAssistants } from '@renderer/store/settings'
|
||||
import { setShowRightSidebar, toggleRightSidebar, toggleShowAssistants } from '@renderer/store/settings'
|
||||
|
||||
export function useShowRightSidebar() {
|
||||
const showRightSidebar = useAppSelector((state) => state.settings.showRightSidebar)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
rightSidebarShown: showRightSidebar,
|
||||
toggleRightSidebar: () => dispatch(toggleRightSidebar()),
|
||||
showRightSidebar: () => dispatch(setShowRightSidebar(true)),
|
||||
hideRightSidebar: () => dispatch(setShowRightSidebar(false))
|
||||
}
|
||||
}
|
||||
|
||||
export function useShowAssistants() {
|
||||
const showAssistants = useAppSelector((state) => state.settings.showAssistants)
|
||||
|
||||
@ -70,6 +70,7 @@ const resources = {
|
||||
'topics.delete.all.content': 'Are you sure you want to delete all topics?',
|
||||
'topics.list': 'Topic List',
|
||||
'input.new_topic': 'New Topic',
|
||||
'input.topics': ' Topics ',
|
||||
'input.clear': 'Clear',
|
||||
'input.expand': 'Expand',
|
||||
'input.collapse': 'Collapse',
|
||||
@ -315,6 +316,7 @@ const resources = {
|
||||
'topics.delete.all.content': '确定要删除所有话题吗?',
|
||||
'topics.list': '话题列表',
|
||||
'input.new_topic': '新话题',
|
||||
'input.topics': ' 话题 ',
|
||||
'input.clear': '清除',
|
||||
'input.expand': '展开',
|
||||
'input.collapse': '收起',
|
||||
|
||||
@ -5,36 +5,22 @@ import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { getDefaultTopic, syncAsistantToAgent } from '@renderer/services/assistant'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Dropdown, Tooltip } from 'antd'
|
||||
import { Dropdown } from 'antd'
|
||||
import { ItemType } from 'antd/es/menu/interface'
|
||||
import { last } from 'lodash'
|
||||
import { FC, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Topics from './Topics'
|
||||
|
||||
interface Props {
|
||||
activeAssistant: Assistant
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
showTopics: boolean
|
||||
setShowTopics: (showTopics: boolean) => void
|
||||
onCreateAssistant: () => void
|
||||
}
|
||||
|
||||
const Assistants: FC<Props> = ({
|
||||
activeAssistant,
|
||||
setActiveAssistant,
|
||||
activeTopic,
|
||||
setActiveTopic,
|
||||
showTopics,
|
||||
setShowTopics,
|
||||
onCreateAssistant
|
||||
}) => {
|
||||
const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => {
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
const { updateAssistant } = useAssistant(activeAssistant.id)
|
||||
@ -49,6 +35,15 @@ const Assistants: FC<Props> = ({
|
||||
[assistants, onCreateAssistant, removeAssistant, setActiveAssistant]
|
||||
)
|
||||
|
||||
const onEditAssistant = useCallback(
|
||||
async (assistant: Assistant) => {
|
||||
const _assistant = await AssistantSettingPopup.show({ assistant })
|
||||
updateAssistant(_assistant)
|
||||
syncAsistantToAgent(_assistant)
|
||||
},
|
||||
[updateAssistant]
|
||||
)
|
||||
|
||||
const getMenuItems = useCallback(
|
||||
(assistant: Assistant) =>
|
||||
[
|
||||
@ -56,11 +51,7 @@ const Assistants: FC<Props> = ({
|
||||
label: t('common.edit'),
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
async onClick() {
|
||||
const _assistant = await AssistantSettingPopup.show({ assistant })
|
||||
updateAssistant(_assistant)
|
||||
syncAsistantToAgent(_assistant)
|
||||
}
|
||||
onClick: () => onEditAssistant(assistant)
|
||||
},
|
||||
{
|
||||
label: t('common.duplicate'),
|
||||
@ -81,7 +72,7 @@ const Assistants: FC<Props> = ({
|
||||
onClick: () => onDelete(assistant)
|
||||
}
|
||||
] as ItemType[],
|
||||
[addAssistant, onDelete, setActiveAssistant, t, updateAssistant]
|
||||
[addAssistant, onDelete, onEditAssistant, setActiveAssistant, t]
|
||||
)
|
||||
|
||||
const onSwitchAssistant = useCallback(
|
||||
@ -93,25 +84,12 @@ const Assistants: FC<Props> = ({
|
||||
})
|
||||
}
|
||||
|
||||
if (assistant.id === activeAssistant?.id) {
|
||||
setShowTopics(true)
|
||||
return
|
||||
}
|
||||
|
||||
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
|
||||
setActiveAssistant(assistant)
|
||||
},
|
||||
[activeAssistant?.id, generating, setActiveAssistant, setShowTopics, t]
|
||||
[generating, setActiveAssistant, t]
|
||||
)
|
||||
|
||||
if (showTopics) {
|
||||
return (
|
||||
<Container style={{ padding: 0 }}>
|
||||
<Topics assistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<DragableList list={assistants} onUpdate={updateAssistants}>
|
||||
@ -121,11 +99,9 @@ const Assistants: FC<Props> = ({
|
||||
onClick={() => onSwitchAssistant(assistant)}
|
||||
className={assistant.id === activeAssistant?.id ? 'active' : ''}>
|
||||
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
|
||||
<Tooltip arrow title={t('chat.topics.list')} placement="bottom" mouseEnterDelay={0.5}>
|
||||
<ArrowRightButton className="arrow-button" onClick={() => setShowTopics(true)}>
|
||||
<ArrowRightOutlined />
|
||||
</ArrowRightButton>
|
||||
</Tooltip>
|
||||
<ArrowRightButton className="arrow-button" onClick={() => onEditAssistant(assistant)}>
|
||||
<ArrowRightOutlined />
|
||||
</ArrowRightButton>
|
||||
{false && <TopicCount className="topics-count">{assistant.topics.length}</TopicCount>}
|
||||
</AssistantItem>
|
||||
</Dropdown>
|
||||
@ -205,6 +181,7 @@ const ArrowRightButton = styled.div`
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 5px;
|
||||
&:hover {
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Flex } from 'antd'
|
||||
import { FC, useState } from 'react'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Inputbar from './Inputbar/Inputbar'
|
||||
import Messages from './Messages/Messages'
|
||||
import Settings from './Settings'
|
||||
import RightSidebar from './RightSidebar'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
@ -17,19 +18,19 @@ interface Props {
|
||||
const Chat: FC<Props> = (props) => {
|
||||
const { assistant } = useAssistant(props.assistant.id)
|
||||
const [showSetting, setShowSetting] = useState(false)
|
||||
const { rightSidebarShown } = useShowRightSidebar()
|
||||
|
||||
useEffect(() => {
|
||||
!rightSidebarShown && showSetting && setShowSetting(false)
|
||||
}, [rightSidebarShown, showSetting])
|
||||
|
||||
return (
|
||||
<Container id="chat">
|
||||
<Main vertical flex={1} justify="space-between">
|
||||
<Messages assistant={assistant} topic={props.activeTopic} />
|
||||
<Inputbar
|
||||
assistant={assistant}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
showSetting={showSetting}
|
||||
setShowSetting={setShowSetting}
|
||||
/>
|
||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} />
|
||||
</Main>
|
||||
{showSetting && <Settings assistant={assistant} onClose={() => setShowSetting(false)} />}
|
||||
<RightSidebar assistant={assistant} activeTopic={props.activeTopic} setActiveTopic={props.setActiveTopic} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,41 +1,26 @@
|
||||
import { ArrowLeftOutlined, UnorderedListOutlined } from '@ant-design/icons'
|
||||
import { Navbar, NavbarCenter, NavbarLeft } from '@renderer/components/app/Navbar'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { isMac, isWindows } from '@renderer/config/constant'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useAssistant, useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowAssistants } from '@renderer/hooks/useStore'
|
||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||
import { getDefaultTopic } from '@renderer/services/assistant'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Switch } from 'antd'
|
||||
import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import AddAssistantPopup from '../../components/Popups/AddAssistantPopup'
|
||||
import Assistants from './Assistants'
|
||||
import Chat from './Chat'
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
import Navbar from './Navbar'
|
||||
|
||||
let _activeAssistant: Assistant
|
||||
let _showTopics = false
|
||||
|
||||
const HomePage: FC = () => {
|
||||
const { assistants, addAssistant } = useAssistants()
|
||||
const [activeAssistant, setActiveAssistant] = useState(_activeAssistant || assistants[0])
|
||||
const { showAssistants } = useShowAssistants()
|
||||
const { defaultAssistant } = useDefaultAssistant()
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
const [showTopics, setShowTopics] = useState(_showTopics)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(activeAssistant)
|
||||
const { addTopic } = useAssistant(activeAssistant.id)
|
||||
|
||||
_activeAssistant = activeAssistant
|
||||
_showTopics = showTopics
|
||||
|
||||
const onCreateDefaultAssistant = () => {
|
||||
const assistant = { ...defaultAssistant, id: uuid() }
|
||||
@ -43,59 +28,18 @@ const HomePage: FC = () => {
|
||||
setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
const onCreate = async () => {
|
||||
if (showTopics) {
|
||||
const topic = getDefaultTopic()
|
||||
addTopic(topic)
|
||||
setActiveTopic(topic)
|
||||
} else {
|
||||
const assistant = await AddAssistantPopup.show()
|
||||
assistant && setActiveAssistant(assistant)
|
||||
}
|
||||
}
|
||||
|
||||
const onSetActiveTopic = (topic: Topic) => {
|
||||
setActiveTopic(topic)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Navbar>
|
||||
{showAssistants && (
|
||||
<NavbarLeft
|
||||
style={{ justifyContent: 'space-between', alignItems: 'center', borderRight: 'none', padding: '0 8px' }}>
|
||||
<NewButton onClick={() => setShowTopics(!showTopics)} className="back-button">
|
||||
{showTopics ? <ArrowLeftOutlined /> : <UnorderedListOutlined />}
|
||||
<BackText>{showTopics ? t('common.assistant') : t('chat.topics.title')}</BackText>
|
||||
</NewButton>
|
||||
<NewButton onClick={onCreate}>
|
||||
<i className="iconfont icon-a-addchat"></i>
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
<NavbarCenter
|
||||
style={{ justifyContent: 'space-between', paddingLeft: isMac ? 16 : 8, paddingRight: isWindows ? 135 : 12 }}>
|
||||
<HStack alignItems="center">
|
||||
<AssistantName>{activeAssistant?.name || t('chat.default.name')}</AssistantName>
|
||||
<SelectModelButton assistant={activeAssistant} />
|
||||
</HStack>
|
||||
<ThemeSwitch
|
||||
checkedChildren={<i className="iconfont icon-theme icon-dark1" />}
|
||||
unCheckedChildren={<i className="iconfont icon-theme icon-theme-light" />}
|
||||
checked={theme === 'dark'}
|
||||
onChange={toggleTheme}
|
||||
/>
|
||||
</NavbarCenter>
|
||||
</Navbar>
|
||||
<Navbar activeAssistant={activeAssistant} setActiveAssistant={setActiveAssistant} />
|
||||
<ContentContainer>
|
||||
{showAssistants && (
|
||||
<Assistants
|
||||
activeAssistant={activeAssistant}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
activeTopic={activeTopic}
|
||||
setActiveTopic={setActiveTopic}
|
||||
showTopics={showTopics}
|
||||
setShowTopics={setShowTopics}
|
||||
onCreateAssistant={onCreateDefaultAssistant}
|
||||
/>
|
||||
)}
|
||||
@ -118,67 +62,4 @@ const ContentContainer = styled.div`
|
||||
background-color: var(--color-background);
|
||||
`
|
||||
|
||||
const AssistantName = styled.span`
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
font-family: Ubuntu;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
`
|
||||
|
||||
export const NewButton = styled.div`
|
||||
-webkit-app-region: none;
|
||||
border-radius: 4px;
|
||||
padding: 0 5px;
|
||||
height: 30px;
|
||||
gap: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
color: var(--color-icon);
|
||||
.icon-a-addchat {
|
||||
font-size: 20px;
|
||||
}
|
||||
.anticon {
|
||||
font-size: 19px;
|
||||
}
|
||||
.icon-showsidebarhoriz,
|
||||
.icon-hidesidebarhoriz {
|
||||
font-size: 17px;
|
||||
}
|
||||
&.back-button {
|
||||
margin-left: ${isMac ? '8px' : 0};
|
||||
.anticon {
|
||||
font-size: 16px;
|
||||
}
|
||||
.anticon-arrow-left {
|
||||
font-size: 14px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-mute);
|
||||
color: var(--color-icon-white);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-mute);
|
||||
cursor: pointer;
|
||||
color: var(--color-icon-white);
|
||||
}
|
||||
`
|
||||
|
||||
const BackText = styled.span`
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
`
|
||||
|
||||
const ThemeSwitch = styled(Switch)`
|
||||
-webkit-app-region: none;
|
||||
margin-right: 10px;
|
||||
.icon-theme {
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
|
||||
export default HomePage
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
ControlOutlined,
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
HistoryOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlusCircleOutlined,
|
||||
QuestionCircleOutlined
|
||||
@ -30,13 +31,11 @@ import SendMessageButton from './SendMessageButton'
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
showSetting: boolean
|
||||
setShowSetting: (show: boolean) => void
|
||||
}
|
||||
|
||||
let _text = ''
|
||||
|
||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic, showSetting, setShowSetting }) => {
|
||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
const [text, setText] = useState(_text)
|
||||
const [inputFocus, setInputFocus] = useState(false)
|
||||
const { addTopic } = useAssistant(assistant.id)
|
||||
@ -221,8 +220,13 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic, showSetting, setShowSe
|
||||
</ToolbarButton>
|
||||
</Popconfirm>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow className={showSetting ? 'active' : ''}>
|
||||
<ToolbarButton type="text" onClick={() => setShowSetting(!showSetting)}>
|
||||
<Tooltip placement="top" title={t('chat.input.topics')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR)}>
|
||||
<HistoryOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS)}>
|
||||
<ControlOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
@ -236,7 +240,6 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic, showSetting, setShowSe
|
||||
<TextCount>
|
||||
<Tooltip title={t('chat.input.context_count.tip') + ' | ' + t('chat.input.estimated_tokens.tip')}>
|
||||
<StyledTag>
|
||||
<i className="iconfont icon-history" style={{ marginRight: '3px' }} />
|
||||
{assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT}
|
||||
<Divider type="vertical" style={{ marginTop: 2, marginLeft: 5, marginRight: 5 }} />↑{inputTokenCount}
|
||||
<span style={{ margin: '0 2px' }}>/</span>
|
||||
@ -342,11 +345,12 @@ const TextCount = styled.div`
|
||||
|
||||
const StyledTag = styled(Tag)`
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-width: 0.5;
|
||||
margin: 0;
|
||||
`
|
||||
|
||||
export default Inputbar
|
||||
|
||||
111
src/renderer/src/pages/home/Navbar.tsx
Normal file
111
src/renderer/src/pages/home/Navbar.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
|
||||
import { isMac, isWindows } from '@renderer/config/constant'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { removeLeadingEmoji } from '@renderer/utils'
|
||||
import { Switch } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
|
||||
interface Props {
|
||||
activeAssistant: Assistant
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant }) => {
|
||||
const { assistant } = useAssistant(activeAssistant.id)
|
||||
const { t } = useTranslation()
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { rightSidebarShown, toggleRightSidebar } = useShowRightSidebar()
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
|
||||
const onCreateAssistant = async () => {
|
||||
const assistant = await AddAssistantPopup.show()
|
||||
assistant && setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
return (
|
||||
<Navbar>
|
||||
{showAssistants && (
|
||||
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: '0 8px' }}>
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 8 : 0 }}>
|
||||
<i className="iconfont icon-hidesidebarhoriz" />
|
||||
</NewButton>
|
||||
<NewButton onClick={onCreateAssistant}>
|
||||
<i className="iconfont icon-a-addchat"></i>
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
<NavbarCenter style={{ paddingLeft: isMac ? 16 : 8 }}>
|
||||
{!showAssistants && (
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginRight: isMac ? 8 : 25 }}>
|
||||
<i className="iconfont icon-showsidebarhoriz" />
|
||||
</NewButton>
|
||||
)}
|
||||
<AssistantName>{removeLeadingEmoji(assistant?.name) || t('chat.default.name')}</AssistantName>
|
||||
<SelectModelButton assistant={assistant} />
|
||||
</NavbarCenter>
|
||||
<NavbarRight style={{ justifyContent: 'flex-end', paddingRight: isWindows ? 140 : 12 }}>
|
||||
<ThemeSwitch
|
||||
checkedChildren={<i className="iconfont icon-theme icon-dark1" />}
|
||||
unCheckedChildren={<i className="iconfont icon-theme icon-theme-light" />}
|
||||
checked={theme === 'dark'}
|
||||
onChange={toggleTheme}
|
||||
/>
|
||||
<NewButton onClick={toggleRightSidebar}>
|
||||
<i className={`iconfont ${rightSidebarShown ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} />
|
||||
</NewButton>
|
||||
</NavbarRight>
|
||||
</Navbar>
|
||||
)
|
||||
}
|
||||
|
||||
export const NewButton = styled.div`
|
||||
-webkit-app-region: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
color: var(--color-icon);
|
||||
cursor: pointer;
|
||||
.icon-a-addchat {
|
||||
font-size: 20px;
|
||||
}
|
||||
.anticon {
|
||||
font-size: 19px;
|
||||
}
|
||||
.icon-showsidebarhoriz,
|
||||
.icon-hidesidebarhoriz {
|
||||
font-size: 17px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-mute);
|
||||
color: var(--color-icon-white);
|
||||
}
|
||||
`
|
||||
|
||||
const AssistantName = styled.span`
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
font-family: Ubuntu;
|
||||
`
|
||||
|
||||
const ThemeSwitch = styled(Switch)`
|
||||
-webkit-app-region: none;
|
||||
margin-right: 10px;
|
||||
.icon-theme {
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
|
||||
export default HeaderNavbar
|
||||
96
src/renderer/src/pages/home/RightSidebar.tsx
Normal file
96
src/renderer/src/pages/home/RightSidebar.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Segmented } from 'antd'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Settings from './Settings'
|
||||
import Topics from './Topics'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const RightSidebar: FC<Props> = (props) => {
|
||||
const [tab, setTab] = useState<'topic' | 'settings'>('topic')
|
||||
const { rightSidebarShown, showRightSidebar, hideRightSidebar } = useShowRightSidebar()
|
||||
const { t } = useTranslation()
|
||||
const isTopicTab = tab === 'topic'
|
||||
const isSettingsTab = tab === 'settings'
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
||||
if (rightSidebarShown && isTopicTab) {
|
||||
return hideRightSidebar()
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
return setTab('topic')
|
||||
}
|
||||
showRightSidebar()
|
||||
setTab('topic')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
|
||||
if (rightSidebarShown && isSettingsTab) {
|
||||
return hideRightSidebar()
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
return setTab('settings')
|
||||
}
|
||||
showRightSidebar()
|
||||
setTab('settings')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => setTab('topic'))
|
||||
]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
}, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar])
|
||||
|
||||
if (!rightSidebarShown) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Segmented
|
||||
value={tab}
|
||||
style={{ borderRadius: 0, padding: '10px', gap: 5, borderBottom: '0.5px solid var(--color-border)' }}
|
||||
options={[
|
||||
{ label: t('common.topics'), value: 'topic', icon: <BarsOutlined /> },
|
||||
{ label: t('settings.title'), value: 'settings', icon: <SettingOutlined /> }
|
||||
]}
|
||||
block
|
||||
onChange={(value) => setTab(value as 'topic' | 'settings')}
|
||||
/>
|
||||
<TabContent>
|
||||
{tab === 'topic' && <Topics {...props} />}
|
||||
{tab === 'settings' && <Settings assistant={props.assistant} />}
|
||||
</TabContent>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: var(--topic-list-width);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
.collapsed {
|
||||
width: 0;
|
||||
border-left: none;
|
||||
}
|
||||
`
|
||||
|
||||
const TabContent = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
`
|
||||
|
||||
export default RightSidebar
|
||||
@ -1,4 +1,4 @@
|
||||
import { CheckOutlined, CloseOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
|
||||
import { CheckOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { DEFAULT_CONEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
@ -19,7 +19,6 @@ import styled from 'styled-components'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const SettingsTab: FC<Props> = (props) => {
|
||||
@ -88,10 +87,6 @@ const SettingsTab: FC<Props> = (props) => {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<SettingsHeader>
|
||||
{t('settings.title')}
|
||||
<CloseIcon onClick={props.onClose} />
|
||||
</SettingsHeader>
|
||||
<SettingSubtitle>
|
||||
{t('settings.messages.model.title')}{' '}
|
||||
<Tooltip title={t('chat.settings.reset')}>
|
||||
@ -264,21 +259,4 @@ const SettingRowTitleSmall = styled(SettingRowTitle)`
|
||||
font-size: 13px;
|
||||
`
|
||||
|
||||
const SettingsHeader = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 15px;
|
||||
border-bottom: 0.5px solid var(--color-border);
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
`
|
||||
|
||||
const CloseIcon = styled(CloseOutlined)`
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-3);
|
||||
`
|
||||
|
||||
export default SettingsTab
|
||||
|
||||
@ -125,10 +125,15 @@ const Container = styled.div`
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-top: 10px;
|
||||
min-width: var(--topic-list-width);
|
||||
max-width: var(--topic-list-width);
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
overflow-y: scroll;
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
`
|
||||
|
||||
const TopicListItem = styled.div`
|
||||
padding: 5px 10px;
|
||||
padding: 7px 10px;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
|
||||
@ -9,6 +9,7 @@ export enum ThemeMode {
|
||||
}
|
||||
|
||||
export interface SettingsState {
|
||||
showRightSidebar: boolean
|
||||
showAssistants: boolean
|
||||
sendMessageShortcut: SendMessageShortcut
|
||||
language: string
|
||||
@ -23,6 +24,7 @@ export interface SettingsState {
|
||||
}
|
||||
|
||||
const initialState: SettingsState = {
|
||||
showRightSidebar: true,
|
||||
showAssistants: true,
|
||||
sendMessageShortcut: 'Enter',
|
||||
language: navigator.language,
|
||||
@ -32,7 +34,7 @@ const initialState: SettingsState = {
|
||||
messageFont: 'system',
|
||||
showInputEstimatedTokens: false,
|
||||
theme: ThemeMode.light,
|
||||
windowStyle: 'opaque',
|
||||
windowStyle: 'transparent',
|
||||
fontSize: 14
|
||||
}
|
||||
|
||||
@ -40,6 +42,12 @@ const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
reducers: {
|
||||
toggleRightSidebar: (state) => {
|
||||
state.showRightSidebar = !state.showRightSidebar
|
||||
},
|
||||
setShowRightSidebar: (state, action: PayloadAction<boolean>) => {
|
||||
state.showRightSidebar = action.payload
|
||||
},
|
||||
toggleShowAssistants: (state) => {
|
||||
state.showAssistants = !state.showAssistants
|
||||
},
|
||||
@ -78,6 +86,8 @@ const settingsSlice = createSlice({
|
||||
})
|
||||
|
||||
export const {
|
||||
setShowRightSidebar,
|
||||
toggleRightSidebar,
|
||||
toggleShowAssistants,
|
||||
setSendMessageShortcut,
|
||||
setLanguage,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user