setIsHovering(true)}
onPointerLeave={() => setIsHovering(false)}
>
{/* Collapsed: Single-line prompt bar with optional suggestions */}
{!isExpanded && (
{/* Main input row */}
{/* Mushroom + Brain icon with selection count badge */}
ππ§
{selectionInfo && (
{selectionInfo.count}
)}
{/* Input field - context-aware placeholder */}
setPrompt(e.target.value)}
onKeyDown={(e) => {
e.stopPropagation()
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
// Direct tool input mode if single tool selected
if (selectedToolInfo?.promptInfo.canDirectInput && prompt.trim()) {
handleDirectToolInput(prompt.trim())
} else {
handleSubmit()
}
}
}}
onPointerDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
onFocus={(e) => e.stopPropagation()}
placeholder={
selectedToolInfo
? selectedToolInfo.promptInfo.placeholder
: selectionInfo && selectionInfo.count > 1
? `${selectionInfo.count} selected β try a suggestion below...`
: "Ask mi anything about this workspace..."
}
style={{
flex: 1,
background: 'transparent',
border: 'none',
padding: '8px 4px',
fontSize: '14px',
color: colors.inputText,
outline: 'none',
}}
/>
{/* Indexing indicator */}
{isIndexing && (
{Math.round(indexingProgress)}%
)}
{/* Voice button (compact) */}
{isVoiceSupported && (
{
e.stopPropagation()
toggleVoice()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
width: '34px',
height: '34px',
borderRadius: '50%',
border: 'none',
background: isRecording
? `rgba(16, 185, 129, 0.15)`
: 'transparent',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: isRecording ? ACCENT_COLOR : colors.textMuted,
transition: 'all 0.2s ease',
flexShrink: 0,
}}
title={isRecording ? "Stop recording" : "Voice input"}
>
)}
{/* Send button - shows tool-specific label when tool selected */}
{
e.stopPropagation()
if (selectedToolInfo?.promptInfo.canDirectInput && prompt.trim()) {
handleDirectToolInput(prompt.trim())
} else {
handleSubmit()
}
}}
onPointerDown={(e) => e.stopPropagation()}
disabled={!prompt.trim() || isLoading}
style={{
height: '34px',
padding: selectedToolInfo ? '0 12px' : '0 14px',
borderRadius: '17px',
border: 'none',
background: prompt.trim() && !isLoading
? selectedToolInfo ? '#6366f1' : ACCENT_COLOR
: colors.inputBg,
cursor: prompt.trim() && !isLoading ? 'pointer' : 'default',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '4px',
color: prompt.trim() && !isLoading ? 'white' : colors.textMuted,
transition: 'all 0.2s ease',
flexShrink: 0,
opacity: prompt.trim() && !isLoading ? 1 : 0.5,
fontSize: '11px',
fontWeight: 500,
}}
title={selectedToolInfo?.promptInfo.inputLabel || "Send"}
>
{selectedToolInfo && prompt.trim() ? (
<>
β
{selectedToolInfo.promptInfo.inputLabel}
>
) : (
)}
{/* Expand button if there's history */}
{conversationHistory.length > 0 && (
{
e.stopPropagation()
toggleExpand()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
width: '34px',
height: '34px',
borderRadius: '50%',
border: 'none',
background: 'transparent',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: ACCENT_COLOR,
transition: 'all 0.2s',
flexShrink: 0,
}}
title="View conversation"
>
)}
{/* Prompt suggestions row - context-aware */}
{/* Show tool-specific help when single tool selected */}
{selectedToolInfo && (
e.stopPropagation()}
>
handleSuggestionClick(selectedToolInfo.promptInfo.helpPrompt)}
/>
handleSuggestionClick(`Use content from my canvas to help fill this ${selectedToolInfo.toolType}`)}
/>
)}
{/* Show transform suggestions when multiple shapes selected */}
{!selectedToolInfo && selectionInfo && selectionInfo.count > 1 && (
e.stopPropagation()}
>
{SELECTION_SUGGESTIONS.slice(0, 5).map((suggestion) => (
handleSuggestionClick(suggestion.prompt)}
/>
))}
)}
)}
{/* Expanded: Header + Conversation + Input */}
{isExpanded && (
<>
{/* Header */}
ππ§
ask your mycelial intelligence anything about this workspace
{isIndexing && (
Indexing... {Math.round(indexingProgress)}%
)}
{
e.stopPropagation()
toggleExpand()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
background: 'transparent',
border: 'none',
cursor: 'pointer',
color: colors.textMuted,
padding: '4px',
borderRadius: '6px',
display: 'flex',
alignItems: 'center',
transition: 'all 0.2s',
}}
title="Collapse"
>
{/* Conversation area */}
e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
>
{conversationHistory.length === 0 && !streamingResponse && (
I'm your Mycelial Intelligence β the awareness connecting all shapes and ideas in your workspace.
Ask me about what's on your canvas, how to use the tools, or what connections I perceive between your ideas.
)}
{conversationHistory.map((msg, idx) => (
{/* Tool suggestions for assistant messages */}
{msg.role === 'assistant' && msg.suggestedTools && msg.suggestedTools.length > 0 && (
Suggested Tools
{msg.suggestedTools.length > 1 && (
{
e.stopPropagation()
handleSpawnAllTools()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
fontSize: '11px',
padding: '4px 10px',
borderRadius: '8px',
border: `1px solid ${ACCENT_COLOR}`,
background: 'transparent',
color: ACCENT_COLOR,
cursor: 'pointer',
fontWeight: 500,
transition: 'all 0.2s ease',
}}
title="Spawn all suggested tools on canvas"
>
Spawn All
)}
{msg.suggestedTools.map((tool) => (
))}
)}
))}
{/* Streaming response */}
{streamingResponse && (
<>
{renderMessageContent(streamingResponse)}
{isLoading && (
)}
>
)}
{/* Loading indicator */}
{isLoading && !streamingResponse && (
)}
{/* Combined "Try next" section - tools + follow-up suggestions in one scrollable row */}
{!isLoading && (followUpSuggestions.length > 0 || suggestedTools.length > 0) && (
β¨
Try next
{suggestedTools.length > 1 && (
{
e.stopPropagation()
handleSpawnAllTools()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
fontSize: '10px',
padding: '3px 8px',
borderRadius: '6px',
border: `1px solid ${ACCENT_COLOR}`,
background: 'transparent',
color: ACCENT_COLOR,
cursor: 'pointer',
fontWeight: 500,
transition: 'all 0.2s ease',
}}
title="Spawn all suggested tools on canvas"
>
Spawn All
)}
{/* Suggested tools first */}
{suggestedTools.map((tool) => (
))}
{/* Then follow-up prompts */}
{followUpSuggestions.map((suggestion, i) => (
handleSuggestionClick(suggestion.prompt)}
/>
))}
)}
{/* Input area (expanded) */}
setPrompt(e.target.value)}
onKeyDown={(e) => {
e.stopPropagation()
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
handleSubmit()
}
}}
onPointerDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
onFocus={(e) => e.stopPropagation()}
placeholder="Ask a follow-up..."
style={{
flex: 1,
background: colors.inputBg,
border: `1px solid ${colors.inputBorder}`,
borderRadius: '18px',
padding: '8px 14px',
fontSize: '13px',
color: colors.inputText,
outline: 'none',
transition: 'all 0.2s ease',
}}
/>
{/* Voice input button */}
{isVoiceSupported && (
{
e.stopPropagation()
toggleVoice()
}}
onPointerDown={(e) => e.stopPropagation()}
style={{
width: '36px',
height: '36px',
borderRadius: '50%',
border: `1px solid ${isRecording ? ACCENT_COLOR : colors.inputBorder}`,
background: isRecording
? `rgba(16, 185, 129, 0.1)`
: colors.inputBg,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: isRecording ? ACCENT_COLOR : colors.textMuted,
transition: 'all 0.2s ease',
boxShadow: isRecording ? `0 0 12px rgba(16, 185, 129, 0.3)` : 'none',
flexShrink: 0,
}}
title={isRecording ? "Stop recording" : "Start voice input"}
>
)}
{/* Send button */}
{
e.stopPropagation()
handleSubmit()
}}
onPointerDown={(e) => e.stopPropagation()}
disabled={!prompt.trim() || isLoading}
style={{
width: '36px',
height: '36px',
borderRadius: '50%',
border: 'none',
background: prompt.trim() && !isLoading
? ACCENT_COLOR
: colors.inputBg,
cursor: prompt.trim() && !isLoading ? 'pointer' : 'not-allowed',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: prompt.trim() && !isLoading ? 'white' : colors.textMuted,
transition: 'all 0.2s ease',
boxShadow: prompt.trim() && !isLoading
? '0 2px 8px rgba(16, 185, 129, 0.3)'
: 'none',
flexShrink: 0,
}}
title="Send message"
>
>
)}