feat: add show or hide assistant sidebar

This commit is contained in:
kangfenmao 2024-07-22 21:57:39 +08:00
parent a0c147ae3f
commit f434fe1231
8 changed files with 88 additions and 31 deletions

View File

@ -12,7 +12,7 @@
--color-white-mute: #f2f2f2; --color-white-mute: #f2f2f2;
--color-black: #1b1b1f; --color-black: #1b1b1f;
--color-black-soft: #303030; --color-black-soft: #262626;
--color-black-mute: #363636; --color-black-mute: #363636;
--color-gray-1: #515c67; --color-gray-1: #515c67;

View File

@ -1,5 +1,5 @@
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch, useAppSelector } from '@renderer/store'
import { toggleRightSidebar } from '@renderer/store/settings' import { toggleRightSidebar, toggleShowAssistants } from '@renderer/store/settings'
export function useShowRightSidebar() { export function useShowRightSidebar() {
const showRightSidebar = useAppSelector((state) => state.settings.showRightSidebar) const showRightSidebar = useAppSelector((state) => state.settings.showRightSidebar)
@ -7,6 +7,16 @@ export function useShowRightSidebar() {
return { return {
showRightSidebar, showRightSidebar,
setShowRightSidebar: () => dispatch(toggleRightSidebar()) toggleRightSidebar: () => dispatch(toggleRightSidebar())
}
}
export function useShowAssistants() {
const showAssistants = useAppSelector((state) => state.settings.showAssistants)
const dispatch = useAppDispatch()
return {
showAssistants,
toggleShowAssistants: () => dispatch(toggleShowAssistants())
} }
} }

View File

@ -5,15 +5,17 @@ import styled from 'styled-components'
import Chat from './components/Chat' import Chat from './components/Chat'
import Assistants from './components/Assistants' import Assistants from './components/Assistants'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { useShowRightSidebar } from '@renderer/hooks/useStore' import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import Navigation from './components/Navigation' import Navigation from './components/Navigation'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { PlusSquareOutlined } from '@ant-design/icons'
const HomePage: FC = () => { const HomePage: FC = () => {
const { assistants, addAssistant } = useAssistants() const { assistants, addAssistant } = useAssistants()
const [activeAssistant, setActiveAssistant] = useState(assistants[0]) const [activeAssistant, setActiveAssistant] = useState(assistants[0])
const { showRightSidebar, setShowRightSidebar } = useShowRightSidebar() const { showRightSidebar, toggleRightSidebar } = useShowRightSidebar()
const { showAssistants, toggleShowAssistants } = useShowAssistants()
const { defaultAssistant } = useDefaultAssistant() const { defaultAssistant } = useDefaultAssistant()
const { t } = useTranslation() const { t } = useTranslation()
@ -26,29 +28,36 @@ const HomePage: FC = () => {
return ( return (
<Container> <Container>
<Navbar> <Navbar>
<NavbarLeft style={{ justifyContent: 'flex-end', borderRight: 'none' }}> {showAssistants && (
<NewButton onClick={onCreateAssistant}> <NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: '0 8px' }}>
<i className="iconfont icon-a-addchat"></i> <NewButton onClick={toggleShowAssistants} style={{ marginLeft: 8 }}>
</NewButton> <i className="iconfont icon-hidesidebarhoriz" />
</NavbarLeft> </NewButton>
<NewButton onClick={onCreateAssistant}>
<PlusSquareOutlined />
</NewButton>
</NavbarLeft>
)}
<Navigation activeAssistant={activeAssistant} /> <Navigation activeAssistant={activeAssistant} />
<NavbarRight style={{ justifyContent: 'flex-end', padding: 5 }}> <NavbarRight style={{ justifyContent: 'flex-end', padding: 5 }}>
<Tooltip <Tooltip
placement="left" placement="left"
title={showRightSidebar ? t('assistant.topics.hide_topics') : t('assistant.topics.show_topics')} title={showRightSidebar ? t('assistant.topics.hide_topics') : t('assistant.topics.show_topics')}
arrow> arrow>
<NewButton onClick={setShowRightSidebar}> <NewButton onClick={toggleRightSidebar}>
<i className={`iconfont ${showRightSidebar ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} /> <i className={`iconfont ${showRightSidebar ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} />
</NewButton> </NewButton>
</Tooltip> </Tooltip>
</NavbarRight> </NavbarRight>
</Navbar> </Navbar>
<ContentContainer> <ContentContainer>
<Assistants {showAssistants && (
activeAssistant={activeAssistant} <Assistants
setActiveAssistant={setActiveAssistant} activeAssistant={activeAssistant}
onCreateAssistant={onCreateAssistant} setActiveAssistant={setActiveAssistant}
/> onCreateAssistant={onCreateAssistant}
/>
)}
<Chat assistant={activeAssistant} /> <Chat assistant={activeAssistant} />
</ContentContainer> </ContentContainer>
</Container> </Container>
@ -59,33 +68,31 @@ const Container = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
height: calc(100vh - var(--navbar-height));
` `
const ContentContainer = styled.div` const ContentContainer = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: row; flex-direction: row;
height: 100%;
` `
const NewButton = styled.div` export const NewButton = styled.div`
-webkit-app-region: none; -webkit-app-region: none;
border-radius: 4px; border-radius: 4px;
width: 34px; width: 28px;
height: 34px; height: 28px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
color: var(--color-icon); color: var(--color-icon);
.iconfont { .anticon {
font-size: 22px; font-size: 18px;
} }
.icon-showsidebarhoriz, .icon-showsidebarhoriz,
.icon-hidesidebarhoriz { .icon-hidesidebarhoriz {
font-size: 18px; font-size: 16px;
} }
&:hover { &:hover {
background-color: var(--color-background-soft); background-color: var(--color-background-soft);

View File

@ -7,6 +7,9 @@ import { Button, Dropdown, MenuProps } from 'antd'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import { NewButton } from '../HomePage'
import { useShowAssistants } from '@renderer/hooks/useStore'
import { capitalizeFirstLetter } from '@renderer/utils'
interface Props { interface Props {
activeAssistant: Assistant activeAssistant: Assistant
@ -17,6 +20,7 @@ const Navigation: FC<Props> = ({ activeAssistant }) => {
const { model, setModel } = useAssistant(activeAssistant.id) const { model, setModel } = useAssistant(activeAssistant.id)
const { providers } = useProviders() const { providers } = useProviders()
const { t } = useTranslation() const { t } = useTranslation()
const { showAssistants, toggleShowAssistants } = useShowAssistants()
const items: MenuProps['items'] = providers const items: MenuProps['items'] = providers
.filter((p) => p.models.length > 0) .filter((p) => p.models.length > 0)
@ -33,12 +37,17 @@ const Navigation: FC<Props> = ({ activeAssistant }) => {
})) }))
return ( return (
<NavbarCenter style={{ border: 'none', padding: '0 15px' }}> <NavbarCenter style={{ border: 'none', paddingLeft: showAssistants ? 8 : 16 }}>
{assistant?.name} {!showAssistants && (
<NewButton onClick={toggleShowAssistants} style={{ marginRight: 8 }}>
<i className="iconfont icon-showsidebarhoriz" />
</NewButton>
)}
<AssistantName>{assistant?.name}</AssistantName>
<DropdownMenu menu={{ items, style: { maxHeight: '80vh', overflow: 'auto' } }} trigger={['click']}> <DropdownMenu menu={{ items, style: { maxHeight: '80vh', overflow: 'auto' } }} trigger={['click']}>
<Button size="small" type="primary" ghost style={{ fontSize: '11px' }}> <DropdownButton size="small" type="primary" ghost>
{model ? model.name : t('button.select_model')} {model ? capitalizeFirstLetter(model.name) : t('button.select_model')}
</Button> </DropdownButton>
</DropdownMenu> </DropdownMenu>
</NavbarCenter> </NavbarCenter>
) )
@ -49,4 +58,15 @@ const DropdownMenu = styled(Dropdown)`
margin-left: 10px; margin-left: 10px;
` `
const AssistantName = styled.span`
font-weight: bold;
margin-left: 5px;
`
const DropdownButton = styled(Button)`
font-size: 10px;
border-radius: 15px;
padding: 0 8px;
`
export default Navigation export default Navigation

View File

@ -19,7 +19,7 @@ const persistedReducer = persistReducer(
{ {
key: 'cherry-studio', key: 'cherry-studio',
storage, storage,
version: 13, version: 14,
blacklist: ['runtime'], blacklist: ['runtime'],
migrate migrate
}, },

View File

@ -243,6 +243,16 @@ const migrate = createMigrate({
} }
} }
} }
},
// @ts-ignore store type is unknown
'14': (state: RootState) => {
return {
...state,
settings: {
...state.settings,
showAssistants: true
}
}
} }
}) })

View File

@ -4,12 +4,14 @@ export type SendMessageShortcut = 'Enter' | 'Shift+Enter'
export interface SettingsState { export interface SettingsState {
showRightSidebar: boolean showRightSidebar: boolean
showAssistants: boolean
sendMessageShortcut: SendMessageShortcut sendMessageShortcut: SendMessageShortcut
language: string language: string
} }
const initialState: SettingsState = { const initialState: SettingsState = {
showRightSidebar: true, showRightSidebar: true,
showAssistants: true,
sendMessageShortcut: 'Enter', sendMessageShortcut: 'Enter',
language: navigator.language language: navigator.language
} }
@ -21,6 +23,9 @@ const settingsSlice = createSlice({
toggleRightSidebar: (state) => { toggleRightSidebar: (state) => {
state.showRightSidebar = !state.showRightSidebar state.showRightSidebar = !state.showRightSidebar
}, },
toggleShowAssistants: (state) => {
state.showAssistants = !state.showAssistants
},
setSendMessageShortcut: (state, action: PayloadAction<SendMessageShortcut>) => { setSendMessageShortcut: (state, action: PayloadAction<SendMessageShortcut>) => {
state.sendMessageShortcut = action.payload state.sendMessageShortcut = action.payload
}, },
@ -30,6 +35,6 @@ const settingsSlice = createSlice({
} }
}) })
export const { toggleRightSidebar, setSendMessageShortcut, setLanguage } = settingsSlice.actions export const { toggleRightSidebar, toggleShowAssistants, setSendMessageShortcut, setLanguage } = settingsSlice.actions
export default settingsSlice.reducer export default settingsSlice.reducer

View File

@ -198,3 +198,8 @@ export function estimateHistoryTokenCount(assistant: Assistant, msgs: Message[])
return all.usedTokens - 7 return all.usedTokens - 7
} }
// 首字母大写
export const capitalizeFirstLetter = (str: string) => {
return str.charAt(0).toUpperCase() + str.slice(1)
}