Skip to content

Commit cef9cf8

Browse files
Allow multiline text on the AI homepage (#308)
* Allow multiline text on the AI homepage * 📝 Add docstrings to `ai-textarea` (#309) Docstrings generation was requested by @JakeSCahill. * #308 (comment) The following files were modified: * `src/js/react/components/ChatInterface.jsx` Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent fae9903 commit cef9cf8

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

src/css/home.css

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ body.article.home {
4444

4545
.home .chat-footer-wrapper.fixed-bottom .chat-card {
4646
height: 100px;
47+
overflow-y: auto;
4748
}
4849

4950
.home .chat-container {
@@ -175,21 +176,32 @@ body.article.home {
175176
.home .chat-card {
176177
display: flex;
177178
flex-direction: column;
178-
height: 140px;
179+
align-items: stretch; /* allow content to stretch it */
180+
max-height: 280px;
181+
min-height: 140px;
179182
border-radius: var(--border-radius-radius-lg);
180183
background-color: var(--input-color);
181184
box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 0.12);
185+
transition: height 0.2s ease;
186+
overflow-y: auto;
182187
}
183188

184189
.home .chat-content {
185190
display: flex;
186191
align-items: flex-start;
187192
gap: var(--spacings-spacing-xs);
188193
padding: var(--spacings-spacing-lg);
189-
flex: 1;
194+
flex: 1 1 auto;
190195
}
191196

192197
.home .chat-input {
198+
width: 100%;
199+
resize: none;
200+
overflow: auto;
201+
min-height: 40px;
202+
max-height: 200px;
203+
padding: 10px;
204+
line-height: 1.4;
193205
flex: 1;
194206
border: none;
195207
outline: none;
@@ -541,7 +553,7 @@ body.article.home {
541553
display: flex;
542554
flex-direction: column;
543555
padding: 1rem;
544-
align-items: start;
556+
align-items: flex-start;
545557
background-color: var(--chip-color);
546558
}
547559

src/js/react/components/ChatInterface.jsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ function ActionButtons({ onReset, onCopy, setCopyToast }) {
141141
)
142142
}
143143

144-
// ——— Main ChatInterface ————————————————————————————————————————————————————
144+
/**
145+
* Renders the main chat interface, providing a conversational UI with markdown-rendered answers, feedback and copy/reset actions, animated loading states, and responsive suggestion chips.
146+
*
147+
* Manages user input, conversation state, and UI responsiveness for both desktop and mobile. Handles dynamic textarea resizing, scroll-to-bottom behavior, and conditional display of header/footer elements based on user interaction. Integrates with the chat backend via the `useChat` hook to submit queries, stop or reset conversations, and display AI-generated suggestions. Also manages inline toast notifications for copy and feedback actions.
148+
*/
145149
export default function ChatInterface() {
146150
const [message, setMessage] = useState('')
147151
const [dots, setDots] = useState('')
@@ -151,6 +155,12 @@ export default function ChatInterface() {
151155
const [hasInteracted, setHasInteracted] = useState(false)
152156
const [copyToast, setCopyToast] = useState(null)
153157
const [feedbackToast, setFeedbackToast] = useState(null)
158+
const textareaRef = useRef(null)
159+
160+
const resetTextareaHeight = () => {
161+
if (!textareaRef.current) return
162+
textareaRef.current.style.height = 'unset'
163+
}
154164

155165
// Detect mobile vs. desktop breakpoint
156166
const [isMobile, setIsMobile] = useState(window.innerWidth < 1150)
@@ -280,6 +290,7 @@ export default function ChatInterface() {
280290
const handleSubmit = (e) => {
281291
e.preventDefault()
282292
doQuery(message)
293+
resetTextareaHeight()
283294
}
284295

285296
const handleReset = () => {
@@ -290,6 +301,7 @@ export default function ChatInterface() {
290301
setShowScrollDown(false)
291302
window.scrollTo({ top: 0, behavior: 'smooth' })
292303
setDropdownOpen(false)
304+
resetTextareaHeight()
293305
}
294306

295307
const handleCopy = async () => {
@@ -458,14 +470,28 @@ export default function ChatInterface() {
458470
<form onSubmit={handleSubmit}>
459471
<div className="chat-card">
460472
<div className="chat-content">
461-
<input
462-
className="chat-input"
463-
type="text"
464-
placeholder="How can we help you with Redpanda today?"
465-
value={message}
466-
onChange={(e) => setMessage(e.target.value)}
467-
disabled={isGeneratingAnswer || isPreparingAnswer}
468-
/>
473+
<textarea
474+
ref={textareaRef}
475+
id="chat-message"
476+
name="chat-message"
477+
className="chat-input"
478+
placeholder="How can we help you with Redpanda today?"
479+
value={message}
480+
onChange={(e) => {
481+
setMessage(e.target.value)
482+
483+
const el = e.target
484+
el.style.height = 'auto'
485+
el.style.height = Math.min(el.scrollHeight, 200) + 'px'
486+
}}
487+
onKeyDown={(e) => {
488+
if (e.key === 'Enter' && !e.shiftKey) {
489+
e.preventDefault()
490+
handleSubmit(e)
491+
}
492+
}}
493+
disabled={isGeneratingAnswer || isPreparingAnswer}
494+
/>
469495
</div>
470496
<div className="chat-footer">
471497
{isPreparingAnswer || isGeneratingAnswer ? (

0 commit comments

Comments
 (0)