mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-26 20:45:37 +02:00
fix(chat): reading-width container + refresh placeholder on agent switch
- Wrap ChatMessageList and ChatInput in mx-auto max-w-4xl px-5 so wide chat windows don't sprawl — matches the issue-detail / project-detail width convention - draftKey now includes the selected agent id in the new-chat state. Tiptap's Placeholder only applies at mount, so key-driven remount is the simplest way to refresh it when the user switches agents before sending the first message. Side benefit: per-agent new-chat drafts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,15 @@ export function ChatInput({
|
||||
}: ChatInputProps) {
|
||||
const editorRef = useRef<ContentEditorRef>(null);
|
||||
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
||||
const draftKey = activeSessionId ?? DRAFT_NEW_SESSION;
|
||||
const selectedAgentId = useChatStore((s) => s.selectedAgentId);
|
||||
// Scope the new-chat draft by agent:
|
||||
// 1. Switching agents while composing a brand-new chat gives each
|
||||
// agent its own draft (no cross-agent leakage).
|
||||
// 2. Tiptap's Placeholder extension is only applied at mount; this
|
||||
// key changes on agent switch so the editor remounts and the
|
||||
// `Tell {agent} what to do…` placeholder refreshes.
|
||||
const draftKey =
|
||||
activeSessionId ?? `${DRAFT_NEW_SESSION}:${selectedAgentId ?? ""}`;
|
||||
// Select a primitive — empty-string fallback keeps referential stability.
|
||||
const inputDraft = useChatStore((s) => s.inputDrafts[draftKey] ?? "");
|
||||
const setInputDraft = useChatStore((s) => s.setInputDraft);
|
||||
@@ -65,8 +73,8 @@ export function ChatInput({
|
||||
: "Tell me what to do…";
|
||||
|
||||
return (
|
||||
<div className="p-2 pt-0">
|
||||
<div className="relative flex min-h-16 max-h-40 flex-col rounded-lg bg-card pb-9 border-1 border-border transition-colors focus-within:border-brand">
|
||||
<div className="px-5 pb-3 pt-0">
|
||||
<div className="relative mx-auto flex min-h-16 max-h-40 w-full max-w-4xl flex-col rounded-lg bg-card pb-9 border-1 border-border transition-colors focus-within:border-brand">
|
||||
<div className="flex-1 min-h-0 overflow-y-auto px-3 py-2">
|
||||
<ContentEditor
|
||||
// Remount the editor when the active session changes so its
|
||||
|
||||
@@ -53,22 +53,24 @@ export function ChatMessageList({
|
||||
const hasLive = showLiveTimeline && liveTimeline.length > 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={scrollRef}
|
||||
style={fadeStyle}
|
||||
className="flex-1 overflow-y-auto px-4 py-3 space-y-4"
|
||||
>
|
||||
{messages.map((msg) => (
|
||||
<MessageBubble key={msg.id} message={msg} />
|
||||
))}
|
||||
{hasLive && (
|
||||
<div className="w-full space-y-1.5">
|
||||
<TimelineView items={liveTimeline} />
|
||||
</div>
|
||||
)}
|
||||
{isWaiting && !hasLive && !pendingAlreadyPersisted && (
|
||||
<Loader2 className="size-4 animate-spin text-muted-foreground" />
|
||||
)}
|
||||
<div ref={scrollRef} style={fadeStyle} className="flex-1 overflow-y-auto">
|
||||
{/* Inner container matches issue / project detail width convention
|
||||
* (max-w-4xl + mx-auto) so switching between chat and content
|
||||
* views doesn't jolt the reading width. px-5 is a touch tighter
|
||||
* than issue-detail's px-8 because the chat window can be narrow. */}
|
||||
<div className="mx-auto w-full max-w-4xl px-5 py-4 space-y-4">
|
||||
{messages.map((msg) => (
|
||||
<MessageBubble key={msg.id} message={msg} />
|
||||
))}
|
||||
{hasLive && (
|
||||
<div className="w-full space-y-1.5">
|
||||
<TimelineView items={liveTimeline} />
|
||||
</div>
|
||||
)}
|
||||
{isWaiting && !hasLive && !pendingAlreadyPersisted && (
|
||||
<Loader2 className="size-4 animate-spin text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user