feat: change topics position
This commit is contained in:
parent
d809f50c0e
commit
ab0e7e1e07
@ -3,6 +3,7 @@ import {
|
||||
SendMessageShortcut,
|
||||
setSendMessageShortcut as _setSendMessageShortcut,
|
||||
setTheme,
|
||||
setTopicPosition,
|
||||
setWindowStyle,
|
||||
ThemeMode
|
||||
} from '@renderer/store/settings'
|
||||
@ -21,6 +22,9 @@ export function useSettings() {
|
||||
},
|
||||
setWindowStyle(windowStyle: 'transparent' | 'opaque') {
|
||||
dispatch(setWindowStyle(windowStyle))
|
||||
},
|
||||
setTopicPosition(topicPosition: 'left' | 'right') {
|
||||
dispatch(setTopicPosition(topicPosition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,5 @@
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
setShowRightSidebar,
|
||||
setShowTopics,
|
||||
toggleRightSidebar,
|
||||
toggleShowAssistants,
|
||||
toggleShowTopics
|
||||
} 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))
|
||||
}
|
||||
}
|
||||
import { setShowTopics, toggleShowAssistants, toggleShowTopics } from '@renderer/store/settings'
|
||||
|
||||
export function useShowAssistants() {
|
||||
const showAssistants = useAppSelector((state) => state.settings.showAssistants)
|
||||
|
||||
@ -207,7 +207,10 @@ const resources = {
|
||||
'theme.window.style.title': 'Window Style',
|
||||
'theme.window.style.transparent': 'Transparent Window',
|
||||
'theme.window.style.opaque': 'Opaque Window',
|
||||
'font_size.title': 'Message Font Size'
|
||||
'font_size.title': 'Message Font Size',
|
||||
'topic.position': 'Topic Position',
|
||||
'topic.position.left': 'Left',
|
||||
'topic.position.right': 'Right'
|
||||
},
|
||||
translate: {
|
||||
title: 'Translation',
|
||||
@ -454,7 +457,10 @@ const resources = {
|
||||
'theme.window.style.title': '窗口样式',
|
||||
'theme.window.style.transparent': '透明窗口',
|
||||
'theme.window.style.opaque': '不透明窗口',
|
||||
'font_size.title': '消息字体大小'
|
||||
'font_size.title': '消息字体大小',
|
||||
'topic.position': '话题位置',
|
||||
'topic.position.left': '左侧',
|
||||
'topic.position.right': '右侧'
|
||||
},
|
||||
translate: {
|
||||
title: '翻译',
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useShowRightSidebar, useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Flex } from 'antd'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Inputbar from './Inputbar/Inputbar'
|
||||
@ -17,23 +18,21 @@ interface Props {
|
||||
|
||||
const Chat: FC<Props> = (props) => {
|
||||
const { assistant } = useAssistant(props.assistant.id)
|
||||
const [showSetting, setShowSetting] = useState(false)
|
||||
const { rightSidebarShown } = useShowRightSidebar()
|
||||
const { showTopics } = useShowTopics()
|
||||
|
||||
useEffect(() => {
|
||||
!rightSidebarShown && showSetting && setShowSetting(false)
|
||||
}, [rightSidebarShown, showSetting])
|
||||
const { topicPosition } = useSettings()
|
||||
|
||||
return (
|
||||
<Container id="chat">
|
||||
{showTopics && (
|
||||
{showTopics && topicPosition === 'left' && (
|
||||
<Topics assistant={assistant} activeTopic={props.activeTopic} setActiveTopic={props.setActiveTopic} />
|
||||
)}
|
||||
<Main vertical flex={1} justify="space-between">
|
||||
<Messages assistant={assistant} topic={props.activeTopic} setActiveTopic={props.setActiveTopic} />
|
||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} />
|
||||
</Main>
|
||||
{showTopics && topicPosition === 'right' && (
|
||||
<Topics assistant={assistant} activeTopic={props.activeTopic} setActiveTopic={props.setActiveTopic} />
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingP
|
||||
import { isMac, isWindows } from '@renderer/config/constant'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { getDefaultTopic } from '@renderer/services/assistant'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
@ -27,8 +28,9 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiv
|
||||
const { assistant, addTopic } = useAssistant(activeAssistant.id)
|
||||
const { t } = useTranslation()
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { showTopics } = useShowTopics()
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
const { topicPosition } = useSettings()
|
||||
|
||||
const onCreateAssistant = async () => {
|
||||
const assistant = await AddAssistantPopup.show()
|
||||
@ -53,7 +55,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiv
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
{showTopics && (
|
||||
{showTopics && topicPosition === 'left' && (
|
||||
<NavbarCenter
|
||||
style={{
|
||||
paddingLeft: isMac && !showAssistants ? 16 : 8,
|
||||
@ -80,7 +82,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiv
|
||||
)}
|
||||
<NavbarRight style={{ justifyContent: 'space-between', paddingRight: isWindows ? 130 : 12, flex: 1 }}>
|
||||
<HStack alignItems="center">
|
||||
{!showAssistants && !showTopics && (
|
||||
{!showAssistants && (topicPosition === 'left' ? !showTopics : true) && (
|
||||
<NewButton
|
||||
onClick={() => toggleShowAssistants()}
|
||||
style={{ marginRight: isMac ? 8 : 25, marginLeft: isMac ? 8 : 0 }}>
|
||||
@ -102,6 +104,11 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiv
|
||||
checked={theme === 'dark'}
|
||||
onChange={toggleTheme}
|
||||
/>
|
||||
{topicPosition === 'right' && (
|
||||
<NewButton onClick={toggleShowTopics}>
|
||||
<i className={`iconfont icon-sidebar-${showTopics ? 'left' : 'right'}`} />
|
||||
</NewButton>
|
||||
)}
|
||||
</HStack>
|
||||
</NavbarRight>
|
||||
</Navbar>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Segmented } from 'antd'
|
||||
@ -18,7 +18,7 @@ interface Props {
|
||||
|
||||
const RightSidebar: FC<Props> = (props) => {
|
||||
const [tab, setTab] = useState<'topic' | 'settings'>('topic')
|
||||
const { rightSidebarShown, showRightSidebar, hideRightSidebar } = useShowRightSidebar()
|
||||
const { showTopics, setShowTopics } = useShowTopics()
|
||||
const { t } = useTranslation()
|
||||
const isTopicTab = tab === 'topic'
|
||||
const isSettingsTab = tab === 'settings'
|
||||
@ -26,31 +26,31 @@ const RightSidebar: FC<Props> = (props) => {
|
||||
useEffect(() => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
||||
if (rightSidebarShown && isTopicTab) {
|
||||
return hideRightSidebar()
|
||||
if (showTopics && isTopicTab) {
|
||||
return setShowTopics(false)
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
if (showTopics) {
|
||||
return setTab('topic')
|
||||
}
|
||||
showRightSidebar()
|
||||
setShowTopics(true)
|
||||
setTab('topic')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
|
||||
if (rightSidebarShown && isSettingsTab) {
|
||||
return hideRightSidebar()
|
||||
if (showTopics && isSettingsTab) {
|
||||
return setShowTopics(false)
|
||||
}
|
||||
if (rightSidebarShown) {
|
||||
if (showTopics) {
|
||||
return setTab('settings')
|
||||
}
|
||||
showRightSidebar()
|
||||
setShowTopics(true)
|
||||
setTab('settings')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => setTab('topic'))
|
||||
]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
}, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar])
|
||||
}, [isSettingsTab, isTopicTab, showTopics, setShowTopics])
|
||||
|
||||
if (!rightSidebarShown) {
|
||||
if (!showTopics) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import { DeleteOutlined, EditOutlined, OpenAIOutlined } from '@ant-design/icons'
|
||||
import DragableList from '@renderer/components/DragableList'
|
||||
import PromptPopup from '@renderer/components/Popups/PromptPopup'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { fetchMessagesSummary } from '@renderer/services/api'
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
@ -21,6 +22,9 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
|
||||
const { t } = useTranslation()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
const { topicPosition } = useSettings()
|
||||
|
||||
const borderStyle = '0.5px solid var(--color-border)'
|
||||
|
||||
const getTopicMenuItems = useCallback(
|
||||
(topic: Topic) => {
|
||||
@ -88,17 +92,19 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
)
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Container style={topicPosition === 'left' ? { borderRight: borderStyle } : { borderLeft: borderStyle }}>
|
||||
<DragableList list={assistant.topics} onUpdate={updateTopics}>
|
||||
{(topic) => (
|
||||
{(topic) => {
|
||||
const isActive = topic.id === activeTopic?.id
|
||||
const activeClass = topicPosition === 'left' ? 'active-left' : 'active-right'
|
||||
return (
|
||||
<Dropdown menu={{ items: getTopicMenuItems(topic) }} trigger={['contextMenu']} key={topic.id}>
|
||||
<TopicListItem
|
||||
className={topic.id === activeTopic?.id ? 'active' : ''}
|
||||
onClick={() => onSwitchTopic(topic)}>
|
||||
<TopicListItem className={isActive ? activeClass : ''} onClick={() => onSwitchTopic(topic)}>
|
||||
{topic.name}
|
||||
</TopicListItem>
|
||||
</Dropdown>
|
||||
)}
|
||||
)
|
||||
}}
|
||||
</DragableList>
|
||||
</Container>
|
||||
)
|
||||
@ -112,6 +118,7 @@ const Container = styled.div`
|
||||
min-width: var(--topic-list-width);
|
||||
max-width: var(--topic-list-width);
|
||||
border-right: 0.5px solid var(--color-border);
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
overflow-y: scroll;
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
`
|
||||
@ -129,11 +136,15 @@ const TopicListItem = styled.div`
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
&.active {
|
||||
&.active-left {
|
||||
background-color: var(--color-primary);
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
&.active-right {
|
||||
background-color: var(--color-background-mute);
|
||||
font-weight: 500;
|
||||
}
|
||||
`
|
||||
|
||||
export default Topics
|
||||
|
||||
@ -14,7 +14,17 @@ import { useTranslation } from 'react-i18next'
|
||||
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from '.'
|
||||
|
||||
const GeneralSettings: FC = () => {
|
||||
const { language, proxyUrl: storeProxyUrl, userName, theme, windowStyle, setTheme, setWindowStyle } = useSettings()
|
||||
const {
|
||||
language,
|
||||
proxyUrl: storeProxyUrl,
|
||||
userName,
|
||||
theme,
|
||||
windowStyle,
|
||||
topicPosition,
|
||||
setTheme,
|
||||
setWindowStyle,
|
||||
setTopicPosition
|
||||
} = useSettings()
|
||||
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
|
||||
const dispatch = useAppDispatch()
|
||||
const { t } = useTranslation()
|
||||
@ -79,6 +89,19 @@ const GeneralSettings: FC = () => {
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingDivider />
|
||||
<SettingRow>
|
||||
<SettingRowTitle>{t('settings.topic.position')}</SettingRowTitle>
|
||||
<Select
|
||||
defaultValue={topicPosition || 'right'}
|
||||
style={{ width: 180 }}
|
||||
onChange={setTopicPosition}
|
||||
options={[
|
||||
{ value: 'left', label: t('settings.topic.position.left') },
|
||||
{ value: 'right', label: t('settings.topic.position.right') }
|
||||
]}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingDivider />
|
||||
<SettingRow>
|
||||
<SettingRowTitle>{t('settings.general.user_name')}</SettingRowTitle>
|
||||
<Input
|
||||
|
||||
@ -18,6 +18,8 @@ export function getDefaultAssistant(): Assistant {
|
||||
export function getDefaultTopic(): Topic {
|
||||
return {
|
||||
id: uuid(),
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
name: i18n.t('chat.default.topic.name'),
|
||||
messages: []
|
||||
}
|
||||
|
||||
@ -393,6 +393,10 @@ const migrateConfig = {
|
||||
updatedAt: new Date().toISOString()
|
||||
}))
|
||||
}))
|
||||
},
|
||||
settings: {
|
||||
...state.settings,
|
||||
topicPosition: 'right'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ export enum ThemeMode {
|
||||
}
|
||||
|
||||
export interface SettingsState {
|
||||
showRightSidebar: boolean
|
||||
showAssistants: boolean
|
||||
showTopics: boolean
|
||||
sendMessageShortcut: SendMessageShortcut
|
||||
@ -22,10 +21,10 @@ export interface SettingsState {
|
||||
theme: ThemeMode
|
||||
windowStyle: 'transparent' | 'opaque'
|
||||
fontSize: number
|
||||
topicPosition: 'left' | 'right'
|
||||
}
|
||||
|
||||
const initialState: SettingsState = {
|
||||
showRightSidebar: true,
|
||||
showAssistants: true,
|
||||
showTopics: true,
|
||||
sendMessageShortcut: 'Enter',
|
||||
@ -37,19 +36,14 @@ const initialState: SettingsState = {
|
||||
showInputEstimatedTokens: false,
|
||||
theme: ThemeMode.light,
|
||||
windowStyle: 'opaque',
|
||||
fontSize: 14
|
||||
fontSize: 14,
|
||||
topicPosition: 'right'
|
||||
}
|
||||
|
||||
const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
reducers: {
|
||||
toggleRightSidebar: (state) => {
|
||||
state.showRightSidebar = !state.showRightSidebar
|
||||
},
|
||||
setShowRightSidebar: (state, action: PayloadAction<boolean>) => {
|
||||
state.showRightSidebar = action.payload
|
||||
},
|
||||
setShowAssistants: (state, action: PayloadAction<boolean>) => {
|
||||
state.showAssistants = action.payload
|
||||
},
|
||||
@ -92,13 +86,14 @@ const settingsSlice = createSlice({
|
||||
setWindowStyle: (state, action: PayloadAction<'transparent' | 'opaque'>) => {
|
||||
state.windowStyle = action.payload
|
||||
console.log(state.windowStyle)
|
||||
},
|
||||
setTopicPosition: (state, action: PayloadAction<'left' | 'right'>) => {
|
||||
state.topicPosition = action.payload
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const {
|
||||
setShowRightSidebar,
|
||||
toggleRightSidebar,
|
||||
setShowAssistants,
|
||||
toggleShowAssistants,
|
||||
setShowTopics,
|
||||
@ -112,7 +107,8 @@ export const {
|
||||
setShowInputEstimatedTokens,
|
||||
setTheme,
|
||||
setFontSize,
|
||||
setWindowStyle
|
||||
setWindowStyle,
|
||||
setTopicPosition
|
||||
} = settingsSlice.actions
|
||||
|
||||
export default settingsSlice.reducer
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user