Skip to content

files: extract page header component#1608

Open
ivaavimusic wants to merge 3 commits intorecoupable:mainfrom
ivaavimusic:ui-polish-upload-guidance
Open

files: extract page header component#1608
ivaavimusic wants to merge 3 commits intorecoupable:mainfrom
ivaavimusic:ui-polish-upload-guidance

Conversation

@ivaavimusic
Copy link
Copy Markdown

@ivaavimusic ivaavimusic commented Mar 30, 2026

Summary

This PR improves several small but noticeable UI affordances across chat, files, and modal interactions.

Changes

  • adds pointer cursors to shared buttons and key sidebar interactions
  • adds pointer cursor to the shared dialog close button
  • improves the files page with a clearer title and short description
  • updates the empty files state to explain that uploads go into the sandbox workspace
  • prevents the landing-page composer from becoming internally scrollable in the empty hero state

Why

These changes make core interactions feel more intentional and reduce ambiguity around clickable controls and sandbox file uploads.

Risk

Low. Changes are UI-focused and scoped to affordances, copy, and composer behavior.

Summary by CodeRabbit

  • New Features

    • Introduced a dedicated header section on the Files page that displays the page title and provides clear instructions for uploading repository files to agent sandboxes.
  • UI Improvements

    • Enhanced the page layout with improved vertical spacing between the header section and file tree for better visual organization and readability.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 30, 2026

@ivaavimusic is attempting to deploy a commit to the Recoupable Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 75219533-fc58-44fc-81f5-2f5e8cda8c61

📥 Commits

Reviewing files that changed from the base of the PR and between bdc0600 and 2745a69.

📒 Files selected for processing (2)
  • app/files/page.tsx
  • components/Sandboxes/FilesPageHeader.tsx
✅ Files skipped from review due to trivial changes (2)
  • app/files/page.tsx
  • components/Sandboxes/FilesPageHeader.tsx

📝 Walkthrough

Walkthrough

This PR introduces a new FilesPageHeader component that displays a title and description for the files page, then integrates it into the files page layout above the existing file tree with proper vertical spacing.

Changes

Cohort / File(s) Summary
New Header Component
components/Sandboxes/FilesPageHeader.tsx
New component exports a simple header with "Files" title and descriptive paragraph about uploading repository files for sandbox agents using utility-based styling.
Files Page Integration
app/files/page.tsx
Imports and renders FilesPageHeader above SandboxFileTree; adds space-y-6 to the outer container for vertical spacing between header and file tree.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Poem

📋 A header blooms above the tree,
"Files" proclaimed for all to see,
With spacing clean and text so bright,
The page now greets with proper height. ✨

🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Solid & Clean Code ✅ Passed FilesPageHeader demonstrates strong adherence to SOLID principles and clean code practices with single responsibility, clear naming, minimal size, and proper component composition.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bdc06008f9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +34 to +35
if (!disableInternalScroll) {
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset textarea height when disabling autosize mode

When disableInternalScroll flips from true to false (e.g., after sending the first message), adjustHeight exits early and never clears the inline textarea.style.height previously set during autosizing. This leaves the composer stuck at an expanded height even after the input is cleared, so the post-send chat input can remain oversized until remount. Add a reset path for the non-autosize branch (or whenever the flag changes) so height returns to the normal controlled size.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
components/Sandboxes/NoSandboxFiles.tsx (1)

24-30: Optional: remove duplicated width constraint to reduce style drift.

max-w-md is applied on both wrapper and root dropzone; keeping it in one place makes future layout changes safer.

♻️ Suggested simplification
-      <div
+      <div
         {...getRootProps()}
         role="region"
         aria-label="File upload dropzone"
         className={cn(
-          "w-full max-w-md rounded-lg p-8 border-2 border-dashed transition-all",
+          "w-full rounded-lg p-8 border-2 border-dashed transition-all",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/Sandboxes/NoSandboxFiles.tsx` around lines 24 - 30, The dropzone
has a duplicated width constraint: the outer wrapper div and the inner element
using {...getRootProps()} both include "max-w-md", which can cause style drift;
remove "max-w-md" from the inner element's className (the element that spreads
getRootProps()) and keep it on the outer wrapper div so the width constraint is
defined in a single place, ensuring future layout changes are safer.
components/Sidebar/RecentChats/ChatItem.tsx (1)

155-182: Align menu keyboard behavior with role="menu" semantics.

This menu currently handles Escape, but not arrow-key navigation/focus movement expected for menu patterns. Either implement full menu keyboard behavior or switch to semantics that match current interaction.

As per coding guidelines, "Support arrow key navigation in dropdown menu components" and "Implement proper focus management in dropdown menu components".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/Sidebar/RecentChats/ChatItem.tsx` around lines 155 - 182, The menu
currently uses role="menu" but only handles Escape; update ChatItem.tsx to
either implement proper menu keyboard/focus behavior or change semantics to
match current interactions: either (A) implement arrow-key focus movement and
roving focus inside the menu when isMenuOpen (manage focus on menuRef and menu
items, handle ArrowDown/ArrowUp to move focus between the buttons, Home/End to
jump, and Escape to close via onMenuToggle) and ensure the buttons
(onRenameClick, onDeleteClick) are focusable and have role="menuitem" and
appropriate aria-activedescendant/aria-controls as needed, or (B) remove
role="menu" and use role="listbox" or no menu role to reflect basic click-only
behavior; pick one approach and update ChatItem's menuRef, isMenuOpen
conditional, onMenuToggle, onRenameClick and onDeleteClick accordingly to
maintain correct focus cleanup when closing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/VercelChat/FileMentionsInput.tsx`:
- Around line 33-45: The adjustHeight callback exits early when
disableInternalScroll is false, leaving any previously set inline textarea
height intact; update adjustHeight (and callers if needed) so that when
disableInternalScroll is false it clears the inline height on the element
referenced by inputRef (e.g., set textarea.style.height = "" or "auto") before
returning, ensuring the composer resets to its default height; reference the
adjustHeight function, the disableInternalScroll flag, and
inputRef/textarea.style.height when making the change.

---

Nitpick comments:
In `@components/Sandboxes/NoSandboxFiles.tsx`:
- Around line 24-30: The dropzone has a duplicated width constraint: the outer
wrapper div and the inner element using {...getRootProps()} both include
"max-w-md", which can cause style drift; remove "max-w-md" from the inner
element's className (the element that spreads getRootProps()) and keep it on the
outer wrapper div so the width constraint is defined in a single place, ensuring
future layout changes are safer.

In `@components/Sidebar/RecentChats/ChatItem.tsx`:
- Around line 155-182: The menu currently uses role="menu" but only handles
Escape; update ChatItem.tsx to either implement proper menu keyboard/focus
behavior or change semantics to match current interactions: either (A) implement
arrow-key focus movement and roving focus inside the menu when isMenuOpen
(manage focus on menuRef and menu items, handle ArrowDown/ArrowUp to move focus
between the buttons, Home/End to jump, and Escape to close via onMenuToggle) and
ensure the buttons (onRenameClick, onDeleteClick) are focusable and have
role="menuitem" and appropriate aria-activedescendant/aria-controls as needed,
or (B) remove role="menu" and use role="listbox" or no menu role to reflect
basic click-only behavior; pick one approach and update ChatItem's menuRef,
isMenuOpen conditional, onMenuToggle, onRenameClick and onDeleteClick
accordingly to maintain correct focus cleanup when closing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 022d880d-fae1-416f-b459-4fcafde4208e

📥 Commits

Reviewing files that changed from the base of the PR and between 0a6fc82 and bdc0600.

📒 Files selected for processing (9)
  • app/files/page.tsx
  • components/Sandboxes/NoSandboxFiles.tsx
  • components/Sidebar/NewChatButton.tsx
  • components/Sidebar/RecentChats/ChatItem.tsx
  • components/VercelChat/ChatInput.tsx
  • components/VercelChat/FileMentionsInput.tsx
  • components/VercelChat/mentionsStyles.ts
  • components/ui/button.tsx
  • components/ui/dialog.tsx

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recoup-chat Ready Ready Preview Mar 30, 2026 4:27pm

Request Review

Comment on lines +5 to +13
<div className="px-6 md:px-12 py-8 space-y-6">
<div className="max-w-3xl">
<h1 className="text-left font-heading text-3xl font-bold">
Files
</h1>
<p className="mt-2 text-lg text-muted-foreground font-light font-sans">
Upload repository files for your agent sandbox, including code, docs, assets, and reference material.
</p>
</div>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single Responsibility / Open Closed Principles

  • actual: adding net new code to an existing component.
  • required: new component file for the Header code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I’ll keep the header improvement but move it into a separate component file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the state of missing files, we actually want these files to get setup via the Sandbox task.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. I was approaching this as a general empty-state improvement, but I see that the intended flow is different here. I’ll revert this file from the PR for now and keep missing-files UX as a separate follow-up.

}}
className={cn(
"shrink-0 w-4 h-4 rounded border-2 transition-all duration-150 flex items-center justify-center",
"shrink-0 w-4 h-4 rounded border-2 transition-all duration-150 flex items-center justify-center cursor-pointer",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single Responsibility Principle

  • why are you modifying chatItem in a pull request titled upload-guidance?
  • Each pull request should improve exactly one thing.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This is unrelated to upload guidance. I’ll remove it from this PR and keep it for a separate UI polish PR.

type="button"
className={cn(
"inline-flex items-center h-10 rounded-lg whitespace-nowrap overflow-hidden transition-all duration-200 text-sm font-normal text-foreground hover:bg-muted",
"inline-flex items-center h-10 rounded-lg whitespace-nowrap overflow-hidden transition-all duration-200 text-sm font-normal text-foreground hover:bg-muted cursor-pointer",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same SRP question here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I’ll move this out of the PR so the scope stays focused.


const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not modify root shadcn components.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood.

>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground cursor-pointer">
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not modify root shadcn components.

onChange={setInput}
disabled={isDisabled || hasPendingUploads}
model={model}
disableInternalScroll={messages.length === 0}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SRP - why are you modifying chat components in a pr titled for file uploads?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. This belongs in a separate PR, not this one. I’ll remove it from here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please summarize what the purpose of these changes are and how they contribute to the title of the PR?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right to call this out. This was a misunderstood change on my side and it does not meaningfully contribute to the scope or title of this PR. I’ll remove it

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of these file changes?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file changed only in support of the same misunderstood change above, so it does not belong in this PR either. I’ll remove this as well.

@ivaavimusic ivaavimusic changed the title Polish upload affordances and file page guidance Extract files page header into dedicated component Mar 30, 2026
@ivaavimusic ivaavimusic changed the title Extract files page header into dedicated component files: extract page header component Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants