diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx index e2fd573fe8ce..6af2a007accf 100644 --- a/apps/web/src/components/ChatView.browser.tsx +++ b/apps/web/src/components/ChatView.browser.tsx @@ -814,7 +814,7 @@ describe("ChatView timeline estimator parity (full app)", () => { try { const initialModeButton = await waitForInteractionModeButton("Chat"); - expect(initialModeButton.title).toContain("enter plan mode"); + expect(initialModeButton.getAttribute("title")).toBeNull(); window.dispatchEvent( new KeyboardEvent("keydown", { @@ -826,7 +826,7 @@ describe("ChatView timeline estimator parity (full app)", () => { ); await waitForLayout(); - expect((await waitForInteractionModeButton("Chat")).title).toContain("enter plan mode"); + expect(await waitForInteractionModeButton("Chat")).toBeTruthy(); const composerEditor = await waitForComposerEditor(); composerEditor.focus(); @@ -841,9 +841,8 @@ describe("ChatView timeline estimator parity (full app)", () => { await vi.waitFor( async () => { - expect((await waitForInteractionModeButton("Plan")).title).toContain( - "return to normal chat mode", - ); + const planButton = await waitForInteractionModeButton("Plan"); + expect(planButton.getAttribute("title")).toBeNull(); }, { timeout: 8_000, interval: 16 }, ); @@ -859,7 +858,8 @@ describe("ChatView timeline estimator parity (full app)", () => { await vi.waitFor( async () => { - expect((await waitForInteractionModeButton("Chat")).title).toContain("enter plan mode"); + const chatButton = await waitForInteractionModeButton("Chat"); + expect(chatButton.getAttribute("title")).toBeNull(); }, { timeout: 8_000, interval: 16 }, ); diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 51b300ba8ec2..c907ba6ac3cc 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -31,6 +31,8 @@ import { } from "@t3tools/shared/model"; import { memo, + type ComponentProps, + type ReactNode, useCallback, useEffect, useLayoutEffect, @@ -251,6 +253,7 @@ function formatWorkingTimer(startIso: string, endIso: string): string | null { return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`; } + const LAST_EDITOR_KEY = "t3code:last-editor"; const LAST_INVOKED_SCRIPT_BY_PROJECT_KEY = "t3code:last-invoked-script-by-project"; const MAX_VISIBLE_WORK_LOG_ENTRIES = 6; @@ -3720,49 +3723,85 @@ export default function ChatView({ threadId }: ChatViewProps) { {/* Interaction mode toggle */} - + + + + + {interactionMode === "plan" ? "Plan" : "Chat"} + + + } + /> + + + + {interactionMode === "plan" + ? "Plan mode — click to return to normal chat mode" + : "Default mode — click to enter plan mode"} + + + ⇧ + Tab + + + + {/* Divider */} {/* Runtime mode toggle */} - + } + /> + + {runtimeMode === "full-access" ? "Full access — click to require approvals" - : "Approval required — click for full access" - } - > - {runtimeMode === "full-access" ? : } - - {runtimeMode === "full-access" ? "Full access" : "Supervised"} - - + : "Approval required — click for full access"} + + {/* Plan sidebar toggle */} {(activePlan || activeProposedPlan || planSidebarOpen) ? ( diff --git a/apps/web/src/components/ui/tooltip.tsx b/apps/web/src/components/ui/tooltip.tsx index f41c4520075c..3bd799bf6916 100644 --- a/apps/web/src/components/ui/tooltip.tsx +++ b/apps/web/src/components/ui/tooltip.tsx @@ -9,7 +9,16 @@ const TooltipProvider = TooltipPrimitive.Provider; const Tooltip = TooltipPrimitive.Root; function TooltipTrigger(props: TooltipPrimitive.Trigger.Props) { - return ; + const { delay = 120, closeDelay = 80, ...restProps } = props; + + return ( + + ); } function TooltipPopup({ @@ -38,7 +47,7 @@ function TooltipPopup({ >