Skip to content

Commit 5238f2b

Browse files
committed
refactor: move queue preview to separate line
Split the status bar into two rows: - Row 1: status indicator (left) | scroll indicator (center) | elapsed time (right) - Row 2: queue preview (full width, only shown when messages are queued) This gives the queue preview its own dedicated space and makes it feel more distinct from the status/time indicators. The queue preview now has nearly full terminal width available to display longer message previews. Removed the complex width calculation function since the queue preview now gets the full width (minus padding).
1 parent 65d2025 commit 5238f2b

File tree

1 file changed

+68
-83
lines changed

1 file changed

+68
-83
lines changed

cli/src/chat.tsx

Lines changed: 68 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -555,39 +555,6 @@ export const Chat = ({
555555
<StatusElapsedTime streamStatus={streamStatus} timerStartTime={timerStartTime} />
556556
)
557557

558-
// Calculate available width for queue preview based on actual content
559-
const calculateQueuePreviewWidth = () => {
560-
// Estimate status text length
561-
let statusTextLength = 0
562-
if (nextCtrlCWillExit) {
563-
statusTextLength = 27 // "Press Ctrl-C again to exit"
564-
} else if (clipboardMessage) {
565-
statusTextLength = clipboardMessage.length
566-
} else if (streamStatus === 'waiting') {
567-
statusTextLength = 11 // "thinking..."
568-
} else if (streamStatus === 'streaming') {
569-
statusTextLength = 10 // "working..."
570-
}
571-
572-
// Estimate scroll indicator (1 char normally, 20 when hovered, use 1 for calculation)
573-
const scrollIndicatorLength = !isAtBottom ? 1 : 0
574-
575-
// Estimate elapsed time length (typically 2-7 chars like "5s" or "1m 30s")
576-
const elapsedTimeLength = streamStatus !== 'idle' ? 7 : 0
577-
578-
// Account for padding, gaps, and margins (~10 chars)
579-
const overhead = 10
580-
581-
// Calculate available space
582-
const availableWidth =
583-
terminalWidth - statusTextLength - scrollIndicatorLength - elapsedTimeLength - overhead
584-
585-
// Return reasonable bounds: minimum 20, maximum 60
586-
return Math.max(20, Math.min(60, availableWidth))
587-
}
588-
589-
const queuePreviewWidth = calculateQueuePreviewWidth()
590-
591558
const validationBanner = useValidationBanner({
592559
liveValidationErrors: validationErrors,
593560
loadedAgentsData,
@@ -682,68 +649,86 @@ export const Chat = ({
682649
{shouldShowStatusLine && (
683650
<box
684651
style={{
685-
flexDirection: 'row',
686-
alignItems: 'center',
652+
flexDirection: 'column',
687653
width: '100%',
688654
}}
689655
>
690-
{/* Left section */}
656+
{/* Main status line: status indicator | scroll indicator | elapsed time */}
691657
<box
692658
style={{
693-
flexGrow: 1,
694-
flexShrink: 1,
695-
flexBasis: 0,
696659
flexDirection: 'row',
697-
gap: 2,
660+
alignItems: 'center',
661+
width: '100%',
698662
}}
699663
>
700-
<text style={{ wrapMode: 'none' }}>{statusIndicatorNode}</text>
701-
{shouldShowQueuePreview && (
664+
{/* Left section - status indicator */}
665+
<box
666+
style={{
667+
flexGrow: 1,
668+
flexShrink: 1,
669+
flexBasis: 0,
670+
}}
671+
>
672+
<text style={{ wrapMode: 'none' }}>{statusIndicatorNode}</text>
673+
</box>
674+
675+
{/* Center section - scroll indicator (always centered) */}
676+
<box style={{ flexShrink: 0 }}>
677+
{!isAtBottom && (
678+
<box
679+
style={{ paddingLeft: 2, paddingRight: 2 }}
680+
onMouseDown={() => scrollToLatest()}
681+
onMouseOver={() => setScrollIndicatorHovered(true)}
682+
onMouseOut={() => setScrollIndicatorHovered(false)}
683+
>
684+
<text>
685+
<span
686+
fg={theme.info}
687+
attributes={
688+
scrollIndicatorHovered
689+
? TextAttributes.BOLD
690+
: TextAttributes.DIM
691+
}
692+
>
693+
{scrollIndicatorHovered ? '↓ Scroll to bottom ↓' : '↓'}
694+
</span>
695+
</text>
696+
</box>
697+
)}
698+
</box>
699+
700+
{/* Right section - elapsed time */}
701+
<box
702+
style={{
703+
flexGrow: 1,
704+
flexShrink: 1,
705+
flexBasis: 0,
706+
flexDirection: 'row',
707+
justifyContent: 'flex-end',
708+
}}
709+
>
710+
<text style={{ wrapMode: 'none' }}>{elapsedTimeNode}</text>
711+
</box>
712+
</box>
713+
714+
{/* Queue preview line - separate row */}
715+
{shouldShowQueuePreview && (
716+
<box
717+
style={{
718+
flexDirection: 'row',
719+
width: '100%',
720+
}}
721+
>
702722
<text style={{ wrapMode: 'none' }}>
703723
<span fg={theme.secondary} bg={theme.inputFocusedBg}>
704-
{` ${formatQueuedPreview(queuedMessages, queuePreviewWidth)} `}
724+
{` ${formatQueuedPreview(
725+
queuedMessages,
726+
Math.max(30, terminalWidth - 10),
727+
)} `}
705728
</span>
706729
</text>
707-
)}
708-
</box>
709-
710-
{/* Center section - scroll indicator (always centered) */}
711-
<box style={{ flexShrink: 0 }}>
712-
{!isAtBottom && (
713-
<box
714-
style={{ paddingLeft: 2, paddingRight: 2 }}
715-
onMouseDown={() => scrollToLatest()}
716-
onMouseOver={() => setScrollIndicatorHovered(true)}
717-
onMouseOut={() => setScrollIndicatorHovered(false)}
718-
>
719-
<text>
720-
<span
721-
fg={theme.info}
722-
attributes={
723-
scrollIndicatorHovered
724-
? TextAttributes.BOLD
725-
: TextAttributes.DIM
726-
}
727-
>
728-
{scrollIndicatorHovered ? '↓ Scroll to bottom ↓' : '↓'}
729-
</span>
730-
</text>
731-
</box>
732-
)}
733-
</box>
734-
735-
{/* Right section */}
736-
<box
737-
style={{
738-
flexGrow: 1,
739-
flexShrink: 1,
740-
flexBasis: 0,
741-
flexDirection: 'row',
742-
justifyContent: 'flex-end',
743-
}}
744-
>
745-
<text style={{ wrapMode: 'none' }}>{elapsedTimeNode}</text>
746-
</box>
730+
</box>
731+
)}
747732
</box>
748733
)}
749734
<box

0 commit comments

Comments
 (0)