feat: Enhanced UI/UX with design updates, i18n, and feature enhancements.
- Updated design styles for segmented tabs and size adjustments for assistive elements. - Added internationalization translations for English and Chinese. - Removed unused import and functionality for switching topics sidebar. - Added functionality to hide or show the right sidebar in the Chat page. - Renamed Assistants component to RightSidebar. - Improved functionality for showing and toggling topics and settings in the input bar. - Removed unused imports and refactored Navbar component layout. - Updated existing right sidebar functionality to allow for custom position and show topic settings. - Removed inline styles for width from Settings component Container styles. - Added new features for managing topics in the home page, including drag and drop functionality, a "show all" button for viewing more topics, and improved handling of large topic lists.
This commit is contained in:
parent
9a502b5e47
commit
200d78a140
@ -48,8 +48,8 @@
|
||||
--status-bar-height: 40px;
|
||||
--input-bar-height: 85px;
|
||||
|
||||
--assistants-width: 240px;
|
||||
--topic-list-width: 270px;
|
||||
--assistants-width: 280px;
|
||||
--topic-list-width: 280px;
|
||||
--settings-width: var(--assistants-width);
|
||||
}
|
||||
|
||||
@ -208,3 +208,23 @@ body,
|
||||
.ant-drawer-header {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.segmented-tab {
|
||||
.ant-segmented-item-label {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 13px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
.anticon-setting {
|
||||
font-size: 12px;
|
||||
}
|
||||
.ant-segmented-item-icon + * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import systemAgents from '@renderer/config/agents.json'
|
||||
import { useAgents } from '@renderer/hooks/useAgents'
|
||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { covertAgentToAssistant } from '@renderer/services/assistant'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Agent, Assistant } from '@renderer/types'
|
||||
import { Input, Modal, Tag } from 'antd'
|
||||
import { useMemo, useState } from 'react'
|
||||
@ -50,6 +51,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
const assistant = covertAgentToAssistant(agent)
|
||||
|
||||
addAssistant(assistant)
|
||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0)
|
||||
resolve(assistant)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
@ -37,7 +37,9 @@ const resources = {
|
||||
add: 'Add',
|
||||
added: 'Added',
|
||||
manage: 'Manage',
|
||||
select_model: 'Select Model'
|
||||
select_model: 'Select Model',
|
||||
'show.all': 'Show All',
|
||||
collapse: 'Collapse'
|
||||
},
|
||||
message: {
|
||||
copied: 'Copied!',
|
||||
@ -288,7 +290,9 @@ const resources = {
|
||||
add: '添加',
|
||||
added: '已添加',
|
||||
manage: '管理',
|
||||
select_model: '选择模型'
|
||||
select_model: '选择模型',
|
||||
'show.all': '显示全部',
|
||||
collapse: '收起'
|
||||
},
|
||||
message: {
|
||||
copied: '已复制',
|
||||
|
||||
@ -3,7 +3,6 @@ import DragableList from '@renderer/components/DragableList'
|
||||
import CopyIcon from '@renderer/components/Icons/CopyIcon'
|
||||
import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingPopup'
|
||||
import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { getDefaultTopic, syncAsistantToAgent } from '@renderer/services/assistant'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
@ -26,7 +25,6 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
const { updateAssistant, removeAllTopics } = useAssistant(activeAssistant.id)
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const onDelete = useCallback(
|
||||
@ -100,7 +98,6 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
})
|
||||
}
|
||||
|
||||
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
|
||||
setActiveAssistant(assistant)
|
||||
},
|
||||
[generating, setActiveAssistant, t]
|
||||
@ -116,8 +113,8 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
<AssistantItem onClick={() => onSwitchAssistant(assistant)} className={isCurrent ? 'active' : ''}>
|
||||
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
|
||||
<ArrowRightButton
|
||||
className={`arrow-button ${isCurrent && showTopics ? 'active' : ''}`}
|
||||
onClick={() => isCurrent && toggleShowTopics()}>
|
||||
className={`arrow-button ${isCurrent ? 'active' : ''}`}
|
||||
onClick={() => EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)}>
|
||||
<i className="iconfont icon-gridlines" />
|
||||
</ArrowRightButton>
|
||||
{false && <TopicCount className="topics-count">{assistant.topics.length}</TopicCount>}
|
||||
@ -133,9 +130,6 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: var(--assistants-width);
|
||||
max-width: var(--assistants-width);
|
||||
border-right: 0.5px solid var(--color-border);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
overflow-y: auto;
|
||||
padding-top: 10px;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Flex } from 'antd'
|
||||
import { FC } from 'react'
|
||||
@ -13,23 +14,28 @@ interface Props {
|
||||
assistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const Chat: FC<Props> = (props) => {
|
||||
const { assistant } = useAssistant(props.assistant.id)
|
||||
const { topicPosition } = useSettings()
|
||||
const { showTopics } = useShowTopics()
|
||||
|
||||
return (
|
||||
<Container id="chat">
|
||||
{topicPosition === 'left' && (
|
||||
<RightSidebar 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>
|
||||
{topicPosition === 'right' && (
|
||||
<RightSidebar assistant={assistant} activeTopic={props.activeTopic} setActiveTopic={props.setActiveTopic} />
|
||||
{topicPosition === 'right' && showTopics && (
|
||||
<RightSidebar
|
||||
activeAssistant={assistant}
|
||||
activeTopic={props.activeTopic}
|
||||
setActiveAssistant={props.setActiveAssistant}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
position="right"
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
|
||||
@ -1,54 +1,48 @@
|
||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { useShowAssistants } from '@renderer/hooks/useStore'
|
||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { FC, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Assistants from './Assistants'
|
||||
import Chat from './Chat'
|
||||
import Navbar from './Navbar'
|
||||
import RightSidebar from './RightSidebar'
|
||||
|
||||
let _activeAssistant: Assistant
|
||||
|
||||
const HomePage: FC = () => {
|
||||
const { assistants, addAssistant } = useAssistants()
|
||||
const { assistants } = useAssistants()
|
||||
const [activeAssistant, setActiveAssistant] = useState(_activeAssistant || assistants[0])
|
||||
const { showAssistants } = useShowAssistants()
|
||||
const { defaultAssistant } = useDefaultAssistant()
|
||||
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(activeAssistant)
|
||||
|
||||
_activeAssistant = activeAssistant
|
||||
|
||||
const onCreateDefaultAssistant = () => {
|
||||
const assistant = { ...defaultAssistant, id: uuid() }
|
||||
addAssistant(assistant)
|
||||
setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
const onSetActiveTopic = (topic: Topic) => {
|
||||
setActiveTopic(topic)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Navbar
|
||||
activeAssistant={activeAssistant}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
activeTopic={activeTopic}
|
||||
setActiveTopic={onSetActiveTopic}
|
||||
/>
|
||||
<Navbar activeAssistant={activeAssistant} setActiveAssistant={setActiveAssistant} activeTopic={activeTopic} />
|
||||
<ContentContainer>
|
||||
{showAssistants && (
|
||||
<Assistants
|
||||
<RightSidebar
|
||||
activeAssistant={activeAssistant}
|
||||
activeTopic={activeTopic}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
onCreateAssistant={onCreateDefaultAssistant}
|
||||
setActiveTopic={setActiveTopic}
|
||||
position="left"
|
||||
/>
|
||||
)}
|
||||
<Chat assistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={onSetActiveTopic} />
|
||||
<Chat
|
||||
assistant={activeAssistant}
|
||||
activeTopic={activeTopic}
|
||||
setActiveTopic={onSetActiveTopic}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
/>
|
||||
</ContentContainer>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
} from '@ant-design/icons'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { getDefaultTopic } from '@renderer/services/assistant'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { estimateInputTokenCount } from '@renderer/services/messages'
|
||||
@ -48,6 +49,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
const [files, setFiles] = useState<File[]>([])
|
||||
const { t } = useTranslation()
|
||||
const containerRef = useRef(null)
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
|
||||
_text = text
|
||||
|
||||
@ -235,12 +237,22 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
</Popconfirm>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.topics')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR)}>
|
||||
<ToolbarButton
|
||||
type="text"
|
||||
onClick={() => {
|
||||
!showTopics && toggleShowTopics()
|
||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR), 0)
|
||||
}}>
|
||||
<HistoryOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title={t('chat.input.settings')} arrow>
|
||||
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS)}>
|
||||
<ToolbarButton
|
||||
type="text"
|
||||
onClick={() => {
|
||||
!showTopics && toggleShowTopics()
|
||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS), 0)
|
||||
}}>
|
||||
<ControlOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { FormOutlined } from '@ant-design/icons'
|
||||
import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
|
||||
import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingPopup'
|
||||
@ -8,11 +7,9 @@ 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'
|
||||
import { Switch } from 'antd'
|
||||
import { FC, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
@ -21,32 +18,30 @@ interface Props {
|
||||
activeAssistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiveTopic }) => {
|
||||
const { assistant, addTopic } = useAssistant(activeAssistant.id)
|
||||
const { t } = useTranslation()
|
||||
const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant }) => {
|
||||
const { assistant } = useAssistant(activeAssistant.id)
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
const { topicPosition } = useSettings()
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
|
||||
const onCreateAssistant = async () => {
|
||||
const assistant = await AddAssistantPopup.show()
|
||||
assistant && setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
const addNewTopic = useCallback(() => {
|
||||
const topic = getDefaultTopic()
|
||||
addTopic(topic)
|
||||
setActiveTopic(topic)
|
||||
}, [addTopic, setActiveTopic])
|
||||
|
||||
return (
|
||||
<Navbar>
|
||||
{showAssistants && (
|
||||
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: '0 8px' }}>
|
||||
<NavbarLeft
|
||||
style={{
|
||||
justifyContent: 'space-between',
|
||||
borderRight: 'none',
|
||||
padding: '0 8px',
|
||||
width: topicPosition === 'left' ? '300px' : 'var(--assistants-width)'
|
||||
}}>
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 8 : 0 }}>
|
||||
<i className="iconfont icon-hide-sidebar" />
|
||||
</NewButton>
|
||||
@ -55,34 +50,9 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, setActiv
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
{showTopics && topicPosition === 'left' && (
|
||||
<NavbarCenter
|
||||
style={{
|
||||
paddingLeft: isMac && !showAssistants ? 16 : 8,
|
||||
paddingRight: 8,
|
||||
maxWidth: 'var(--topic-list-width)',
|
||||
justifyContent: 'space-between'
|
||||
}}>
|
||||
<HStack alignItems="center">
|
||||
{!showAssistants && (
|
||||
<NewButton onClick={toggleShowAssistants} style={{ marginRight: isMac ? 8 : 25 }}>
|
||||
<i className="iconfont icon-show-sidebar" />
|
||||
</NewButton>
|
||||
)}
|
||||
{showAssistants && (
|
||||
<TitleText>
|
||||
{t('chat.topics.title')} ({assistant.topics.length})
|
||||
</TitleText>
|
||||
)}
|
||||
</HStack>
|
||||
<NewButton onClick={addNewTopic}>
|
||||
<FormOutlined />
|
||||
</NewButton>
|
||||
</NavbarCenter>
|
||||
)}
|
||||
<NavbarRight style={{ justifyContent: 'space-between', paddingRight: isWindows ? 140 : 12, flex: 1 }}>
|
||||
<HStack alignItems="center">
|
||||
{!showAssistants && (topicPosition === 'left' ? !showTopics : true) && (
|
||||
{!showAssistants && (
|
||||
<NewButton
|
||||
onClick={() => toggleShowAssistants()}
|
||||
style={{ marginRight: isMac ? 8 : 25, marginLeft: isMac ? 4 : 0 }}>
|
||||
|
||||
@ -1,78 +1,108 @@
|
||||
import { BarsOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Segmented } from 'antd'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Segmented, SegmentedProps } from 'antd'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Assistants from './Assistants'
|
||||
import Settings from './Settings'
|
||||
import Topics from './Topics'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
activeAssistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
position: 'left' | 'right'
|
||||
}
|
||||
|
||||
const RightSidebar: FC<Props> = (props) => {
|
||||
const [tab, setTab] = useState<'topic' | 'settings'>('topic')
|
||||
const { showTopics, setShowTopics } = useShowTopics()
|
||||
const RightSidebar: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssistant, setActiveTopic, position }) => {
|
||||
const { addAssistant } = useAssistants()
|
||||
const [tab, setTab] = useState<'assistants' | 'topic' | 'settings'>(position === 'left' ? 'assistants' : 'topic')
|
||||
const { topicPosition } = useSettings()
|
||||
const { defaultAssistant } = useDefaultAssistant()
|
||||
const { toggleShowTopics } = useShowTopics()
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isTopicTab = tab === 'topic'
|
||||
const isSettingsTab = tab === 'settings'
|
||||
const borderStyle = '0.5px solid var(--color-border)'
|
||||
const border = position === 'left' ? { borderRight: borderStyle } : { borderLeft: borderStyle }
|
||||
|
||||
const showTab = !(position === 'left' && topicPosition === 'right')
|
||||
const assistantTab = {
|
||||
label: t('common.assistant'),
|
||||
value: 'assistants',
|
||||
icon: <i className="iconfont icon-business-smart-assistant" />
|
||||
}
|
||||
|
||||
const onCreateDefaultAssistant = () => {
|
||||
const assistant = { ...defaultAssistant, id: uuid() }
|
||||
addAssistant(assistant)
|
||||
setActiveAssistant(assistant)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_ASSISTANTS, (): any => {
|
||||
showTab && setTab('assistants')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
||||
if (showTopics && isTopicTab) {
|
||||
return setShowTopics(false)
|
||||
}
|
||||
if (showTopics) {
|
||||
return setTab('topic')
|
||||
}
|
||||
setShowTopics(true)
|
||||
setTab('topic')
|
||||
showTab && setTab('topic')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
|
||||
if (showTopics && isSettingsTab) {
|
||||
return setShowTopics(false)
|
||||
}
|
||||
if (showTopics) {
|
||||
return setTab('settings')
|
||||
}
|
||||
setShowTopics(true)
|
||||
setTab('settings')
|
||||
showTab && setTab('settings')
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => setTab('topic'))
|
||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => {
|
||||
showTab && setTab('topic')
|
||||
if (position === 'left' && topicPosition === 'right') {
|
||||
toggleShowTopics()
|
||||
}
|
||||
})
|
||||
]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
}, [isSettingsTab, isTopicTab, showTopics, setShowTopics])
|
||||
|
||||
if (!showTopics) {
|
||||
return null
|
||||
}
|
||||
}, [position, showTab, tab, toggleShowTopics, topicPosition])
|
||||
|
||||
return (
|
||||
<Container style={topicPosition === 'left' ? { borderRight: borderStyle } : { borderLeft: borderStyle }}>
|
||||
<Container style={{ ...border, width: topicPosition === 'left' ? '300px' : 'var(--assistants-width)' }}>
|
||||
{showTab && (
|
||||
<Segmented
|
||||
value={tab}
|
||||
style={{ borderRadius: 0, padding: '10px', gap: 5, borderBottom: '0.5px solid var(--color-border)' }}
|
||||
options={[
|
||||
className="segmented-tab"
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
padding: '10px',
|
||||
gap: 5,
|
||||
borderBottom: '0.5px solid var(--color-border)'
|
||||
}}
|
||||
options={
|
||||
[
|
||||
position === 'left' && topicPosition === 'left' ? assistantTab : undefined,
|
||||
{ label: t('common.topics'), value: 'topic', icon: <BarsOutlined /> },
|
||||
{ label: t('settings.title'), value: 'settings', icon: <SettingOutlined /> }
|
||||
]}
|
||||
block
|
||||
].filter(Boolean) as SegmentedProps['options']
|
||||
}
|
||||
onChange={(value) => setTab(value as 'topic' | 'settings')}
|
||||
block
|
||||
/>
|
||||
)}
|
||||
<TabContent>
|
||||
{tab === 'topic' && <Topics {...props} />}
|
||||
{tab === 'settings' && <Settings assistant={props.assistant} />}
|
||||
{tab === 'assistants' && (
|
||||
<Assistants
|
||||
activeAssistant={activeAssistant}
|
||||
setActiveAssistant={setActiveAssistant}
|
||||
onCreateAssistant={onCreateDefaultAssistant}
|
||||
/>
|
||||
)}
|
||||
{tab === 'topic' && (
|
||||
<Topics assistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
)}
|
||||
{tab === 'settings' && <Settings assistant={activeAssistant} />}
|
||||
</TabContent>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@ -236,8 +236,6 @@ const Container = styled.div`
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding-bottom: 10px;
|
||||
min-width: var(--topic-list-width);
|
||||
max-width: var(--topic-list-width);
|
||||
padding: 10px 15px;
|
||||
`
|
||||
|
||||
|
||||
@ -6,8 +6,9 @@ import { fetchMessagesSummary } from '@renderer/services/api'
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Dropdown, MenuProps } from 'antd'
|
||||
import { FC, useCallback } from 'react'
|
||||
import { Button, Dropdown, MenuProps } from 'antd'
|
||||
import { take } from 'lodash'
|
||||
import { FC, useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
@ -19,6 +20,8 @@ interface Props {
|
||||
|
||||
const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
|
||||
const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
|
||||
const [showAll, setShowAll] = useState(false)
|
||||
const [draging, setDraging] = useState(false)
|
||||
const { t } = useTranslation()
|
||||
const generating = useAppSelector((state) => state.runtime.generating)
|
||||
|
||||
@ -89,7 +92,11 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<DragableList list={assistant.topics} onUpdate={updateTopics}>
|
||||
<DragableList
|
||||
list={take(assistant.topics, showAll ? assistant.topics.length : 15)}
|
||||
onUpdate={updateTopics}
|
||||
onDragStart={() => setDraging(true)}
|
||||
onDragEnd={() => setDraging(false)}>
|
||||
{(topic) => {
|
||||
const isActive = topic.id === activeTopic?.id
|
||||
return (
|
||||
@ -101,6 +108,13 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
)
|
||||
}}
|
||||
</DragableList>
|
||||
{!draging && assistant.topics.length > 15 && (
|
||||
<Footer>
|
||||
<Button type="link" onClick={() => setShowAll(!showAll)}>
|
||||
{showAll ? t('button.collapse') : t('button.show.all')}
|
||||
</Button>
|
||||
</Footer>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@ -110,8 +124,6 @@ const Container = styled.div`
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-top: 10px;
|
||||
min-width: var(--topic-list-width);
|
||||
max-width: var(--topic-list-width);
|
||||
overflow-y: scroll;
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
`
|
||||
@ -135,4 +147,9 @@ const TopicListItem = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const Footer = styled.div`
|
||||
margin: 0 4px;
|
||||
margin-bottom: 10px;
|
||||
`
|
||||
|
||||
export default Topics
|
||||
|
||||
@ -12,6 +12,7 @@ export const EVENT_NAMES = {
|
||||
REGENERATE_MESSAGE: 'REGENERATE_MESSAGE',
|
||||
CHAT_COMPLETION_PAUSED: 'CHAT_COMPLETION_PAUSED',
|
||||
ESTIMATED_TOKEN_COUNT: 'ESTIMATED_TOKEN_COUNT',
|
||||
SHOW_ASSISTANTS: 'SHOW_ASSISTANTS',
|
||||
SHOW_CHAT_SETTINGS: 'SHOW_CHAT_SETTINGS',
|
||||
SHOW_TOPIC_SIDEBAR: 'SHOW_TOPIC_SIDEBAR',
|
||||
SWITCH_TOPIC_SIDEBAR: 'SWITCH_TOPIC_SIDEBAR',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user