优化新会话页面显示布局

This commit is contained in:
xintaofei
2026-03-10 23:49:28 +08:00
parent 380f430d5a
commit 5960ccebb9
3 changed files with 92 additions and 29 deletions

View File

@@ -32,6 +32,7 @@ interface ConversationShellProps {
availableCommands?: AvailableCommandInfo[] | null availableCommands?: AvailableCommandInfo[] | null
attachmentTabId?: string | null attachmentTabId?: string | null
draftStorageKey?: string | null draftStorageKey?: string | null
hideInput?: boolean
} }
export function ConversationShell({ export function ConversationShell({
@@ -55,6 +56,7 @@ export function ConversationShell({
availableCommands, availableCommands,
attachmentTabId, attachmentTabId,
draftStorageKey, draftStorageKey,
hideInput = false,
}: ConversationShellProps) { }: ConversationShellProps) {
return ( return (
<div className="flex h-full min-h-0 flex-col"> <div className="flex h-full min-h-0 flex-col">
@@ -65,6 +67,7 @@ export function ConversationShell({
onRespond={onRespondPermission} onRespond={onRespondPermission}
/> />
{!hideInput && (
<ChatInput <ChatInput
status={status} status={status}
promptCapabilities={promptCapabilities} promptCapabilities={promptCapabilities}
@@ -83,6 +86,7 @@ export function ConversationShell({
attachmentTabId={attachmentTabId} attachmentTabId={attachmentTabId}
draftStorageKey={draftStorageKey} draftStorageKey={draftStorageKey}
/> />
)}
{error && ( {error && (
<div className="px-4 py-2 text-xs text-destructive bg-destructive/5 border-t border-destructive/20"> <div className="px-4 py-2 text-xs text-destructive bg-destructive/5 border-t border-destructive/20">

View File

@@ -11,6 +11,7 @@ import { useConnectionLifecycle } from "@/hooks/use-connection-lifecycle"
import { MessageListView } from "@/components/message/message-list-view" import { MessageListView } from "@/components/message/message-list-view"
import { ConversationShell } from "@/components/chat/conversation-shell" import { ConversationShell } from "@/components/chat/conversation-shell"
import { AgentSelector } from "@/components/chat/agent-selector" import { AgentSelector } from "@/components/chat/agent-selector"
import { ChatInput } from "@/components/chat/chat-input"
import { import {
createConversation, createConversation,
openSettingsWindow, openSettingsWindow,
@@ -151,6 +152,7 @@ const ConversationTabView = memo(function ConversationTabView({
const [agentConnectError, setAgentConnectError] = useState<string | null>( const [agentConnectError, setAgentConnectError] = useState<string | null>(
null null
) )
const [hasSentMessage, setHasSentMessage] = useState(false)
const hasPersistedConversation = dbConversationId != null const hasPersistedConversation = dbConversationId != null
const canAutoConnect = const canAutoConnect =
@@ -425,6 +427,7 @@ const ConversationTabView = memo(function ConversationTabView({
) )
setSendSignal((prev) => prev + 1) setSendSignal((prev) => prev + 1)
setSyncState(effectiveConversationId, "awaiting_persist") setSyncState(effectiveConversationId, "awaiting_persist")
setHasSentMessage(true)
lifecycleSend(draft, selectedModeIdArg) lifecycleSend(draft, selectedModeIdArg)
const persistedId = dbConvIdRef.current const persistedId = dbConvIdRef.current
@@ -534,6 +537,9 @@ const ConversationTabView = memo(function ConversationTabView({
[connConnect, connDisconnect, workingDirForConnection] [connConnect, connDisconnect, workingDirForConnection]
) )
const showDraftHeader = !hasPersistedConversation
const isWelcomeMode = showDraftHeader && !hasSentMessage
const messageListNode = ( const messageListNode = (
<MessageListView <MessageListView
conversationId={effectiveConversationId} conversationId={effectiveConversationId}
@@ -543,11 +549,10 @@ const ConversationTabView = memo(function ConversationTabView({
sessionStats={detail?.session_stats ?? null} sessionStats={detail?.session_stats ?? null}
detailLoading={detailLoading} detailLoading={detailLoading}
detailError={detailError} detailError={detailError}
hideEmptyState={showDraftHeader}
/> />
) )
const showDraftHeader = !hasPersistedConversation
return ( return (
<ConversationShell <ConversationShell
status={connStatus} status={connStatus}
@@ -569,8 +574,59 @@ const ConversationTabView = memo(function ConversationTabView({
availableCommands={connectionCommands} availableCommands={connectionCommands}
attachmentTabId={tabId} attachmentTabId={tabId}
draftStorageKey={draftStorageKey} draftStorageKey={draftStorageKey}
hideInput={isWelcomeMode}
> >
{showDraftHeader ? ( {isWelcomeMode ? (
<div className="flex h-full min-h-0 flex-col items-center justify-center">
<div className="flex w-full max-w-2xl flex-col gap-4 px-4">
<AgentSelector
defaultAgentType={selectedAgent}
onSelect={handleAgentSelect}
onAgentsLoaded={(agents) => {
setAgentsLoaded(true)
setUsableAgentCount(
agents.filter((agent) => agent.enabled && agent.available)
.length
)
}}
onOpenAgentsSettings={handleOpenAgentsSettings}
disabled={isConnecting || dbConversationId != null}
/>
{autoConnectError || agentConnectError ? (
<button
type="button"
onClick={handleOpenAgentsSettings}
className="w-full cursor-pointer rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-center text-xs text-destructive transition-colors hover:bg-destructive/10"
>
<div
className="overflow-hidden text-ellipsis whitespace-nowrap text-center"
title={autoConnectError ?? agentConnectError ?? ""}
>
{autoConnectError ?? agentConnectError}
</div>
</button>
) : null}
<ChatInput
status={connStatus}
promptCapabilities={conn.promptCapabilities}
defaultPath={workingDirForConnection}
onFocus={handleFocus}
onSend={handleSend}
onCancel={handleCancel}
modes={connectionModes}
configOptions={connectionConfigOptions}
modeLoading={modeLoading}
configOptionsLoading={configOptionsLoading}
selectedModeId={selectedModeId}
onModeChange={setModeId}
onConfigOptionChange={handleSetConfigOption}
availableCommands={connectionCommands}
attachmentTabId={tabId}
draftStorageKey={draftStorageKey}
/>
</div>
</div>
) : showDraftHeader ? (
<div className="flex h-full min-h-0 flex-col"> <div className="flex h-full min-h-0 flex-col">
<div className="px-4 pt-3 pb-2"> <div className="px-4 pt-3 pb-2">
<AgentSelector <AgentSelector

View File

@@ -36,6 +36,7 @@ interface MessageListViewProps {
sessionStats?: SessionStats | null sessionStats?: SessionStats | null
detailLoading?: boolean detailLoading?: boolean
detailError?: string | null detailError?: string | null
hideEmptyState?: boolean
} }
interface ResolvedMessageGroup extends MessageGroup { interface ResolvedMessageGroup extends MessageGroup {
@@ -133,6 +134,7 @@ export function MessageListView({
sessionStats = null, sessionStats = null,
detailLoading = false, detailLoading = false,
detailError = null, detailError = null,
hideEmptyState = false,
}: MessageListViewProps) { }: MessageListViewProps) {
const t = useTranslations("Folder.chat.messageList") const t = useTranslations("Folder.chat.messageList")
const sharedT = useTranslations("Folder.chat.shared") const sharedT = useTranslations("Folder.chat.shared")
@@ -237,14 +239,15 @@ export function MessageListView({
}, []) }, [])
const emptyState = useMemo( const emptyState = useMemo(
() => ( () =>
hideEmptyState ? null : (
<div className="px-4 py-12 text-center"> <div className="px-4 py-12 text-center">
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">
{t("emptyConversation")} {t("emptyConversation")}
</p> </p>
</div> </div>
), ),
[t] [hideEmptyState, t]
) )
const agentPlanOverlayKey = liveMessage?.id ?? `history-${conversationId}` const agentPlanOverlayKey = liveMessage?.id ?? `history-${conversationId}`