diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index 1c604f9a..8fb0490a 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -107,7 +107,7 @@ type QueuedChatMessage = { reasoningEffort: ReasoningEffort } -const CHAT_QUEUE_LIMIT = 5 +const CHAT_QUEUE_LIMIT = 3 function normalizeModelId(value: unknown): ModelId | null { if (typeof value !== "string") return null @@ -1274,6 +1274,7 @@ export function ChatSidebar({ ? cn( "flex flex-col space-y-3 min-h-full justify-end", isPageDesktop || isMobile ? "pt-2" : "pt-14", + isStackedInput && "px-4", ) : "" } @@ -1423,8 +1424,7 @@ export function ChatSidebar({ ? "Structuring response…" : "Waiting for input…" } - queuedMessagePreview={messageQueue[0]?.text ?? null} - queuedMessageCount={messageQueue.length} + queuedMessages={messageQueue} showStatusStrip={showInputStatusStrip} onExpandedChange={setIsInputExpanded} chainOfThoughtComponent={ diff --git a/apps/web/components/chat/input/actions.tsx b/apps/web/components/chat/input/actions.tsx index b193a872..10a1c914 100644 --- a/apps/web/components/chat/input/actions.tsx +++ b/apps/web/components/chat/input/actions.tsx @@ -33,7 +33,7 @@ export function SendButton({ Send Icon diff --git a/apps/web/components/chat/input/index.tsx b/apps/web/components/chat/input/index.tsx index 5e6a7219..6a82b476 100644 --- a/apps/web/components/chat/input/index.tsx +++ b/apps/web/components/chat/input/index.tsx @@ -1,12 +1,24 @@ "use client" -import { ChevronUpIcon } from "lucide-react" +import { BrainIcon, ChevronUpIcon, ZapIcon } from "lucide-react" import NovaOrb from "@/components/nova/nova-orb" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" import { type ReactNode, useEffect, useRef, useState } from "react" -import { motion } from "motion/react" +import { AnimatePresence, motion } from "motion/react" import { SendButton, StopButton } from "./actions" +import { + type ModelId, + modelNames, + type ReasoningEffort, +} from "@/lib/models" + +export interface QueuedChatMessagePreview { + id: string + text: string + model: ModelId + reasoningEffort: ReasoningEffort +} interface ChatInputProps { value: string @@ -18,8 +30,7 @@ interface ChatInputProps { sendDisabled?: boolean sendDisabledTooltip?: string activeStatus?: string - queuedMessagePreview?: string | null - queuedMessageCount?: number + queuedMessages?: QueuedChatMessagePreview[] chainOfThoughtComponent?: React.ReactNode onExpandedChange?: (expanded: boolean) => void /** Model + space controls on one row with send; textarea full-width above */ @@ -38,8 +49,7 @@ export default function ChatInput({ sendDisabled = false, sendDisabledTooltip, activeStatus, - queuedMessagePreview, - queuedMessageCount = 0, + queuedMessages = [], chainOfThoughtComponent, onExpandedChange, stackedToolbar, @@ -49,7 +59,7 @@ export default function ChatInput({ const [isExpanded, setIsExpanded] = useState(false) const textareaRef = useRef(null) const isSendDisabled = !value.trim() || sendDisabled - const hasQueuedPreview = !!queuedMessagePreview && queuedMessageCount > 0 + const hasQueuedPreview = queuedMessages.length > 0 const resolvedSendDisabledTooltip = sendDisabled && value.trim() ? sendDisabledTooltip @@ -142,36 +152,61 @@ export default function ChatInput({ )} {hasQueuedPreview && ( - -
- - QUEUED - - - {queuedMessagePreview} - - {queuedMessageCount > 1 && ( - - +{queuedMessageCount - 1} - - )} -
-
+
+ + {queuedMessages.map((queued) => { + const model = modelNames[queued.model] + const ReasoningIcon = + queued.reasoningEffort === "thinking" + ? BrainIcon + : ZapIcon + const reasoningLabel = + queued.reasoningEffort === "thinking" + ? "Thinking" + : "Instant" + return ( + +
+ + {queued.text} + + + + {model.name} {model.version} + + · + + {reasoningLabel} + +
+
+ ) + })} +
+
)} ) : null} {stackedToolbar ? ( -
+