优化新会话页面显示布局

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
attachmentTabId?: string | null
draftStorageKey?: string | null
hideInput?: boolean
}
export function ConversationShell({
@@ -55,6 +56,7 @@ export function ConversationShell({
availableCommands,
attachmentTabId,
draftStorageKey,
hideInput = false,
}: ConversationShellProps) {
return (
<div className="flex h-full min-h-0 flex-col">
@@ -65,24 +67,26 @@ export function ConversationShell({
onRespond={onRespondPermission}
/>
<ChatInput
status={status}
promptCapabilities={promptCapabilities}
defaultPath={defaultPath}
onFocus={onFocus}
onSend={onSend}
onCancel={onCancel}
modes={modes}
configOptions={configOptions}
modeLoading={modeLoading}
configOptionsLoading={configOptionsLoading}
selectedModeId={selectedModeId}
onModeChange={onModeChange}
onConfigOptionChange={onConfigOptionChange}
availableCommands={availableCommands}
attachmentTabId={attachmentTabId}
draftStorageKey={draftStorageKey}
/>
{!hideInput && (
<ChatInput
status={status}
promptCapabilities={promptCapabilities}
defaultPath={defaultPath}
onFocus={onFocus}
onSend={onSend}
onCancel={onCancel}
modes={modes}
configOptions={configOptions}
modeLoading={modeLoading}
configOptionsLoading={configOptionsLoading}
selectedModeId={selectedModeId}
onModeChange={onModeChange}
onConfigOptionChange={onConfigOptionChange}
availableCommands={availableCommands}
attachmentTabId={attachmentTabId}
draftStorageKey={draftStorageKey}
/>
)}
{error && (
<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 { ConversationShell } from "@/components/chat/conversation-shell"
import { AgentSelector } from "@/components/chat/agent-selector"
import { ChatInput } from "@/components/chat/chat-input"
import {
createConversation,
openSettingsWindow,
@@ -151,6 +152,7 @@ const ConversationTabView = memo(function ConversationTabView({
const [agentConnectError, setAgentConnectError] = useState<string | null>(
null
)
const [hasSentMessage, setHasSentMessage] = useState(false)
const hasPersistedConversation = dbConversationId != null
const canAutoConnect =
@@ -425,6 +427,7 @@ const ConversationTabView = memo(function ConversationTabView({
)
setSendSignal((prev) => prev + 1)
setSyncState(effectiveConversationId, "awaiting_persist")
setHasSentMessage(true)
lifecycleSend(draft, selectedModeIdArg)
const persistedId = dbConvIdRef.current
@@ -534,6 +537,9 @@ const ConversationTabView = memo(function ConversationTabView({
[connConnect, connDisconnect, workingDirForConnection]
)
const showDraftHeader = !hasPersistedConversation
const isWelcomeMode = showDraftHeader && !hasSentMessage
const messageListNode = (
<MessageListView
conversationId={effectiveConversationId}
@@ -543,11 +549,10 @@ const ConversationTabView = memo(function ConversationTabView({
sessionStats={detail?.session_stats ?? null}
detailLoading={detailLoading}
detailError={detailError}
hideEmptyState={showDraftHeader}
/>
)
const showDraftHeader = !hasPersistedConversation
return (
<ConversationShell
status={connStatus}
@@ -569,8 +574,59 @@ const ConversationTabView = memo(function ConversationTabView({
availableCommands={connectionCommands}
attachmentTabId={tabId}
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="px-4 pt-3 pb-2">
<AgentSelector

View File

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