refactor(ui): enhance component interactions and layout adjustments

- Updated ChatNavbar to remove unnecessary padding for a cleaner look.
- Added min-height to AddButton for consistent button sizing.
- Introduced hover state management in AgentItem and AssistantItem for improved user experience.
- Refactored dropdown menu handling in AgentItem and AssistantItem to enhance interaction.
- Adjusted margin in HeaderRow for better spacing.
- Modified SessionWorkspaceMeta to display folder names more clearly with tooltips.

These changes aim to improve the overall UI responsiveness and clarity in component interactions.
This commit is contained in:
kangfenmao 2026-01-25 13:39:53 +08:00
parent 78c6f97248
commit bd798284df
7 changed files with 57 additions and 33 deletions

View File

@ -67,7 +67,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
}
return (
<NavbarHeader className="home-navbar" style={{ height: 'var(--navbar-height)', paddingRight: 16 }}>
<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}>

View File

@ -6,6 +6,7 @@ import styled from 'styled-components'
const StyledButton = styled(Button)`
height: 36px;
min-height: 36px;
width: calc(var(--assistants-width) - 20px);
justify-content: flex-start;
border-radius: var(--list-item-border-radius);

View File

@ -9,7 +9,7 @@ import type { MenuProps } from 'antd'
import { Dropdown, Tooltip } from 'antd'
import { Bot, MoreVertical } from 'lucide-react'
import type { FC } from 'react'
import { memo, useCallback, useMemo } from 'react'
import { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
// const logger = loggerService.withContext('AgentItem')
@ -24,6 +24,7 @@ interface AgentItemProps {
const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) => {
const { t } = useTranslation()
const { clickAssistantToShowTopic, topicPosition, assistantIconType } = useSettings()
const [isHovered, setIsHovered] = useState(false)
const handlePress = useCallback(() => {
// Show session sidebar if setting is enabled (reusing the assistant setting for consistency)
@ -35,13 +36,9 @@ const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) =
onPress()
}, [clickAssistantToShowTopic, topicPosition, onPress])
const handleMoreClick = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation()
agent.id && AgentSettingsPopup.show({ agentId: agent.id })
},
[agent.id]
)
const handleMenuButtonClick = useCallback((e: React.MouseEvent) => {
e.stopPropagation()
}, [])
const menuItems: MenuProps['items'] = useMemo(
() => [
@ -75,17 +72,26 @@ const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) =
menu={{ items: menuItems }}
trigger={['contextMenu']}
popupRender={(menu) => <div onPointerDown={(e) => e.stopPropagation()}>{menu}</div>}>
<Container onClick={handlePress} isActive={isActive}>
<Container
onClick={handlePress}
isActive={isActive}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<AssistantNameRow className="name" title={agent.name ?? agent.id}>
<AgentNameWrapper>
<AgentLabel agent={agent} hideIcon={assistantIconType === 'none'} />
</AgentNameWrapper>
{isActive && (
<MenuButton onClick={handleMoreClick}>
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
</MenuButton>
{(isActive || isHovered) && (
<Dropdown
menu={{ items: menuItems }}
trigger={['click']}
popupRender={(menu) => <div onPointerDown={(e) => e.stopPropagation()}>{menu}</div>}>
<MenuButton onClick={handleMenuButtonClick}>
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
</MenuButton>
</Dropdown>
)}
{!isActive && assistantIconType !== 'none' && <BotIcon />}
{!isActive && !isHovered && assistantIconType !== 'none' && <BotIcon />}
</AssistantNameRow>
</Container>
</Dropdown>

View File

@ -69,6 +69,7 @@ const AssistantItem: FC<AssistantItemProps> = ({
const { assistants, updateAssistants } = useAssistants()
const [isPending, setIsPending] = useState(false)
const [isHovered, setIsHovered] = useState(false)
const dispatch = useAppDispatch()
useEffect(() => {
@ -148,20 +149,20 @@ const AssistantItem: FC<AssistantItemProps> = ({
[assistant.emoji, assistantName]
)
const handleMoreClick = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation()
AssistantSettingsPopup.show({ assistant })
},
[assistant]
)
const handleMenuButtonClick = useCallback((e: React.MouseEvent) => {
e.stopPropagation()
}, [])
return (
<Dropdown
menu={{ items: menuItems }}
trigger={['contextMenu']}
popupRender={(menu) => <div onPointerDown={(e) => e.stopPropagation()}>{menu}</div>}>
<Container onClick={handleSwitch} isActive={isActive}>
<Container
onClick={handleSwitch}
isActive={isActive}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<AssistantNameRow className="name" title={fullAssistantName}>
<AssistantAvatar
assistant={assistant}
@ -170,10 +171,15 @@ const AssistantItem: FC<AssistantItemProps> = ({
/>
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
</AssistantNameRow>
{isActive && (
<MenuButton onClick={handleMoreClick}>
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
</MenuButton>
{(isActive || isHovered) && (
<Dropdown
menu={{ items: menuItems }}
trigger={['click']}
popupRender={(menu) => <div onPointerDown={(e) => e.stopPropagation()}>{menu}</div>}>
<MenuButton onClick={handleMenuButtonClick}>
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
</MenuButton>
</Dropdown>
)}
</Container>
</Dropdown>

View File

@ -104,9 +104,11 @@ const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
scrollerStyle={{ overflowX: 'hidden' }}
autoHideScrollbar
header={
<AddButton onClick={createDefaultSession} disabled={creatingSession} className="-mt-[4px] mb-[6px]">
{t('agent.session.add.title')}
</AddButton>
<div className="mt-[2px]">
<AddButton onClick={createDefaultSession} disabled={creatingSession} className="-mt-[4px] mb-[6px]">
{t('agent.session.add.title')}
</AddButton>
</div>
}>
{(session) => (
<SessionItem

View File

@ -911,7 +911,7 @@ const HeaderRow = styled.div`
align-items: center;
gap: 6px;
padding-right: 10px;
margin-bottom: 6px;
margin-bottom: 8px;
margin-top: 2px;
`

View File

@ -130,14 +130,22 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
// ? t(permissionModeCard.titleKey, permissionModeCard.titleFallback)
// : permissionMode
const getLastFolderName = (path: string): string => {
const trimmedPath = path.replace(/[/\\]+$/, '')
const parts = trimmedPath.split(/[/\\]/)
return parts[parts.length - 1] || path
}
const infoItems: ReactNode[] = []
const InfoTag = ({
text,
tooltip,
className,
onClick
}: {
text: string
tooltip?: string
className?: string
classNames?: {}
onClick?: (e: React.MouseEvent) => void
@ -148,7 +156,7 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
onClick !== undefined ? 'cursor-pointer' : undefined,
className
)}
title={text}
title={tooltip ?? text}
onClick={onClick}>
<Folder className="h-3.5 w-3.5 shrink-0" />
<span className="block truncate">{text}</span>
@ -161,7 +169,8 @@ const SessionWorkspaceMeta: FC<{ agent: AgentEntity; session: AgentSessionEntity
infoItems.push(
<InfoTag
key="path"
text={firstAccessiblePath}
text={getLastFolderName(firstAccessiblePath)}
tooltip={firstAccessiblePath}
className="max-w-60 transition-colors hover:border-primary hover:text-primary"
onClick={() => {
window.api.file