Skip to content

Commit 0c7a757

Browse files
Merge pull request #632 from OpenSecretCloud/codex-review-maple-issue-631-maple
Agent Mode: match chat composer sizing
2 parents c5bd692 + f817909 commit 0c7a757

1 file changed

Lines changed: 83 additions & 15 deletions

File tree

frontend/src/components/AgentMode.tsx

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import {
1010
ChevronLeft,
1111
ChevronRight,
1212
Circle,
13+
Expand,
1314
FolderOpen,
1415
Loader2,
1516
Lock,
1617
MessageSquarePlus,
1718
MoreHorizontal,
1819
ShieldCheck,
20+
Shrink,
1921
Trash,
2022
X,
2123
Zap
@@ -250,6 +252,9 @@ export function AgentMode({ userId }: { userId: string }) {
250252
const [isSessionMcpServersLoading, setIsSessionMcpServersLoading] = useState(false);
251253
const [isMcpServerTogglePending, setIsMcpServerTogglePending] = useState(false);
252254
const [input, setInput] = useState("");
255+
const [isAgentFullscreen, setIsAgentFullscreen] = useState(
256+
() => localStorage.getItem("agentFullscreen") === "true"
257+
);
253258
const [error, setError] = useState<string | null>(null);
254259
const [hasManualProxyConflict, setHasManualProxyConflict] = useState(false);
255260
const [isAuthTransitionReady, setIsAuthTransitionReady] = useState(false);
@@ -303,6 +308,10 @@ export function AgentMode({ userId }: { userId: string }) {
303308
activeSessionIdRef.current = activeSessionId;
304309
}, [activeSessionId]);
305310

311+
useEffect(() => {
312+
localStorage.setItem("agentFullscreen", isAgentFullscreen.toString());
313+
}, [isAgentFullscreen]);
314+
306315
const updateAutoScrollFromPosition = useCallback(() => {
307316
const container = chatContainerRef.current;
308317
if (!container) return;
@@ -1765,7 +1774,14 @@ export function AgentMode({ userId }: { userId: string }) {
17651774
className="relative flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain"
17661775
onScroll={updateAutoScrollFromPosition}
17671776
>
1768-
<div className="mx-auto w-full max-w-4xl p-4 md:p-6 landscape-short:p-2">
1777+
<div
1778+
className={cn(
1779+
"mx-auto w-full p-4 md:p-6 landscape-short:p-2",
1780+
timelineItems.length === 0 && isAgentFullscreen
1781+
? "flex min-h-full max-w-6xl flex-col"
1782+
: "max-w-4xl"
1783+
)}
1784+
>
17691785
{timelineItems.length === 0 ? (
17701786
<EmptyAgentState
17711787
activeRootLabel={activeRootLabel}
@@ -1782,6 +1798,7 @@ export function AgentMode({ userId }: { userId: string }) {
17821798
model={model}
17831799
projectRoot={projectRoot}
17841800
recentRoots={recentRoots}
1801+
isExpanded={isAgentFullscreen}
17851802
onCancelPrompt={cancelPrompt}
17861803
onChooseProjectRoot={chooseProjectRoot}
17871804
onInputChange={setInput}
@@ -1792,6 +1809,7 @@ export function AgentMode({ userId }: { userId: string }) {
17921809
onModelChange={selectModel}
17931810
onProjectRootChange={selectProjectRoot}
17941811
onSendMessage={() => void sendMessage()}
1812+
onToggleExpanded={() => setIsAgentFullscreen((current) => !current)}
17951813
/>
17961814
) : (
17971815
<AgentTimeline
@@ -1846,17 +1864,28 @@ export function AgentMode({ userId }: { userId: string }) {
18461864
}
18471865

18481866
function EmptyAgentState(props: AgentComposerProps) {
1867+
const isExpanded = props.isExpanded ?? false;
1868+
18491869
return (
1850-
<div className="flex min-h-[52vh] items-center justify-center">
1851-
<div className="flex w-full max-w-4xl flex-col items-center gap-6 text-center landscape-short:gap-3">
1852-
<h1 className="mb-6 overflow-visible pb-1 font-displayWide text-4xl font-normal leading-relaxed brand-gradient-text landscape-short:mb-2 landscape-short:text-2xl">
1853-
Work in a folder...
1854-
</h1>
1870+
<div
1871+
className={cn(
1872+
"flex items-center justify-center",
1873+
isExpanded ? "min-h-0 flex-1" : "min-h-[52vh]"
1874+
)}
1875+
>
1876+
<div className="flex w-full flex-col items-center gap-6 text-center landscape-short:gap-3">
1877+
{!isExpanded ? (
1878+
<h1 className="mb-6 overflow-visible pb-1 font-displayWide text-4xl font-normal leading-relaxed brand-gradient-text landscape-short:mb-2 landscape-short:text-2xl">
1879+
Work in a folder...
1880+
</h1>
1881+
) : null}
18551882
<AgentComposer {...props} />
1856-
<p className="flex items-center justify-center gap-1 text-center text-xs text-muted-foreground/60">
1857-
<Lock className="h-3 w-3" />
1858-
Encrypted and private at every step
1859-
</p>
1883+
{!isExpanded ? (
1884+
<p className="flex items-center justify-center gap-1 text-center text-xs text-muted-foreground/60">
1885+
<Lock className="h-3 w-3" />
1886+
Encrypted and private at every step
1887+
</p>
1888+
) : null}
18601889
</div>
18611890
</div>
18621891
);
@@ -2218,6 +2247,7 @@ interface AgentComposerProps {
22182247
model: string;
22192248
projectRoot: string;
22202249
recentRoots: RecentProjectRoot[];
2250+
isExpanded?: boolean;
22212251
onCancelPrompt: () => void;
22222252
onChooseProjectRoot: () => void;
22232253
onInputChange: (value: string) => void;
@@ -2228,6 +2258,7 @@ interface AgentComposerProps {
22282258
onModelChange: (value: string) => void;
22292259
onProjectRootChange: (value: string) => void;
22302260
onSendMessage: () => void;
2261+
onToggleExpanded?: () => void;
22312262
}
22322263

22332264
function AgentComposer({
@@ -2245,6 +2276,7 @@ function AgentComposer({
22452276
model,
22462277
projectRoot,
22472278
recentRoots,
2279+
isExpanded = false,
22482280
onCancelPrompt,
22492281
onChooseProjectRoot,
22502282
onInputChange,
@@ -2254,28 +2286,64 @@ function AgentComposer({
22542286
onModeChange,
22552287
onModelChange,
22562288
onProjectRootChange,
2257-
onSendMessage
2289+
onSendMessage,
2290+
onToggleExpanded
22582291
}: AgentComposerProps) {
2292+
const textareaRef = useRef<HTMLTextAreaElement>(null);
22592293
const rootOptions = recentRoots.some((root) => root.path === projectRoot)
22602294
? recentRoots
22612295
: projectRoot
22622296
? [{ path: projectRoot, name: activeRootLabel, lastUsedMs: Date.now() }, ...recentRoots]
22632297
: recentRoots;
22642298

2299+
useLayoutEffect(() => {
2300+
const textarea = textareaRef.current;
2301+
if (!textarea) return;
2302+
2303+
if (isExpanded) {
2304+
textarea.style.height = "";
2305+
return;
2306+
}
2307+
2308+
textarea.style.height = "auto";
2309+
textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
2310+
}, [input, isExpanded]);
2311+
22652312
return (
2266-
<ChatComposerSurface>
2313+
<ChatComposerSurface
2314+
className={cn(
2315+
"transition-all duration-300",
2316+
isExpanded && "flex h-[70vh] max-h-[800px] min-h-0 flex-col"
2317+
)}
2318+
>
2319+
{onToggleExpanded ? (
2320+
<button
2321+
type="button"
2322+
onClick={onToggleExpanded}
2323+
className="absolute right-2 top-2 z-10 rounded-full p-1.5 text-muted-foreground/60 transition-colors hover:bg-muted/50 hover:text-foreground"
2324+
aria-label={isExpanded ? "Exit fullscreen" : "Enter fullscreen"}
2325+
>
2326+
{isExpanded ? <Shrink className="h-4 w-4" /> : <Expand className="h-4 w-4" />}
2327+
</button>
2328+
) : null}
22672329
<Textarea
2330+
ref={textareaRef}
22682331
id="agent-message"
22692332
value={input}
22702333
onChange={(event) => onInputChange(event.target.value)}
22712334
onKeyDown={onKeyDown}
22722335
disabled={isSendDisabled}
22732336
placeholder="Ask Maple to work in this folder..."
2274-
className={CHAT_COMPOSER_TEXTAREA_CLASS}
2275-
rows={1}
2337+
className={cn(
2338+
CHAT_COMPOSER_TEXTAREA_CLASS,
2339+
onToggleExpanded && "pr-8",
2340+
isExpanded &&
2341+
"min-h-0 max-h-none flex-1 overflow-y-auto landscape-short:min-h-0 landscape-short:max-h-none"
2342+
)}
2343+
rows={isExpanded ? undefined : 1}
22762344
/>
22772345

2278-
<div className="grid grid-cols-[minmax(0,1fr)_auto] items-end gap-x-2 gap-y-2 px-2 pb-2 pt-1">
2346+
<div className="grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-end gap-x-2 gap-y-2 px-2 pb-2 pt-1">
22792347
<div className="flex min-w-0 flex-wrap items-center gap-1.5 sm:gap-2">
22802348
<AgentModelSelector
22812349
disabled={isModelSelectionDisabled}

0 commit comments

Comments
 (0)