mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 06:30:10 +08:00
fix: adjust Navbar and Chat components for better layout and responsiveness
- Updated Navbar styles to improve margin handling for macOS. - Refactored Chat component to streamline layout and enhance responsiveness, including adjustments to main height calculations and navbar integration. - Cleaned up commented code and improved the structure of the ChatNavbar for better clarity and maintainability. - Enhanced styling in various components for consistent appearance and behavior across different screen sizes.
This commit is contained in:
parent
8470e252d6
commit
d4b1db0407
@ -67,14 +67,14 @@ const NavbarContainer = styled.div<{ $isFullScreen: boolean }>`
|
||||
flex-direction: row;
|
||||
min-height: ${isMac ? 'env(titlebar-area-height)' : 'var(--navbar-height)'};
|
||||
max-height: var(--navbar-height);
|
||||
margin-left: ${isMac ? 'calc(var(--sidebar-width) * -1)' : 0};
|
||||
margin-left: ${isMac ? 'calc(var(--sidebar-width) * -1 + 2px)' : 0};
|
||||
padding-left: ${({ $isFullScreen }) =>
|
||||
isMac ? ($isFullScreen ? 'var(--sidebar-width)' : 'env(titlebar-area-x)') : 0};
|
||||
-webkit-app-region: drag;
|
||||
`
|
||||
|
||||
const NavbarLeftContainer = styled.div`
|
||||
min-width: ${isMac ? 'calc(var(--assistants-width) - 20px)' : 'var(--assistants-width)'};
|
||||
/* min-width: ${isMac ? 'calc(var(--assistants-width) - 20px)' : 'var(--assistants-width)'}; */
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -140,9 +140,7 @@ const Chat: FC<Props> = (props) => {
|
||||
firstUpdateOrNoFirstUpdateHandler()
|
||||
}
|
||||
|
||||
const mainHeight = isTopNavbar
|
||||
? 'calc(100vh - var(--navbar-height) - var(--navbar-height) - 12px)'
|
||||
: 'calc(100vh - var(--navbar-height))'
|
||||
const mainHeight = isTopNavbar ? 'calc(100vh - var(--navbar-height) - 6px)' : 'calc(100vh - var(--navbar-height))'
|
||||
|
||||
const SessionMessages = useMemo(() => {
|
||||
if (activeAgentId === null) {
|
||||
@ -192,66 +190,84 @@ const Chat: FC<Props> = (props) => {
|
||||
</div>
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Container id="chat" className={classNames([messageStyle, { 'multi-select-mode': isMultiSelectMode }])}>
|
||||
{isTopNavbar && (
|
||||
<ChatNavbar
|
||||
activeAssistant={props.assistant}
|
||||
activeTopic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
setActiveAssistant={props.setActiveAssistant}
|
||||
position="left"
|
||||
/>
|
||||
)}
|
||||
<HStack>
|
||||
<Main
|
||||
ref={mainRef}
|
||||
id="chat-main"
|
||||
vertical
|
||||
flex={1}
|
||||
justify="space-between"
|
||||
style={{ maxWidth: chatMaxWidth, height: mainHeight }}>
|
||||
<QuickPanelProvider>
|
||||
{activeTopicOrSession === 'topic' && (
|
||||
<>
|
||||
<Messages
|
||||
key={props.activeTopic.id}
|
||||
assistant={assistant}
|
||||
topic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
onComponentUpdate={messagesComponentUpdateHandler}
|
||||
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
||||
/>
|
||||
<ContentSearch
|
||||
ref={contentSearchRef}
|
||||
searchTarget={mainRef as React.RefObject<HTMLElement>}
|
||||
filter={contentSearchFilter}
|
||||
includeUser={filterIncludeUser}
|
||||
onIncludeUserChange={userOutlinedItemClickHandler}
|
||||
/>
|
||||
{messageNavigation === 'buttons' && <ChatNavigation containerId="messages" />}
|
||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
||||
</>
|
||||
)}
|
||||
{activeTopicOrSession === 'session' && !activeAgentId && <AgentInvalid />}
|
||||
{activeTopicOrSession === 'session' && activeAgentId && !activeSessionId && <SessionInvalid />}
|
||||
{activeTopicOrSession === 'session' && activeAgentId && activeSessionId && (
|
||||
<>
|
||||
<SessionMessages />
|
||||
<SessionInputBar />
|
||||
</>
|
||||
)}
|
||||
{isMultiSelectMode && <MultiSelectActionPopup topic={props.activeTopic} />}
|
||||
</QuickPanelProvider>
|
||||
</Main>
|
||||
<motion.div
|
||||
animate={{
|
||||
marginRight: topicPosition === 'right' && showTopics ? 'var(--assistants-width)' : 0
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
style={{ flex: 1, display: 'flex', minWidth: 0 }}>
|
||||
<Main
|
||||
ref={mainRef}
|
||||
id="chat-main"
|
||||
vertical
|
||||
flex={1}
|
||||
justify="space-between"
|
||||
style={{ maxWidth: chatMaxWidth, height: mainHeight }}>
|
||||
<QuickPanelProvider>
|
||||
<ChatNavbar
|
||||
activeAssistant={props.assistant}
|
||||
activeTopic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
setActiveAssistant={props.setActiveAssistant}
|
||||
position="left"
|
||||
/>
|
||||
<div
|
||||
className="flex flex-1 flex-col justify-between"
|
||||
style={{ height: `calc(${mainHeight} - var(--navbar-height))` }}>
|
||||
{activeTopicOrSession === 'topic' && (
|
||||
<>
|
||||
<Messages
|
||||
key={props.activeTopic.id}
|
||||
assistant={assistant}
|
||||
topic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
onComponentUpdate={messagesComponentUpdateHandler}
|
||||
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
||||
/>
|
||||
<ContentSearch
|
||||
ref={contentSearchRef}
|
||||
searchTarget={mainRef as React.RefObject<HTMLElement>}
|
||||
filter={contentSearchFilter}
|
||||
includeUser={filterIncludeUser}
|
||||
onIncludeUserChange={userOutlinedItemClickHandler}
|
||||
/>
|
||||
{messageNavigation === 'buttons' && <ChatNavigation containerId="messages" />}
|
||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
||||
</>
|
||||
)}
|
||||
{activeTopicOrSession === 'session' && !activeAgentId && <AgentInvalid />}
|
||||
{activeTopicOrSession === 'session' && activeAgentId && !activeSessionId && <SessionInvalid />}
|
||||
{activeTopicOrSession === 'session' && activeAgentId && activeSessionId && (
|
||||
<>
|
||||
<SessionMessages />
|
||||
<SessionInputBar />
|
||||
</>
|
||||
)}
|
||||
{isMultiSelectMode && <MultiSelectActionPopup topic={props.activeTopic} />}
|
||||
</div>
|
||||
</QuickPanelProvider>
|
||||
</Main>
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false}>
|
||||
{topicPosition === 'right' && showTopics && (
|
||||
<motion.div
|
||||
initial={{ width: 0, opacity: 0 }}
|
||||
animate={{ width: 'auto', opacity: 1 }}
|
||||
exit={{ width: 0, opacity: 0 }}
|
||||
key="right-tabs"
|
||||
initial={{ x: 'var(--assistants-width)' }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: 'var(--assistants-width)' }}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
style={{ overflow: 'hidden' }}>
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: isTopNavbar ? 0 : 'calc(var(--navbar-height) + 1px)',
|
||||
width: 'var(--assistants-width)',
|
||||
height: '100%',
|
||||
zIndex: 10
|
||||
}}>
|
||||
<Tabs
|
||||
activeAssistant={assistant}
|
||||
activeTopic={props.activeTopic}
|
||||
@ -269,13 +285,14 @@ const Chat: FC<Props> = (props) => {
|
||||
|
||||
export const useChatMaxWidth = () => {
|
||||
const { showTopics, topicPosition } = useSettings()
|
||||
const { isLeftNavbar } = useNavbarPosition()
|
||||
const { isLeftNavbar, isTopNavbar } = useNavbarPosition()
|
||||
const { showAssistants } = useShowAssistants()
|
||||
const showRightTopics = showTopics && topicPosition === 'right'
|
||||
const minusAssistantsWidth = showAssistants ? '- var(--assistants-width)' : ''
|
||||
const minusRightTopicsWidth = showRightTopics ? '- var(--assistants-width)' : ''
|
||||
const minusBorderWidth = isTopNavbar ? (showTopics ? '- 12px' : '- 6px') : ''
|
||||
const sidebarWidth = isLeftNavbar ? '- var(--sidebar-width)' : ''
|
||||
return `calc(100vw ${sidebarWidth} ${minusAssistantsWidth} ${minusRightTopicsWidth})`
|
||||
return `calc(100vw ${sidebarWidth} ${minusAssistantsWidth} ${minusRightTopicsWidth} ${minusBorderWidth})`
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
|
||||
@ -3,7 +3,7 @@ import { HStack } from '@renderer/components/Layout'
|
||||
import SearchPopup from '@renderer/components/Popups/SearchPopup'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { modelGenerating } from '@renderer/hooks/useRuntime'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShortcut } from '@renderer/hooks/useShortcuts'
|
||||
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
@ -34,6 +34,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { topicPosition, narrowMode } = useSettings()
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
const { isTopNavbar } = useNavbarPosition()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useShortcut('toggle_show_assistants', toggleShowAssistants)
|
||||
@ -73,16 +74,16 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
||||
// )
|
||||
|
||||
return (
|
||||
<NavbarHeader className="home-navbar">
|
||||
<div className="flex min-w-0 flex-1 shrink items-center overflow-auto">
|
||||
{showAssistants && (
|
||||
<NavbarHeader className="home-navbar" style={{ height: 'var(--navbar-height)' }}>
|
||||
<div className="flex h-full min-w-0 flex-1 shrink items-center overflow-auto">
|
||||
{isTopNavbar && showAssistants && (
|
||||
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={0.8}>
|
||||
<NavbarIcon onClick={toggleShowAssistants}>
|
||||
<PanelLeftClose size={18} />
|
||||
</NavbarIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!showAssistants && (
|
||||
{isTopNavbar && !showAssistants && (
|
||||
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={0.8}>
|
||||
<NavbarIcon onClick={() => toggleShowAssistants()} style={{ marginRight: 8 }}>
|
||||
<PanelRightClose size={18} />
|
||||
@ -90,13 +91,13 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
||||
</Tooltip>
|
||||
)}
|
||||
<AnimatePresence initial={false}>
|
||||
{!showAssistants && (
|
||||
{!showAssistants && isTopNavbar && (
|
||||
<motion.div
|
||||
initial={{ width: 0, opacity: 0 }}
|
||||
animate={{ width: 'auto', opacity: 1 }}
|
||||
exit={{ width: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}>
|
||||
<NavbarIcon onClick={onShowAssistantsDrawer} style={{ marginRight: 8 }}>
|
||||
<NavbarIcon onClick={onShowAssistantsDrawer} style={{ marginRight: 5 }}>
|
||||
<Menu size={18} />
|
||||
</NavbarIcon>
|
||||
</motion.div>
|
||||
@ -105,25 +106,29 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
||||
<ChatNavbarContent assistant={assistant} />
|
||||
</div>
|
||||
<HStack alignItems="center" gap={8}>
|
||||
<UpdateAppButton />
|
||||
<Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}>
|
||||
<NarrowIcon onClick={handleNarrowModeToggle}>
|
||||
<i className="iconfont icon-icon-adaptive-width"></i>
|
||||
</NarrowIcon>
|
||||
</Tooltip>
|
||||
<Tooltip title={t('chat.assistant.search.placeholder')} mouseEnterDelay={0.8}>
|
||||
<NavbarIcon onClick={() => SearchPopup.show()}>
|
||||
<Search size={18} />
|
||||
</NavbarIcon>
|
||||
</Tooltip>
|
||||
{topicPosition === 'right' && !showTopics && (
|
||||
{isTopNavbar && <UpdateAppButton />}
|
||||
{isTopNavbar && (
|
||||
<Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}>
|
||||
<NarrowIcon onClick={handleNarrowModeToggle}>
|
||||
<i className="iconfont icon-icon-adaptive-width"></i>
|
||||
</NarrowIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isTopNavbar && (
|
||||
<Tooltip title={t('chat.assistant.search.placeholder')} mouseEnterDelay={0.8}>
|
||||
<NavbarIcon onClick={() => SearchPopup.show()}>
|
||||
<Search size={18} />
|
||||
</NavbarIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isTopNavbar && topicPosition === 'right' && !showTopics && (
|
||||
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={2}>
|
||||
<NavbarIcon onClick={toggleShowTopics}>
|
||||
<PanelLeftClose size={18} />
|
||||
</NavbarIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
{topicPosition === 'right' && showTopics && (
|
||||
{isTopNavbar && topicPosition === 'right' && showTopics && (
|
||||
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={2}>
|
||||
<NavbarIcon onClick={toggleShowTopics}>
|
||||
<PanelRightClose size={18} />
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import SearchPopup from '@renderer/components/Popups/SearchPopup'
|
||||
import { isLinux, isMac, isWin } from '@renderer/config/constant'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { isLinux, isWin } from '@renderer/config/constant'
|
||||
import { modelGenerating } from '@renderer/hooks/useRuntime'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useShortcut } from '@renderer/hooks/useShortcuts'
|
||||
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
|
||||
import { useChatMaxWidth } from '@renderer/pages/home/Chat'
|
||||
import ChatNavbarContent from '@renderer/pages/home/components/ChatNavbarContent'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import { setNarrowMode } from '@renderer/store/settings'
|
||||
@ -17,11 +14,10 @@ import { Tooltip } from 'antd'
|
||||
import { t } from 'i18next'
|
||||
import { Menu, PanelLeftClose, PanelRightClose, Search } from 'lucide-react'
|
||||
import { AnimatePresence, motion } from 'motion/react'
|
||||
import React, { FC } from 'react'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import AssistantsDrawer from './components/AssistantsDrawer'
|
||||
import SelectModelButton from './components/SelectModelButton'
|
||||
import UpdateAppButton from './components/UpdateAppButton'
|
||||
|
||||
interface Props {
|
||||
@ -40,11 +36,9 @@ const HeaderNavbar: FC<Props> = ({
|
||||
setActiveTopic,
|
||||
activeTopicOrSession
|
||||
}) => {
|
||||
const { assistant } = useAssistant(activeAssistant.id)
|
||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||
const { topicPosition, narrowMode } = useSettings()
|
||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||
const chatMaxWidth = useChatMaxWidth()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useShortcut('toggle_show_assistants', toggleShowAssistants)
|
||||
@ -101,7 +95,7 @@ const HeaderNavbar: FC<Props> = ({
|
||||
justifyContent: 'flex-start',
|
||||
borderRight: 'none',
|
||||
paddingLeft: 0,
|
||||
paddingRight: 10,
|
||||
paddingRight: 0,
|
||||
minWidth: 'auto'
|
||||
}}>
|
||||
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={0.8}>
|
||||
@ -123,22 +117,7 @@ const HeaderNavbar: FC<Props> = ({
|
||||
</AnimatePresence>
|
||||
</NavbarLeft>
|
||||
)}
|
||||
<NavbarCenter>
|
||||
{activeTopicOrSession === 'topic' ? (
|
||||
<HStack alignItems="center" gap={6} ml={!isMac ? 16 : 0}>
|
||||
<SelectModelButton assistant={assistant} />
|
||||
</HStack>
|
||||
) : (
|
||||
<ChatNavbarContainer
|
||||
style={{
|
||||
maxWidth: chatMaxWidth,
|
||||
marginLeft: !isMac ? 16 : 0
|
||||
}}>
|
||||
<ChatNavbarContent assistant={assistant} />
|
||||
</ChatNavbarContainer>
|
||||
)}
|
||||
</NavbarCenter>
|
||||
|
||||
<NavbarCenter></NavbarCenter>
|
||||
<NavbarRight
|
||||
style={{
|
||||
justifyContent: 'flex-end',
|
||||
@ -220,15 +199,4 @@ const NarrowIcon = styled(NavbarIcon)`
|
||||
}
|
||||
`
|
||||
|
||||
const ChatNavbarContainer: React.FC<{ children: React.ReactNode; style?: React.CSSProperties }> = ({
|
||||
children,
|
||||
style
|
||||
}) => {
|
||||
return (
|
||||
<div className="nodrag flex min-w-0 flex-1 items-center justify-start gap-1.5 overflow-hidden" style={style}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeaderNavbar
|
||||
|
||||
@ -180,7 +180,7 @@ const AssistantsTab: FC<AssistantsTabProps> = (props) => {
|
||||
const Container = styled(Scrollbar)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
padding: 12px 10px;
|
||||
`
|
||||
|
||||
export default AssistantsTab
|
||||
|
||||
@ -30,7 +30,7 @@ const SessionSettingsTab: FC<Props> = ({ session, update }) => {
|
||||
|
||||
return (
|
||||
<div className="w-[var(--assistants-width)] p-2 px-3 pt-4">
|
||||
<EssentialSettings agentBase={session} update={update} />
|
||||
<EssentialSettings agentBase={session} update={update} showModelSetting={false} />
|
||||
<AdvancedSettings agentBase={session} update={update} />
|
||||
<Divider className="my-2" />
|
||||
<Button size="sm" fullWidth onPress={onMoreSetting}>
|
||||
|
||||
@ -14,7 +14,6 @@ const SessionsTab: FC<SessionsTabProps> = () => {
|
||||
const { activeAgentId } = chat
|
||||
const { t } = useTranslation()
|
||||
const { apiServer } = useSettings()
|
||||
const { topicPosition, navbarPosition } = useSettings()
|
||||
|
||||
if (!apiServer.enabled) {
|
||||
return (
|
||||
@ -34,15 +33,7 @@ const SessionsTab: FC<SessionsTabProps> = () => {
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
initial={{ width: 0, opacity: 0 }}
|
||||
animate={{ width: 'var(--assistants-width)', opacity: 1 }}
|
||||
exit={{ width: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.5, ease: 'easeInOut' }}
|
||||
className={cn(
|
||||
'overflow-hidden',
|
||||
topicPosition === 'right' && navbarPosition === 'top' ? 'rounded-l-2xl border-t border-b border-l' : undefined
|
||||
)}>
|
||||
<motion.div className={cn('overflow-hidden', 'h-full')}>
|
||||
<Sessions agentId={activeAgentId} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
@ -44,9 +44,16 @@ const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) =
|
||||
<AgentLabel agent={agent} />
|
||||
</AgentNameWrapper>
|
||||
</AssistantNameRow>
|
||||
<MenuButton>
|
||||
{isActive ? <SessionCount>{sessions.length}</SessionCount> : <Bot size={14} className="text-primary" />}
|
||||
</MenuButton>
|
||||
{isActive && (
|
||||
<MenuButton>
|
||||
<SessionCount>{sessions.length}</SessionCount>
|
||||
</MenuButton>
|
||||
)}
|
||||
{!isActive && (
|
||||
<BotIcon>
|
||||
<Bot size={16} className="text-primary" />
|
||||
</BotIcon>
|
||||
)}
|
||||
</Container>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
@ -110,6 +117,16 @@ export const MenuButton: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ cla
|
||||
/>
|
||||
)
|
||||
|
||||
export const BotIcon: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute top-[8px] right-[12px] flex flex-row items-center justify-center rounded-full text-[14px] text-[var(--color-text)]',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
export const SessionCount: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Button, cn, Input, Tooltip } from '@heroui/react'
|
||||
import { DeleteIcon, EditIcon } from '@renderer/components/Icons'
|
||||
import { isMac } from '@renderer/config/constant'
|
||||
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
||||
@ -11,9 +10,19 @@ import { SessionLabel } from '@renderer/pages/settings/AgentSettings/shared'
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { newMessagesActions } from '@renderer/store/newMessage'
|
||||
import { AgentSessionEntity } from '@renderer/types'
|
||||
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@renderer/ui/context-menu'
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuTrigger
|
||||
} from '@renderer/ui/context-menu'
|
||||
import { classNames } from '@renderer/utils'
|
||||
import { buildAgentSessionTopicId } from '@renderer/utils/agentSession'
|
||||
import { XIcon } from 'lucide-react'
|
||||
import { Tooltip } from 'antd'
|
||||
import { MenuIcon, XIcon } from 'lucide-react'
|
||||
import React, { FC, memo, startTransition, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
@ -24,13 +33,11 @@ interface SessionItemProps {
|
||||
session: AgentSessionEntity
|
||||
// use external agentId as SSOT, instead of session.agent_id
|
||||
agentId: string
|
||||
isDisabled?: boolean
|
||||
isLoading?: boolean
|
||||
onDelete: () => void
|
||||
onPress: () => void
|
||||
}
|
||||
|
||||
const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoading, onDelete, onPress }) => {
|
||||
const SessionItem: FC<SessionItemProps> = ({ session, agentId, onDelete, onPress }) => {
|
||||
const { t } = useTranslation()
|
||||
const { chat } = useRuntime()
|
||||
const { updateSession } = useUpdateSession(agentId)
|
||||
@ -50,16 +57,16 @@ const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoa
|
||||
const DeleteButton = () => {
|
||||
return (
|
||||
<Tooltip
|
||||
content={t('chat.topics.delete.shortcut', { key: isMac ? '⌘' : 'Ctrl' })}
|
||||
classNames={{ content: 'text-xs' }}
|
||||
delay={500}
|
||||
closeDelay={0}>
|
||||
<div
|
||||
role="button"
|
||||
className={cn(
|
||||
'mr-2 flex aspect-square h-6 w-6 items-center justify-center rounded-2xl',
|
||||
isConfirmingDeletion ? 'hover:bg-danger-100' : 'hover:bg-foreground-300'
|
||||
)}
|
||||
placement="bottom"
|
||||
mouseEnterDelay={0.7}
|
||||
mouseLeaveDelay={0}
|
||||
title={
|
||||
<div style={{ fontSize: '12px', opacity: 0.8, fontStyle: 'italic' }}>
|
||||
{t('chat.topics.delete.shortcut', { key: isMac ? '⌘' : 'Ctrl' })}
|
||||
</div>
|
||||
}>
|
||||
<MenuButton
|
||||
className="menu"
|
||||
onClick={(e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
if (isConfirmingDeletion || e.ctrlKey || e.metaKey) {
|
||||
@ -78,17 +85,11 @@ const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoa
|
||||
}
|
||||
}}>
|
||||
{isConfirmingDeletion ? (
|
||||
<DeleteIcon
|
||||
size={14}
|
||||
className="opacity-0 transition-colors-opacity group-hover:text-danger group-hover:opacity-100"
|
||||
/>
|
||||
<DeleteIcon size={14} color="var(--color-error)" style={{ pointerEvents: 'none' }} />
|
||||
) : (
|
||||
<XIcon
|
||||
size={14}
|
||||
className={cn(isActive ? 'opacity-100' : 'opacity-0', 'group-hover:opacity-100', 'transition-opacity')}
|
||||
/>
|
||||
<XIcon size={14} color="var(--color-text-3)" style={{ pointerEvents: 'none' }} />
|
||||
)}
|
||||
</div>
|
||||
</MenuButton>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
@ -106,44 +107,44 @@ const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoa
|
||||
}
|
||||
}, [activeSessionId, dispatch, isFulfilled, session.id, sessionTopicId])
|
||||
|
||||
const { topicPosition, setTopicPosition } = useSettings()
|
||||
const singlealone = topicPosition === 'right'
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContextMenu modal={false}>
|
||||
<ContextMenuTrigger>
|
||||
<ButtonContainer
|
||||
isDisabled={isDisabled}
|
||||
isLoading={isLoading}
|
||||
onPress={onPress}
|
||||
isActive={isActive}
|
||||
<SessionListItem
|
||||
className={classNames(isActive ? 'active' : '', singlealone ? 'singlealone' : '')}
|
||||
onClick={isEditing ? undefined : onPress}
|
||||
onDoubleClick={() => startEdit(session.name ?? '')}
|
||||
className="group">
|
||||
<SessionLabelContainer className="name h-full w-full pl-1" title={session.name ?? session.id}>
|
||||
{isPending && !isActive && <PendingIndicator />}
|
||||
{isFulfilled && !isActive && <FulfilledIndicator />}
|
||||
{isEditing && (
|
||||
<Input
|
||||
title={session.name ?? session.id}
|
||||
style={{
|
||||
borderRadius: 'var(--list-item-border-radius)',
|
||||
cursor: isEditing ? 'default' : 'pointer'
|
||||
}}>
|
||||
{isPending && !isActive && <PendingIndicator />}
|
||||
{isFulfilled && !isActive && <FulfilledIndicator />}
|
||||
<SessionNameContainer>
|
||||
{isEditing ? (
|
||||
<SessionEditInput
|
||||
ref={inputRef}
|
||||
variant="bordered"
|
||||
value={editValue}
|
||||
onValueChange={handleValueChange}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleValueChange(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
classNames={{
|
||||
base: 'h-full',
|
||||
mainWrapper: 'h-full',
|
||||
inputWrapper: 'h-full min-h-0 px-1.5',
|
||||
input: isSaving ? 'brightness-50' : undefined
|
||||
}}
|
||||
onClick={(e: React.MouseEvent) => e.stopPropagation()}
|
||||
style={{ opacity: isSaving ? 0.5 : 1 }}
|
||||
/>
|
||||
)}
|
||||
{!isEditing && (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<SessionLabel session={session} />
|
||||
) : (
|
||||
<>
|
||||
<SessionName>
|
||||
<SessionLabel session={session} />
|
||||
</SessionName>
|
||||
<DeleteButton />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</SessionLabelContainer>
|
||||
</ButtonContainer>
|
||||
</SessionNameContainer>
|
||||
</SessionListItem>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem
|
||||
@ -157,6 +158,20 @@ const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoa
|
||||
<EditIcon size={14} />
|
||||
{t('common.edit')}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger className="gap-2">
|
||||
<MenuIcon size={14} />
|
||||
{t('settings.topic.position.label')}
|
||||
</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuItem key="left" onClick={() => setTopicPosition('left')}>
|
||||
{t('settings.topic.position.left')}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem key="right" onClick={() => setTopicPosition('right')}>
|
||||
{t('settings.topic.position.right')}
|
||||
</ContextMenuItem>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
<ContextMenuItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
@ -172,38 +187,96 @@ const SessionItem: FC<SessionItemProps> = ({ session, agentId, isDisabled, isLoa
|
||||
)
|
||||
}
|
||||
|
||||
const ButtonContainer: React.FC<React.ComponentProps<typeof Button> & { isActive?: boolean }> = ({
|
||||
isActive,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const { topicPosition } = useSettings()
|
||||
const activeBg = topicPosition === 'left' ? 'bg-[var(--color-list-item)]' : 'bg-foreground-100'
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
variant="light"
|
||||
className={cn(
|
||||
'relative mb-2 flex h-9 flex-row justify-between p-0',
|
||||
'rounded-[var(--list-item-border-radius)]',
|
||||
'border-[0.5px] border-transparent',
|
||||
'w-[calc(var(--assistants-width)_-_20px)]',
|
||||
'cursor-pointer',
|
||||
isActive ? cn(activeBg, 'shadow-sm') : undefined,
|
||||
className
|
||||
)}>
|
||||
{children}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
const SessionListItem = styled.div`
|
||||
padding: 7px 12px;
|
||||
border-radius: var(--list-item-border-radius);
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
width: calc(var(--assistants-width) - 20px);
|
||||
margin-bottom: 8px;
|
||||
|
||||
const SessionLabelContainer: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
|
||||
<div
|
||||
{...props}
|
||||
className={cn('text-[13px] text-[var(--color-text)]', 'flex flex-row items-center gap-2', className)}
|
||||
/>
|
||||
)
|
||||
.menu {
|
||||
opacity: 0;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-list-item-hover);
|
||||
transition: background-color 0.1s;
|
||||
|
||||
.menu {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: var(--color-list-item);
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
.menu {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.singlealone {
|
||||
border-radius: 0 !important;
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
&.active {
|
||||
border-left: 2px solid var(--color-primary);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const SessionNameContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
height: 20px;
|
||||
justify-content: space-between;
|
||||
`
|
||||
|
||||
const SessionName = styled.div`
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const SessionEditInput = styled.input`
|
||||
background: var(--color-background);
|
||||
border: none;
|
||||
color: var(--color-text-1);
|
||||
font-size: 13px;
|
||||
font-family: inherit;
|
||||
padding: 2px 6px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
`
|
||||
|
||||
const MenuButton = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
.anticon {
|
||||
font-size: 12px;
|
||||
}
|
||||
`
|
||||
|
||||
const PendingIndicator = styled.div.attrs({
|
||||
className: 'animation-pulse'
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
} from '@renderer/store/runtime'
|
||||
import { CreateSessionForm } from '@renderer/types'
|
||||
import { buildAgentSessionTopicId } from '@renderer/utils/agentSession'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { motion } from 'framer-motion'
|
||||
import { memo, useCallback, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@ -30,7 +30,7 @@ const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
|
||||
const { agent } = useAgent(agentId)
|
||||
const { sessions, isLoading, error, deleteSession, createSession } = useSessions(agentId)
|
||||
const { chat } = useRuntime()
|
||||
const { activeSessionIdMap, sessionWaiting } = chat
|
||||
const { activeSessionIdMap } = chat
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const setActiveSessionId = useCallback(
|
||||
@ -109,45 +109,30 @@ const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
|
||||
if (error) return <Alert color="danger" content={t('agent.session.get.error.failed')} />
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="sessions-tab flex h-full w-full flex-col p-2">
|
||||
<motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}>
|
||||
<AddButton onPress={handleCreateSession} className="mb-2">
|
||||
{t('agent.session.add.title')}
|
||||
</AddButton>
|
||||
</motion.div>
|
||||
<AnimatePresence>
|
||||
{/* h-9 */}
|
||||
<DynamicVirtualList
|
||||
list={sessions}
|
||||
estimateSize={() => 9 * 4}
|
||||
scrollerStyle={{
|
||||
// FIXME: This component only supports CSSProperties
|
||||
overflowX: 'hidden'
|
||||
}}
|
||||
autoHideScrollbar>
|
||||
{(session) => (
|
||||
<motion.div
|
||||
key={session.id}
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.3 }}>
|
||||
<SessionItem
|
||||
session={session}
|
||||
agentId={agentId}
|
||||
isDisabled={sessionWaiting[session.id]}
|
||||
isLoading={sessionWaiting[session.id]}
|
||||
onDelete={() => handleDeleteSession(session.id)}
|
||||
onPress={() => setActiveSessionId(agentId, session.id)}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</DynamicVirtualList>
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
<div className="sessions-tab flex h-full w-full flex-col p-2">
|
||||
<AddButton onPress={handleCreateSession} className="mb-2">
|
||||
{t('agent.session.add.title')}
|
||||
</AddButton>
|
||||
{/* h-9 */}
|
||||
<DynamicVirtualList
|
||||
list={sessions}
|
||||
estimateSize={() => 9 * 4}
|
||||
scrollerStyle={{
|
||||
// FIXME: This component only supports CSSProperties
|
||||
overflowX: 'hidden'
|
||||
}}
|
||||
autoHideScrollbar>
|
||||
{(session) => (
|
||||
<SessionItem
|
||||
key={session.id}
|
||||
session={session}
|
||||
agentId={agentId}
|
||||
onDelete={() => handleDeleteSession(session.id)}
|
||||
onPress={() => setActiveSessionId(agentId, session.id)}
|
||||
/>
|
||||
)}
|
||||
</DynamicVirtualList>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -189,10 +189,7 @@ const Container = styled.div`
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
[navbar-position='top'] & {
|
||||
height: calc(100vh - var(--navbar-height) - 12px);
|
||||
&.right {
|
||||
height: calc(100vh - var(--navbar-height) - var(--navbar-height) - 12px);
|
||||
}
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
}
|
||||
overflow: hidden;
|
||||
.collapsed {
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { BreadcrumbItem, Breadcrumbs, Chip, cn } from '@heroui/react'
|
||||
import { BreadcrumbItem, Breadcrumbs, cn } from '@heroui/react'
|
||||
import HorizontalScrollContainer from '@renderer/components/HorizontalScrollContainer'
|
||||
import { permissionModeCards } from '@renderer/constants/permissionModes'
|
||||
import { useActiveAgent } from '@renderer/hooks/agents/useActiveAgent'
|
||||
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
|
||||
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||
import { AgentEntity, AgentSessionEntity, ApiModel, Assistant, PermissionMode } from '@renderer/types'
|
||||
import { AgentEntity, AgentSessionEntity, ApiModel, Assistant } from '@renderer/types'
|
||||
import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
|
||||
import { t } from 'i18next'
|
||||
import { Folder } from 'lucide-react'
|
||||
import { FC, ReactNode, useCallback } from 'react'
|
||||
|
||||
import { AgentSettingsPopup, SessionSettingsPopup } from '../../settings/AgentSettings'
|
||||
@ -38,24 +38,15 @@ const ChatNavbarContent: FC<Props> = ({ assistant }) => {
|
||||
<>
|
||||
{activeTopicOrSession === 'topic' && <SelectModelButton assistant={assistant} />}
|
||||
{activeTopicOrSession === 'session' && activeAgent && (
|
||||
<HorizontalScrollContainer>
|
||||
<Breadcrumbs
|
||||
classNames={{
|
||||
base: 'flex',
|
||||
list: 'flex-nowrap'
|
||||
}}>
|
||||
<HorizontalScrollContainer className="ml-2 flex-initial">
|
||||
<Breadcrumbs classNames={{ base: 'flex', list: 'flex-nowrap' }}>
|
||||
<BreadcrumbItem
|
||||
onPress={() => AgentSettingsPopup.show({ agentId: activeAgent.id })}
|
||||
classNames={{
|
||||
base: 'self-stretch',
|
||||
item: 'h-full'
|
||||
}}>
|
||||
<Chip size="md" variant="light" className="h-full transition-background hover:bg-foreground-100">
|
||||
<AgentLabel
|
||||
agent={activeAgent}
|
||||
classNames={{ name: 'max-w-40 font-bold text-xs', avatar: 'h-4.5 w-4.5', container: 'gap-1.5' }}
|
||||
/>
|
||||
</Chip>
|
||||
classNames={{ base: 'self-stretch', item: 'h-full' }}>
|
||||
<AgentLabel
|
||||
agent={activeAgent}
|
||||
classNames={{ name: 'max-w-40 text-xs', avatar: 'h-4.5 w-4.5', container: 'gap-1.5' }}
|
||||
/>
|
||||
</BreadcrumbItem>
|
||||
{activeSession && (
|
||||
<BreadcrumbItem
|
||||
@ -65,13 +56,8 @@ const ChatNavbarContent: FC<Props> = ({ assistant }) => {
|
||||
sessionId: activeSession.id
|
||||
})
|
||||
}
|
||||
classNames={{
|
||||
base: 'self-stretch',
|
||||
item: 'h-full'
|
||||
}}>
|
||||
<Chip size="md" variant="light" className="h-full transition-background hover:bg-foreground-100">
|
||||
<SessionLabel session={activeSession} className="max-w-40 font-bold text-xs" />
|
||||
</Chip>
|
||||
classNames={{ base: 'self-stretch', item: 'h-full' }}>
|
||||
<SessionLabel session={activeSession} className="max-w-40 text-xs" />
|
||||
</BreadcrumbItem>
|
||||
)}
|
||||
{activeSession && (
|
||||
@ -97,11 +83,11 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
|
||||
}
|
||||
|
||||
const firstAccessiblePath = session.accessible_paths?.[0]
|
||||
const permissionMode = (session.configuration?.permission_mode ?? 'default') as PermissionMode
|
||||
const permissionModeCard = permissionModeCards.find((card) => card.mode === permissionMode)
|
||||
const permissionModeLabel = permissionModeCard
|
||||
? t(permissionModeCard.titleKey, permissionModeCard.titleFallback)
|
||||
: permissionMode
|
||||
// const permissionMode = (session.configuration?.permission_mode ?? 'default') as PermissionMode
|
||||
// const permissionModeCard = permissionModeCards.find((card) => card.mode === permissionMode)
|
||||
// const permissionModeLabel = permissionModeCard
|
||||
// ? t(permissionModeCard.titleKey, permissionModeCard.titleFallback)
|
||||
// : permissionMode
|
||||
|
||||
const infoItems: ReactNode[] = []
|
||||
|
||||
@ -117,12 +103,13 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
|
||||
}) => (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-medium border border-default-200 px-2 py-1 text-foreground-500 text-xs dark:text-foreground-400',
|
||||
'flex items-center gap-1.5 text-foreground-500 text-xs dark:text-foreground-400',
|
||||
onClick !== undefined ? 'cursor-pointer' : undefined,
|
||||
className
|
||||
)}
|
||||
title={text}
|
||||
onClick={onClick}>
|
||||
<Folder className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="block truncate">{text}</span>
|
||||
</div>
|
||||
)
|
||||
@ -148,7 +135,7 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
|
||||
)
|
||||
}
|
||||
|
||||
infoItems.push(<InfoTag key="permission-mode" text={permissionModeLabel} className="max-w-50" />)
|
||||
// infoItems.push(<InfoTag key="permission-mode" text={permissionModeLabel} className="max-w-50" />)
|
||||
|
||||
if (infoItems.length === 0) {
|
||||
return null
|
||||
|
||||
@ -38,12 +38,12 @@ const SelectAgentBaseModelButton: FC<Props> = ({ agentBase: agent, onSelect, isD
|
||||
<Button
|
||||
size="sm"
|
||||
variant="light"
|
||||
className="nodrag rounded-2xl px-1 py-3"
|
||||
className="nodrag h-[28px] rounded-2xl px-1"
|
||||
onPress={onSelectModel}
|
||||
isDisabled={isDisabled}>
|
||||
<div className="flex items-center gap-1.5 overflow-x-hidden">
|
||||
<ModelAvatar model={model ? apiModelAdapter(model) : undefined} size={20} />
|
||||
<span className="truncate font-medium">
|
||||
<span className="truncate text-[var(--color-text)]">
|
||||
{model ? model.name : t('button.select_model')} {providerName ? ' | ' + providerName : ''}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -87,6 +87,7 @@ const ButtonContent = styled.div`
|
||||
const ModelName = styled.span`
|
||||
font-weight: 500;
|
||||
margin-right: -2px;
|
||||
font-size: 12px;
|
||||
`
|
||||
|
||||
export default SelectModelButton
|
||||
|
||||
@ -104,7 +104,7 @@ const AgentSettingPopupContainer: React.FC<AgentSettingPopupParams> = ({ tab, ag
|
||||
afterClose={afterClose}
|
||||
maskClosable={false}
|
||||
footer={null}
|
||||
title={<AgentLabel agent={agent} classNames={{ name: 'text-lg font-extrabold' }} />}
|
||||
title={<AgentLabel agent={agent} />}
|
||||
transitionName="animation-move-down"
|
||||
styles={{
|
||||
content: {
|
||||
|
||||
@ -20,13 +20,15 @@ type EssentialSettingsProps =
|
||||
| {
|
||||
agentBase: GetAgentResponse | undefined | null
|
||||
update: ReturnType<typeof useUpdateAgent>['updateAgent']
|
||||
showModelSetting?: boolean
|
||||
}
|
||||
| {
|
||||
agentBase: GetAgentSessionResponse | undefined | null
|
||||
update: ReturnType<typeof useUpdateSession>['updateSession']
|
||||
showModelSetting?: boolean
|
||||
}
|
||||
|
||||
const EssentialSettings: FC<EssentialSettingsProps> = ({ agentBase, update }) => {
|
||||
const EssentialSettings: FC<EssentialSettingsProps> = ({ agentBase, update, showModelSetting = true }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (!agentBase) return null
|
||||
@ -46,7 +48,7 @@ const EssentialSettings: FC<EssentialSettingsProps> = ({ agentBase, update }) =>
|
||||
)}
|
||||
{isAgent && <AvatarSetting agent={agentBase} update={update} />}
|
||||
<NameSetting base={agentBase} update={update} />
|
||||
<ModelSetting base={agentBase} update={update} />
|
||||
{showModelSetting && <ModelSetting base={agentBase} update={update} />}
|
||||
<AccessibleDirsSetting base={agentBase} update={update} />
|
||||
<DescriptionSetting base={agentBase} update={update} />
|
||||
</SettingsContainer>
|
||||
|
||||
@ -106,7 +106,7 @@ const SessionSettingPopupContainer: React.FC<SessionSettingPopupParams> = ({ tab
|
||||
afterClose={afterClose}
|
||||
maskClosable={false}
|
||||
footer={null}
|
||||
title={<SessionLabel session={session} className="font-extrabold text-lg" />}
|
||||
title={<SessionLabel session={session} />}
|
||||
transitionName="animation-move-down"
|
||||
styles={{
|
||||
content: {
|
||||
|
||||
@ -36,7 +36,7 @@ export const AgentLabel: React.FC<AgentLabelProps> = ({ agent, classNames }) =>
|
||||
return (
|
||||
<div className={cn('flex w-full items-center gap-2 truncate', classNames?.container)}>
|
||||
<EmojiIcon emoji={emoji || '⭐️'} className={classNames?.avatar} />
|
||||
<span className={cn('truncate', classNames?.name)}>
|
||||
<span className={cn('truncate', 'text-[var(--color-text)]', classNames?.name)}>
|
||||
{agent?.name ?? (agent?.type ? getAgentTypeLabel(agent.type) : '')}
|
||||
</span>
|
||||
</div>
|
||||
@ -52,7 +52,7 @@ export const SessionLabel: React.FC<SessionLabelProps> = ({ session, className }
|
||||
const displayName = session?.name ?? session?.id
|
||||
return (
|
||||
<>
|
||||
<span className={cn('truncate px-2 text-sm', className)}>{displayName}</span>
|
||||
<span className={cn('truncate text-[var(--color-text)] text-sm', className)}>{displayName}</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user