@@ -102,7 +102,6 @@ function ContentArea({
102102 const { agentName, updateParams } = useSafeSearchParams ( ) ;
103103 const [ prompt , setPrompt ] = useState < string > ( '' ) ;
104104 const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
105- const [ autoScrollEnabled , setAutoScrollEnabled ] = useState ( true ) ;
106105 const [ showScrollButton , setShowScrollButton ] = useState ( false ) ;
107106 const [ localAgentName , setLocalAgentName ] = useLocalStorageState <
108107 string | undefined
@@ -117,9 +116,6 @@ function ContentArea({
117116 // eslint-disable-next-line react-hooks/exhaustive-deps
118117 } , [ isLoading ] ) ;
119118
120- // Show thread view when we have a task ID
121- const inThread = ! ! taskID ;
122-
123119 const handleSelectAgent = useCallback (
124120 ( agentName : string | undefined ) => {
125121 updateParams ( {
@@ -134,7 +130,10 @@ function ContentArea({
134130 // Scroll detection - track if user is near bottom
135131 useEffect ( ( ) => {
136132 const container = scrollContainerRef . current ;
137- if ( ! container ) return ;
133+ if ( ! container ) {
134+ setShowScrollButton ( false ) ;
135+ return ;
136+ }
138137
139138 const handleScroll = ( ) => {
140139 const { scrollTop, scrollHeight, clientHeight } = container ;
@@ -143,38 +142,28 @@ function ContentArea({
143142 const scrollThreshold = 100 ; // pixels from bottom
144143 const isNearBottom = distanceFromBottom < scrollThreshold ;
145144
146- setAutoScrollEnabled ( isNearBottom ) ;
147145 setShowScrollButton ( ! isNearBottom ) ;
148146 } ;
149147
150148 container . addEventListener ( 'scroll' , handleScroll ) ;
151149 return ( ) => container . removeEventListener ( 'scroll' , handleScroll ) ;
152- } , [ inThread ] ) ;
150+ } , [ taskID ] ) ;
151+
152+ const scrollToBottom = useCallback ( ( ) => {
153+ if ( ! scrollContainerRef . current ) return ;
154+ scrollContainerRef . current . scrollTo ( {
155+ top : scrollContainerRef . current . scrollHeight ,
156+ behavior : 'smooth' ,
157+ } ) ;
158+ } , [ scrollContainerRef ] ) ;
153159
154- // Scroll to absolute bottom when task loads or changes
155160 useEffect ( ( ) => {
156161 if ( scrollContainerRef . current && taskID ) {
157- // Use a small delay to ensure content is rendered and heights are calculated
158162 setTimeout ( ( ) => {
159- if ( scrollContainerRef . current ) {
160- // Scroll to the maximum possible scroll position (includes blank space)
161- scrollContainerRef . current . scrollTo ( {
162- top : scrollContainerRef . current . scrollHeight ,
163- behavior : 'smooth' ,
164- } ) ;
165- }
163+ scrollToBottom ( ) ;
166164 } , 150 ) ;
167165 }
168- } , [ taskID ] ) ;
169-
170- // Scroll to bottom handler for button
171- const scrollToBottom = ( ) => {
172- scrollContainerRef . current ?. scrollTo ( {
173- top : scrollContainerRef . current . scrollHeight ,
174- behavior : 'smooth' ,
175- } ) ;
176- setAutoScrollEnabled ( true ) ; // Re-enable auto-scroll when user clicks button
177- } ;
166+ } , [ scrollToBottom , taskID ] ) ;
178167
179168 return (
180169 < AnimatePresence >
@@ -183,7 +172,6 @@ function ContentArea({
183172 className = { `relative flex h-full flex-1 flex-col ${ ! taskID ? 'justify-center' : 'justify-between' } ` }
184173 transition = { { duration : 0.25 , ease : 'easeInOut' } }
185174 >
186- { /* Top Bar */ }
187175 { taskID && agentName && (
188176 < motion . div
189177 key = "topbar"
@@ -201,7 +189,6 @@ function ContentArea({
201189 </ motion . div >
202190 ) }
203191
204- { /* Content Area */ }
205192 { taskID ? (
206193 < motion . div
207194 key = "chat-view"
@@ -215,10 +202,7 @@ function ContentArea({
215202 < div className = "flex min-h-full w-full flex-col items-center px-4 sm:px-6 md:px-8" >
216203 < div className = "w-full max-w-3xl" >
217204 < TaskProvider taskId = { taskID } >
218- < MemoizedTaskMessagesComponent
219- taskId = { taskID }
220- autoScrollEnabled = { autoScrollEnabled }
221- />
205+ < MemoizedTaskMessagesComponent taskId = { taskID } />
222206 </ TaskProvider >
223207 </ div >
224208 </ div >
@@ -249,37 +233,9 @@ function ContentArea({
249233 </ motion . div >
250234 ) }
251235
252- { /* Scroll to bottom button */ }
253- { taskID && (
254- < AnimatePresence >
255- { showScrollButton && (
256- < motion . div
257- className = "pointer-events-none absolute bottom-28 left-1/2 -translate-x-1/2"
258- initial = { { y : 30 , opacity : 0 } }
259- animate = { { y : 0 , opacity : 1 } }
260- exit = { { y : 30 , opacity : 0 } }
261- transition = { {
262- duration : 0.2 ,
263- type : 'spring' ,
264- stiffness : 300 ,
265- damping : 35 ,
266- mass : 0.8 ,
267- } }
268- >
269- < IconButton
270- className = "pointer-events-auto size-10 rounded-full shadow-lg"
271- onClick = { scrollToBottom }
272- icon = { ArrowDown }
273- />
274- </ motion . div >
275- ) }
276- </ AnimatePresence >
277- ) }
278-
279- { /* Prompt Input */ }
280236 < motion . div
281237 layout = "position"
282- className = "flex w-full justify-center px-4 py-4 sm:px-6 md:px-8"
238+ className = "relative flex w-full justify-center px-4 py-4 sm:px-6 md:px-8"
283239 transition = { {
284240 layout : {
285241 type : 'spring' ,
@@ -289,6 +245,32 @@ function ContentArea({
289245 } ,
290246 } }
291247 >
248+ { taskID && (
249+ < AnimatePresence >
250+ { showScrollButton && (
251+ < motion . div
252+ className = "pointer-events-none absolute bottom-full left-1/2 z-10 mb-4 -translate-x-1/2"
253+ initial = { { y : 30 , opacity : 0 } }
254+ animate = { { y : 0 , opacity : 1 } }
255+ exit = { { y : 30 , opacity : 0 } }
256+ transition = { {
257+ duration : 0.2 ,
258+ type : 'spring' ,
259+ stiffness : 300 ,
260+ damping : 35 ,
261+ mass : 0.8 ,
262+ } }
263+ >
264+ < IconButton
265+ className = "pointer-events-auto size-10 rounded-full shadow-lg"
266+ onClick = { scrollToBottom }
267+ icon = { ArrowDown }
268+ />
269+ </ motion . div >
270+ ) }
271+ </ AnimatePresence >
272+ ) }
273+
292274 < div className = "w-full max-w-3xl" >
293275 < PromptInput prompt = { prompt } setPrompt = { setPrompt } />
294276 </ div >
0 commit comments