@@ -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
18481866function 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
22332264function 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