@@ -11,7 +11,7 @@ import {
1111 useRef ,
1212 useState ,
1313} from 'react'
14- import { Button } from '@sim/emcn'
14+ import { Button , cn } from '@sim/emcn'
1515import { PanelLeft } from '@sim/emcn/icons'
1616import { createLogger } from '@sim/logger'
1717import { useParams , useRouter } from 'next/navigation'
@@ -411,70 +411,85 @@ export function Home({ chatId, userName, userId }: HomeProps) {
411411 const showChatSkeleton = Boolean ( chatId ) && ! hasMessages && isChatHistoryPending
412412 const draftScopeKey = `${ workspaceId } :${ chatId ?? 'new' } `
413413
414- if ( ! hasMessages && ! showChatSkeleton ) {
415- return (
416- < div className = 'relative h-full overflow-y-auto bg-[var(--bg)] [scrollbar-gutter:stable_both-edges]' >
417- < div className = 'absolute top-[8.5px] right-[16px] z-10' >
418- < CreditsChip />
419- </ div >
420- { /* Asymmetric padding biases the group up so the full cluster (heading + input + suggestions) sits at the optical center */ }
421- < div className = 'flex min-h-full flex-col items-center justify-center px-6 pt-[2vh] pb-[22vh]' >
422- < h1 className = 'mb-7 max-w-[48rem] text-balance font-season text-[30px] text-[var(--text-primary)]' >
423- What should we get done{ firstName ? `, ${ firstName } ` : '' } ?
424- </ h1 >
425- < div ref = { initialViewInputRef } className = 'relative w-full max-w-[48rem]' >
426- < ChatSurfaceProvider
427- userId = { userId }
428- onContextAdd = { handleContextAdd }
429- onContextRemove = { handleInitialContextRemove }
430- >
431- < UserInput
432- ref = { initialViewUserInputRef }
433- defaultValue = { initialPrompt }
434- draftScopeKey = { draftScopeKey }
435- onSubmit = { handleSubmit }
436- isSending = { isSending }
437- onStopGeneration = { handleStopGeneration }
438- />
439- </ ChatSurfaceProvider >
440- { /* Anchored out of flow so expanding/collapsing never shifts the centered input */ }
441- < div className = 'absolute inset-x-0 top-full' >
442- < SuggestedActions
443- onSelectPrompt = { ( prompt ) => initialViewUserInputRef . current ?. populatePrompt ( prompt ) }
444- />
445- </ div >
446- </ div >
447- </ div >
448- </ div >
449- )
450- }
414+ // The empty state is the chat pane's content, not a layout of its own. It
415+ // used to return early, which meant the resource panel and its toggle did
416+ // not exist until the first message — so there was no way to open a resource
417+ // while composing the very prompt that needed one.
418+ const showEmptyState = ! hasMessages && ! showChatSkeleton
451419
452420 return (
453421 < div className = 'relative flex h-full bg-[var(--bg)]' >
454- < div className = 'flex h-full min-w-[320px] flex-1 flex-col' >
455- < MothershipChat
456- messages = { messages }
457- isSending = { isSending }
458- isReconnecting = { isReconnecting }
459- isLoading = { showChatSkeleton }
460- onSubmit = { handleSubmit }
461- onStopGeneration = { handleStopGeneration }
462- messageQueue = { messageQueue }
463- editingQueuedId = { editingQueuedId }
464- dispatchingHeadId = { dispatchingHeadId }
465- onRemoveQueuedMessage = { removeFromQueue }
466- onSendQueuedMessage = { sendNow }
467- onEditQueuedMessage = { editQueuedMessage }
468- onCancelQueueEdit = { cancelQueueEdit }
469- userId = { userId }
470- chatId = { resolvedChatId }
471- onContextAdd = { handleContextAdd }
472- onWorkspaceResourceSelect = { handleWorkspaceResourceSelect }
473- draftScopeKey = { draftScopeKey }
474- animateInput = { isInputEntering }
475- onInputAnimationEnd = { isInputEntering ? ( ) => setIsInputEntering ( false ) : undefined }
476- initialScrollBlocked = { resources . length > 0 && isResourceCollapsed }
477- />
422+ < div className = 'relative flex h-full min-w-[320px] flex-1 flex-col' >
423+ { /* Clears the expand button when the panel is closed and that button is
424+ occupying the same corner. */ }
425+ { showEmptyState && (
426+ < div
427+ className = { cn (
428+ 'absolute top-[8.5px] z-10' ,
429+ isResourceCollapsed ? 'right-[54px]' : 'right-[16px]'
430+ ) }
431+ >
432+ < CreditsChip />
433+ </ div >
434+ ) }
435+ { showEmptyState ? (
436+ < div className = 'h-full overflow-y-auto [scrollbar-gutter:stable_both-edges]' >
437+ { /* Asymmetric padding biases the group up so the full cluster (heading + input + suggestions) sits at the optical center */ }
438+ < div className = 'flex min-h-full flex-col items-center justify-center px-6 pt-[2vh] pb-[22vh]' >
439+ < h1 className = 'mb-7 max-w-[48rem] text-balance font-season text-[30px] text-[var(--text-primary)]' >
440+ What should we get done{ firstName ? `, ${ firstName } ` : '' } ?
441+ </ h1 >
442+ < div ref = { initialViewInputRef } className = 'relative w-full max-w-[48rem]' >
443+ < ChatSurfaceProvider
444+ userId = { userId }
445+ onContextAdd = { handleContextAdd }
446+ onContextRemove = { handleInitialContextRemove }
447+ >
448+ < UserInput
449+ ref = { initialViewUserInputRef }
450+ defaultValue = { initialPrompt }
451+ draftScopeKey = { draftScopeKey }
452+ onSubmit = { handleSubmit }
453+ isSending = { isSending }
454+ onStopGeneration = { handleStopGeneration }
455+ />
456+ </ ChatSurfaceProvider >
457+ { /* Anchored out of flow so expanding/collapsing never shifts the centered input */ }
458+ < div className = 'absolute inset-x-0 top-full' >
459+ < SuggestedActions
460+ onSelectPrompt = { ( prompt ) =>
461+ initialViewUserInputRef . current ?. populatePrompt ( prompt )
462+ }
463+ />
464+ </ div >
465+ </ div >
466+ </ div >
467+ </ div >
468+ ) : (
469+ < MothershipChat
470+ messages = { messages }
471+ isSending = { isSending }
472+ isReconnecting = { isReconnecting }
473+ isLoading = { showChatSkeleton }
474+ onSubmit = { handleSubmit }
475+ onStopGeneration = { handleStopGeneration }
476+ messageQueue = { messageQueue }
477+ editingQueuedId = { editingQueuedId }
478+ dispatchingHeadId = { dispatchingHeadId }
479+ onRemoveQueuedMessage = { removeFromQueue }
480+ onSendQueuedMessage = { sendNow }
481+ onEditQueuedMessage = { editQueuedMessage }
482+ onCancelQueueEdit = { cancelQueueEdit }
483+ userId = { userId }
484+ chatId = { resolvedChatId }
485+ onContextAdd = { handleContextAdd }
486+ onWorkspaceResourceSelect = { handleWorkspaceResourceSelect }
487+ draftScopeKey = { draftScopeKey }
488+ animateInput = { isInputEntering }
489+ onInputAnimationEnd = { isInputEntering ? ( ) => setIsInputEntering ( false ) : undefined }
490+ initialScrollBlocked = { resources . length > 0 && isResourceCollapsed }
491+ />
492+ ) }
478493 </ div >
479494
480495 { /* Resize handle — zero-width flex child whose absolute child straddles the border */ }
0 commit comments