-
-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Hide example prompts until chat input is focused #306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit implements a change to the chat interface where the example prompts are now hidden by default. They are revealed only when the user clicks on or focuses the chat input field. This change improves the initial user experience by providing a cleaner, less cluttered interface upon first load. Additionally, this commit also introduces a `.gitignore` file to prevent sensitive environment files and development logs from being accidentally committed to the repository. This is a crucial step for improving the project's security and maintainability.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
WalkthroughRemoved a DATABASE_URL entry from .env and added new ignore patterns to .gitignore. Extended ChatPanel with optional onFocus/onBlur props. Updated Chat to manage messages locally, use a new useActions.submit flow, append user/bot messages, and render EmptyScreen based on input focus. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant ChatPanel
participant Chat
participant Actions as useActions.submit
rect rgb(245,245,255)
note over User,Chat: Focus-driven empty state (new)
User->>ChatPanel: focus input (onFocus)
ChatPanel-->>Chat: onFocus()
Chat->>Chat: isInputFocused = true
Chat->>Chat: if messages.empty ⇒ show EmptyScreen
end
rect rgb(245,255,245)
note over User,Actions: Submit flow (append user, await bot)
User->>Chat: submitExampleMessage(text)
Chat->>Chat: append UserMessage(id=nanoid)
Chat->>Actions: submit(text)
Actions-->>Chat: botResponse
Chat->>Chat: append botResponse
Chat-->>User: render ChatMessages
end
rect rgb(255,245,245)
note over User,ChatPanel: Blur handling
User->>ChatPanel: blur input (onBlur)
ChatPanel-->>Chat: onBlur()
Chat->>Chat: isInputFocused = false
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)components/chat.tsx (5)
🔇 Additional comments (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Example prompts can’t be reliably clicked because
onBlurhides them before the click fires; defer the blur update to avoid flicker and missed interactions. dev.logis committed while logs are ignored; remove it from version control.as anyusage weakens type safety; prefer a concrete type (e.g.,UIState[number]).- Minor:
.gitignoreincludes both*.loganddev.log; the latter is redundant.
Additional notes (3)
-
Maintainability |
.gitignore:27-28
Adding both*.loganddev.logis redundant. The*.logpattern already ignoresdev.log. Keeping both can confuse future maintainers about which rule is authoritative. -
Style |
.gitignore:27-35
Minor nit:*.logalready coversdev.log, and.env*.localalready covers the specific.env.development.local,.env.test.local, and.env.production.localentries. Redundant patterns make the file noisier without adding protection. -
Maintainability |
components/chat.tsx:33-45
submitExampleMessagereimplements message submission logic that likely overlaps with the form submission flow inChatPanel. Divergent code paths for sending a message can lead to inconsistencies (e.g., missed validations, different metadata, future features not applied to both).
Summary of changes
- Deleted committed
.envfile and expanded.gitignoreto cover environment files, logs (including*.log), and ajules-scratch/directory. - Added
onFocusandonBluroptional props toChatPaneland wired them to the<Textarea>to detect input focus. - Updated
Chatto:- Track
isInputFocusedstate and show example prompts (<EmptyScreen>) only when the input is focused and there are no messages. - Add
submitExampleMessageto submit example prompts directly viauseActions().submit, appending both the user message and the response to UI state.
- Track
- Introduced a
dev.logfile (while also adding ignore rules for logs).
| ▲ Next.js 15.3.3 (Turbopack) | ||
| - Local: http://localhost:3001 | ||
| - Network: http://192.168.0.2:3001 | ||
| - Environments: .env | ||
|
|
||
| ✓ Starting... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dev.log file is being committed even though logs are now ignored. This defeats the goal of preventing logs from entering the repo and can cause noisy diffs or leak environment details. It should be untracked and removed from the repository.
Suggestion
Remove dev.log from version control and rely on .gitignore to prevent future commits. You can do:
git rm --cached dev.log(or delete the file in the PR)- Commit the change
Reply with "@CharlieHelps yes please" if you'd like me to add a commit removing dev.log from the repo.
components/chat.tsx
Outdated
| setMessages(currentMessages => [...currentMessages, responseMessage as any]) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using as any here undermines type safety and makes it easier for regressions to slip in. Since you’re already updating UIState, prefer a concrete type over any.
Suggestion
Avoid as any by aligning the type of responseMessage with your UI state. For example:
- Import the appropriate UI message type (e.g.,
UIStateorUIMessage) and use it explicitly.
Example:
import type { UIState } from 'ai/rsc'
...
const responseMessage = (await submit(message)) as UIState[number]
setMessages(curr => [...curr, responseMessage])
If the action already returns the correct typed UI component, you may be able to drop the assertion entirely.
Reply with "@CharlieHelps yes please" if you'd like me to add a commit applying this change.
| onFocus={() => setIsInputFocused(true)} | ||
| onBlur={() => setIsInputFocused(false)} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hiding example prompts on input blur makes them disappear before the user can click an example. In the browser event order, the input blur fires before the example’s click, so your onBlur immediately hides <EmptyScreen>, causing a frustrating flicker and missed clicks.
Suggestion
Delay the blur state update so clicks on the examples still register. Replace the onBlur with a deferred update:
onBlur={() => setTimeout(() => setIsInputFocused(false), 0)}
Apply this change to both mobile and desktop ChatPanel instances.
Reply with "@CharlieHelps yes please" if you'd like me to add a commit updating both places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
dev.logis excluded by!**/*.log
📒 Files selected for processing (4)
.env(0 hunks).gitignore(1 hunks)components/chat-panel.tsx(2 hunks)components/chat.tsx(4 hunks)
💤 Files with no reviewable changes (1)
- .env
🧰 Additional context used
🧬 Code graph analysis (1)
components/chat.tsx (4)
components/user-message.tsx (1)
UserMessage(10-22)components/chat-panel.tsx (1)
ChatPanel(22-187)components/chat-messages.tsx (1)
ChatMessages(11-70)components/empty-screen.tsx (1)
EmptyScreen(27-59)
| onFocus={onFocus} | ||
| onBlur={onBlur} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-focus defeats the “show on focus” requirement
Forwarding onFocus/onBlur is good, but because the textarea still auto-focuses on mount (Line 66), the parent handler flips isInputFocused to true immediately. The EmptyScreen—and its example prompts—becomes visible before the user interacts, which contradicts the stated goal of hiding prompts until the chat input is manually focused. Please drop or gate the auto-focus so the new visibility logic only triggers after an intentional focus event.
- useEffect(() => {
- inputRef.current?.focus();
- }, [])📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onFocus={onFocus} | |
| onBlur={onBlur} | |
| // … earlier in ChatPanel component … | |
| const ChatPanel = () => { | |
| const inputRef = useRef<HTMLTextAreaElement>(null); | |
| // — Removed the auto-focus effect so that onFocus/onBlur | |
| // are only triggered by user interaction, not on mount. | |
| // useEffect(() => { | |
| // inputRef.current?.focus(); | |
| // }, []); | |
| // … other hooks and logic … | |
| return ( | |
| <textarea | |
| ref={inputRef} | |
| onFocus={onFocus} | |
| onBlur={onBlur} | |
| // … other props … | |
| /> | |
| ); | |
| }; | |
| // … rest of file … |
🤖 Prompt for AI Agents
In components/chat-panel.tsx around lines 66 and 129-130, the textarea still
auto-focuses on mount (line 66) which immediately fires the forwarded onFocus
and makes the parent treat the input as user-focused; remove or gate that
autoFocus so focus is only set after an intentional user action. Concretely,
stop passing autoFocus unconditionally (either remove the prop or wrap it behind
an explicit prop/state like allowAutoFocus or only set autoFocus after a
confirmed user interaction) so the forwarded onFocus/onBlur reflect actual
manual focus and the EmptyScreen visibility remains hidden until the user
intentionally focuses the input.
| const submitExampleMessage = async (message: string) => { | ||
| setMessages(currentMessages => [ | ||
| ...currentMessages, | ||
| { | ||
| id: nanoid(), | ||
| component: <UserMessage message={message} /> | ||
| } | ||
| ]) | ||
|
|
||
| const responseMessage = await submit(message) | ||
|
|
||
| setMessages(currentMessages => [...currentMessages, responseMessage as any]) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
submitExampleMessage sends the wrong payload to submit
handleSubmit still builds a FormData payload before calling submit, which matches the server action’s contract. Here we now pass a plain string (submit(message)), so clicking an example prompt will either throw (type mismatch) or reach the server without the expected input field. Align the example flow with the form submission by packaging the message into FormData.
const submitExampleMessage = async (message: string) => {
setMessages(currentMessages => [
...currentMessages,
{
id: nanoid(),
component: <UserMessage message={message} />
}
])
- const responseMessage = await submit(message)
+ const formData = new FormData()
+ formData.append('input', message)
+ const responseMessage = await submit(formData)
setMessages(currentMessages => [...currentMessages, responseMessage as any])
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const submitExampleMessage = async (message: string) => { | |
| setMessages(currentMessages => [ | |
| ...currentMessages, | |
| { | |
| id: nanoid(), | |
| component: <UserMessage message={message} /> | |
| } | |
| ]) | |
| const responseMessage = await submit(message) | |
| setMessages(currentMessages => [...currentMessages, responseMessage as any]) | |
| } | |
| const submitExampleMessage = async (message: string) => { | |
| setMessages(currentMessages => [ | |
| ...currentMessages, | |
| { | |
| id: nanoid(), | |
| component: <UserMessage message={message} /> | |
| } | |
| ]) | |
| const formData = new FormData() | |
| formData.append('input', message) | |
| const responseMessage = await submit(formData) | |
| setMessages(currentMessages => [...currentMessages, responseMessage as any]) | |
| } |
🤖 Prompt for AI Agents
components/chat.tsx around lines 33 to 45: submitExampleMessage passes the raw
string to submit but the server action expects a FormData payload like
handleSubmit does; wrap the message in a FormData instance (e.g., const form =
new FormData(); form.append('input', message);) and call submit(form) instead of
submit(message), and ensure any type annotations for submit are satisfied (cast
to the expected type if needed).
This commit implements a change to the chat interface where the example prompts are now hidden by default. They are revealed only when the user clicks on or focuses the chat input field. This change improves the initial user experience by providing a cleaner, less cluttered interface upon first load. Additionally, this commit also introduces a `.gitignore` file to prevent sensitive environment files and development logs from being accidentally committed to the repository. This is a crucial step for improving the project's security and maintainability.
User description
This commit implements a change to the chat interface where the example prompts are now hidden by default. They are revealed only when the user clicks on or focuses the chat input field.
This change improves the initial user experience by providing a cleaner, less cluttered interface upon first load.
Additionally, this commit also introduces a
.gitignorefile to prevent sensitive environment files and development logs from being accidentally committed to the repository. This is a crucial step for improving the project's security and maintainability.PR Type
Enhancement
Description
Hide example prompts until chat input is focused
Improve initial UI experience with cleaner interface
Add focus/blur handlers to chat input component
Remove sensitive database URL from version control
Diagram Walkthrough
File Walkthrough
.env
Remove database credentials from repository.env
chat-panel.tsx
Add focus/blur handlers to chat inputcomponents/chat-panel.tsx
onFocusandonBlurprops to interfacechat.tsx
Implement focus-based example prompt visibilitycomponents/chat.tsx
isInputFocusedstate to track input focussubmitExampleMessagefunction for direct submissionshowEmptyScreenlogic with focus-based visibilityEmptyScreenonly when input is focused and no messages existSummary by CodeRabbit
New Features
Chores