Add tip box with inline wizard alternatives to agent selection screen

- Move "Select the provider" text directly above agent tiles for better flow
- Add info box explaining keyboard capture and alternatives (/wizard command, wand button)
- Display inline Wand2 icon for visual clarity
- Center note box vertically with equal spacing above/below
- Update test mocks to include Info, Wand2, and AlertTriangle icons
This commit is contained in:
Pedram Amini
2026-02-04 13:16:31 -06:00
parent a0f104f58f
commit 32bb3cf354
2 changed files with 26 additions and 19 deletions

View File

@@ -516,7 +516,7 @@ const Tab = memo(function Tab({
data-tab-id={tab.id} data-tab-id={tab.id}
className={` className={`
relative flex items-center gap-1.5 px-3 py-1.5 cursor-pointer relative flex items-center gap-1.5 px-3 py-1.5 cursor-pointer
transition-all duration-150 select-none transition-all duration-150 select-none shrink-0
${isDragging ? 'opacity-50' : ''} ${isDragging ? 'opacity-50' : ''}
${isDragOver ? 'ring-2 ring-inset' : ''} ${isDragOver ? 'ring-2 ring-inset' : ''}
`} `}
@@ -1309,7 +1309,7 @@ const FileTab = memo(function FileTab({
data-tab-id={tab.id} data-tab-id={tab.id}
className={` className={`
relative flex items-center gap-1.5 px-3 py-1.5 cursor-pointer relative flex items-center gap-1.5 px-3 py-1.5 cursor-pointer
transition-all duration-150 select-none transition-all duration-150 select-none shrink-0
${isDragging ? 'opacity-50' : ''} ${isDragging ? 'opacity-50' : ''}
${isDragOver ? 'ring-2 ring-inset' : ''} ${isDragOver ? 'ring-2 ring-inset' : ''}
`} `}
@@ -1601,19 +1601,23 @@ function TabBarInner({
// Ensure the active tab is fully visible (including close button) when activeTabId or activeFileTabId changes, or filter is toggled // Ensure the active tab is fully visible (including close button) when activeTabId or activeFileTabId changes, or filter is toggled
useEffect(() => { useEffect(() => {
// Double requestAnimationFrame ensures the DOM has fully updated after React's state changes
// First rAF: React has committed changes but browser hasn't painted yet
// Second rAF: Browser has painted, all elements (including close button) are rendered
requestAnimationFrame(() => { requestAnimationFrame(() => {
const container = tabBarRef.current; requestAnimationFrame(() => {
// When a file tab is active, scroll to it; otherwise scroll to the active AI tab const container = tabBarRef.current;
const targetTabId = activeFileTabId || activeTabId; // When a file tab is active, scroll to it; otherwise scroll to the active AI tab
const tabElement = container?.querySelector( const targetTabId = activeFileTabId || activeTabId;
`[data-tab-id="${targetTabId}"]` const tabElement = container?.querySelector(
) as HTMLElement | null; `[data-tab-id="${targetTabId}"]`
if (container && tabElement) { ) as HTMLElement | null;
// Use scrollIntoView with 'nearest' to ensure the full tab is visible if (container && tabElement) {
// This scrolls minimally - only if the tab is partially or fully out of view // Use scrollIntoView with 'nearest' to ensure the full tab is visible
// The 'end' option ensures the right edge (with close button) is visible // This scrolls minimally - only if the tab is partially or fully out of view
tabElement.scrollIntoView({ inline: 'nearest', behavior: 'smooth', block: 'nearest' }); tabElement.scrollIntoView({ inline: 'nearest', behavior: 'smooth', block: 'nearest' });
} }
});
}); });
}, [activeTabId, activeFileTabId, showUnreadOnly]); }, [activeTabId, activeFileTabId, showUnreadOnly]);

View File

@@ -1111,7 +1111,10 @@ export function AgentSelectionScreen({ theme }: AgentSelectionScreenProps): JSX.
)} )}
</div> </div>
{/* Tip about in-tab wizard */} </div>
{/* Section 2: Note box - centered in available space */}
<div className="flex justify-center">
<div <div
className="flex items-start gap-2.5 px-4 py-3 rounded-lg max-w-lg text-xs" className="flex items-start gap-2.5 px-4 py-3 rounded-lg max-w-lg text-xs"
style={{ style={{
@@ -1121,8 +1124,8 @@ export function AgentSelectionScreen({ theme }: AgentSelectionScreenProps): JSX.
> >
<Info className="w-4 h-4 flex-shrink-0 mt-0.5" style={{ color: theme.colors.accent }} /> <Info className="w-4 h-4 flex-shrink-0 mt-0.5" style={{ color: theme.colors.accent }} />
<span style={{ color: theme.colors.textDim }}> <span style={{ color: theme.colors.textDim }}>
This wizard captures keyboard input until complete. For a lighter touch, skip this <strong style={{ color: theme.colors.textMain }}>Note:</strong> This wizard captures
and use{' '} application inputs until complete. For a lighter touch, skip this and use{' '}
<code <code
className="px-1 py-0.5 rounded text-[11px]" className="px-1 py-0.5 rounded text-[11px]"
style={{ backgroundColor: theme.colors.border }} style={{ backgroundColor: theme.colors.border }}
@@ -1139,7 +1142,7 @@ export function AgentSelectionScreen({ theme }: AgentSelectionScreenProps): JSX.
</div> </div>
</div> </div>
{/* Section 2: Agent Grid or Connection Error */} {/* Section 3: Agent Grid or Connection Error */}
{sshConnectionError ? ( {sshConnectionError ? (
/* SSH Connection Error State */ /* SSH Connection Error State */
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
@@ -1327,7 +1330,7 @@ export function AgentSelectionScreen({ theme }: AgentSelectionScreenProps): JSX.
</div> </div>
)} )}
{/* Section 3: Continue Button + Keyboard hints */} {/* Section 4: Continue Button + Keyboard hints */}
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<button <button
onClick={handleContinue} onClick={handleContinue}