Skip to content

Commit df3593e

Browse files
committed
fix(cli): improve input text visibility and mode toggle colors
- Set explicit input text colors for light/dark modes instead of 'default' - Dark mode: #e2e8f0 (brighter slate), Light mode: #334155 (darker slate) - Remove hardcoded fallback color that was causing black text in dark mode - Add dedicated orange/red colors for FAST/MAX mode toggle - Simplify agent-mode-toggle to use new dedicated theme properties
1 parent 0274a48 commit df3593e

File tree

13 files changed

+200
-116
lines changed

13 files changed

+200
-116
lines changed

cli/src/components/agent-mode-toggle.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ export const AgentModeToggle = ({
1111
onToggle: () => void
1212
}) => {
1313
const isFast = mode === 'FAST'
14-
const frameColor = isFast
15-
? theme.agentToggleHeaderBg
16-
: theme.agentToggleExpandedBg
17-
const textColor = frameColor
14+
const frameColor = isFast ? theme.modeToggleFastBg : theme.modeToggleMaxBg
15+
const textColor = isFast ? theme.modeToggleFastText : theme.modeToggleMaxText
1816
const label = isFast ? 'FAST' : '💪 MAX'
1917

2018
return (

cli/src/components/branch-item.tsx

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,25 @@ export const BranchItem = ({
4444
isStreaming,
4545
streamingPreview,
4646
finishedPreview,
47-
availableWidth,
4847
statusLabel,
4948
statusColor,
5049
statusIndicator = '●',
5150
theme,
5251
onToggle,
5352
}: BranchItemProps) => {
53+
const resolveFg = (
54+
color?: string,
55+
fallback?: string,
56+
): string | undefined => {
57+
if (color && color !== 'default') return color
58+
if (fallback && fallback !== 'default') return fallback
59+
return undefined
60+
}
61+
const fallbackTextColor =
62+
resolveFg(theme.agentContentText) ??
63+
resolveFg(theme.chromeText) ??
64+
'#d1d5e5'
65+
5466
const isExpanded = !isCollapsed
5567
const toggleFrameColor = isExpanded
5668
? theme.agentToggleExpandedBg
@@ -62,10 +74,10 @@ export const BranchItem = ({
6274
const toggleLabel = `${isCollapsed ? '▸' : '▾'} `
6375
const collapseButtonFrame = theme.agentToggleExpandedBg
6476
const collapseButtonText = collapseButtonFrame
65-
const separatorColor = theme.agentResponseCount
66-
const innerContentWidth = Math.max(0, Math.floor(availableWidth) - 4)
67-
const horizontalLine =
68-
innerContentWidth > 0 ? '─'.repeat(innerContentWidth) : ''
77+
const toggleFrameFg = resolveFg(toggleFrameColor, fallbackTextColor)
78+
const toggleIconFg = resolveFg(toggleIconColor, fallbackTextColor)
79+
const toggleLabelFg = resolveFg(toggleLabelColor, fallbackTextColor)
80+
const headerFg = resolveFg(theme.agentToggleHeaderText, fallbackTextColor)
6981
const statusText =
7082
statusLabel && statusLabel.length > 0
7183
? statusIndicator === '✓'
@@ -172,7 +184,7 @@ export const BranchItem = ({
172184
<box
173185
border
174186
borderStyle="single"
175-
borderColor={toggleFrameColor}
187+
borderColor={toggleFrameFg ?? undefined}
176188
customBorderChars={containerBorderChars}
177189
style={{
178190
flexDirection: 'column',
@@ -196,7 +208,7 @@ export const BranchItem = ({
196208
width: '100%',
197209
}}
198210
>
199-
<text fg={theme.agentToggleHeaderText}>Prompt</text>
211+
<text {...(headerFg ? { fg: headerFg } : undefined)}>Prompt</text>
200212
<text fg={theme.agentText} style={{ wrapMode: 'word' }}>
201213
{prompt}
202214
</text>
@@ -215,9 +227,11 @@ export const BranchItem = ({
215227
onMouseDown={onToggle}
216228
>
217229
<text style={{ wrapMode: 'none' }}>
218-
<span fg={toggleIconColor}>{toggleLabel}</span>
230+
<span {...(toggleIconFg ? { fg: toggleIconFg } : undefined)}>
231+
{toggleLabel}
232+
</span>
219233
<span
220-
fg={toggleLabelColor}
234+
{...(toggleLabelFg ? { fg: toggleLabelFg } : undefined)}
221235
attributes={isExpanded ? TextAttributes.BOLD : undefined}
222236
>
223237
{name}
@@ -252,55 +266,49 @@ export const BranchItem = ({
252266
</box>
253267
) : null
254268
) : (
255-
<>
256-
{horizontalLine && (
257-
<box style={{ paddingLeft: 1, paddingRight: 1 }}>
258-
<text style={{ wrapMode: 'none' }}>
259-
<span fg={separatorColor}>{horizontalLine}</span>
269+
<box
270+
style={{
271+
flexDirection: 'column',
272+
gap: 1,
273+
paddingLeft: 1,
274+
paddingRight: 1,
275+
paddingTop: 0,
276+
paddingBottom: 0,
277+
}}
278+
>
279+
{prompt && (
280+
<box
281+
style={{
282+
flexDirection: 'column',
283+
gap: 0,
284+
marginBottom: content ? 1 : 0,
285+
}}
286+
>
287+
<text {...(headerFg ? { fg: headerFg } : undefined)}>Prompt</text>
288+
<text fg={theme.agentText} style={{ wrapMode: 'word' }}>
289+
{prompt}
260290
</text>
261-
</box>
262-
)}
263-
<box
264-
style={{
265-
flexDirection: 'column',
266-
gap: 0,
267-
paddingLeft: 1,
268-
paddingRight: 1,
269-
paddingTop: 0,
270-
paddingBottom: 0,
271-
}}
272-
>
273-
{prompt && (
274-
<box
275-
style={{
276-
flexDirection: 'column',
277-
gap: 0,
278-
marginBottom: content ? 1 : 0,
279-
}}
280-
>
281-
<text fg={theme.agentToggleHeaderText}>Prompt</text>
282-
<text fg={theme.agentText} style={{ wrapMode: 'word' }}>
283-
{prompt}
291+
{content && (
292+
<text
293+
{...(headerFg ? { fg: headerFg } : undefined)}
294+
style={{ marginTop: 1 }}
295+
>
296+
Response
284297
</text>
285-
{content && (
286-
<text fg={theme.agentToggleHeaderText} style={{ marginTop: 1 }}>
287-
Response
288-
</text>
289-
)}
290-
</box>
291-
)}
292-
{renderExpandedContent(content)}
293-
<box style={{ alignSelf: 'flex-end', marginTop: content ? 0 : 1 }}>
294-
<RaisedPill
295-
segments={[{ text: 'Collapse', fg: collapseButtonText }]}
296-
frameColor={collapseButtonFrame}
297-
textColor={collapseButtonText}
298-
padding={0}
299-
onPress={onToggle}
300-
/>
298+
)}
301299
</box>
300+
)}
301+
{renderExpandedContent(content)}
302+
<box style={{ alignSelf: 'flex-end', marginTop: content ? 0 : 1 }}>
303+
<RaisedPill
304+
segments={[{ text: 'Collapse', fg: collapseButtonText }]}
305+
frameColor={collapseButtonFrame}
306+
textColor={collapseButtonText}
307+
padding={0}
308+
onPress={onToggle}
309+
/>
302310
</box>
303-
</>
311+
</box>
304312
)}
305313
</box>
306314
</box>

cli/src/components/message-block.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export const MessageBlock = ({
193193
streamingPreview={streamingPreview}
194194
finishedPreview={finishedPreview}
195195
theme={theme}
196+
titleColor={textColor}
196197
branchMeta={branchMeta}
197198
onToggle={() => onToggleCollapsed(toolBlock.toolCallId)}
198199
/>

cli/src/components/multiline-input.tsx

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ interface MultilineInputProps {
8888
inputFocusedFg: string
8989
inputPlaceholder: string
9090
cursor: string
91+
statusAccent: string
9192
}
9293
width: number
9394
}
@@ -579,6 +580,33 @@ export const MultilineInput = forwardRef<
579580
maxHeight,
580581
])
581582

583+
const resolveFg = (
584+
color?: string,
585+
fallback?: string,
586+
): string | undefined => {
587+
if (color && color !== 'default') return color
588+
if (fallback && fallback !== 'default') return fallback
589+
return undefined
590+
}
591+
592+
const resolvedInputColor = resolveFg(
593+
isPlaceholder
594+
? theme.inputPlaceholder
595+
: focused
596+
? theme.inputFocusedFg ?? theme.inputFg
597+
: theme.inputFg,
598+
)
599+
600+
const textStyle: Record<string, unknown> = { bg: 'transparent' }
601+
if (resolvedInputColor) {
602+
textStyle.fg = resolvedInputColor
603+
}
604+
if (isPlaceholder) {
605+
textStyle.attributes = TextAttributes.DIM
606+
}
607+
608+
const cursorFg = resolveFg(theme.cursor, theme.statusAccent)
609+
582610
return (
583611
<scrollbox
584612
ref={scrollBoxRef}
@@ -606,24 +634,22 @@ export const MultilineInput = forwardRef<
606634
},
607635
}}
608636
>
609-
<text
610-
style={{
611-
fg: isPlaceholder
612-
? theme.inputPlaceholder
613-
: focused
614-
? theme.inputFocusedFg
615-
: theme.inputFg,
616-
}}
617-
>
637+
<text style={textStyle}>
618638
{showCursor ? (
619639
<>
620640
{beforeCursor}
621641
{shouldHighlight ? (
622-
<span fg={theme.cursor} attributes={TextAttributes.UNDERLINE}>
642+
<span
643+
{...(cursorFg ? { fg: cursorFg } : undefined)}
644+
attributes={TextAttributes.UNDERLINE}
645+
>
623646
{activeChar === ' ' ? '\u00a0' : activeChar}
624647
</span>
625648
) : (
626-
<span fg={theme.cursor} attributes={TextAttributes.BOLD}>
649+
<span
650+
{...(cursorFg ? { fg: cursorFg } : undefined)}
651+
attributes={TextAttributes.BOLD}
652+
>
627653
{CURSOR_CHAR}
628654
</span>
629655
)}

cli/src/components/raised-pill.tsx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,30 @@ export const RaisedPill = ({
3131
onPress,
3232
style,
3333
}: RaisedPillProps): React.ReactNode => {
34+
const resolveFg = (color?: string): string | undefined =>
35+
color && color !== 'default' ? color : undefined
36+
37+
const resolvedFrameColor = resolveFg(frameColor)
38+
const resolvedTextColor = resolveFg(textColor)
39+
3440
const leftRightPadding =
35-
padding > 0 ? [{ text: ' '.repeat(padding), fg: textColor }] : []
41+
padding > 0
42+
? [{ text: ' '.repeat(padding), fg: resolvedTextColor }]
43+
: []
3644

37-
const normalizedSegments: Array<{ text: string; fg: string; attr?: number }> =
38-
[
39-
...leftRightPadding,
40-
...segments.map((segment) => ({
41-
text: segment.text,
42-
fg: segment.fg ?? textColor,
43-
attr: segment.attr,
44-
})),
45-
...leftRightPadding,
46-
]
45+
const normalizedSegments: Array<{
46+
text: string
47+
fg?: string
48+
attr?: number
49+
}> = [
50+
...leftRightPadding,
51+
...segments.map((segment) => ({
52+
text: segment.text,
53+
fg: resolveFg(segment.fg ?? textColor),
54+
attr: segment.attr,
55+
})),
56+
...leftRightPadding,
57+
]
4758

4859
const contentText = normalizedSegments.map((segment) => segment.text).join('')
4960
const contentWidth = Math.max(0, stringWidth(contentText))
@@ -60,24 +71,32 @@ export const RaisedPill = ({
6071
onMouseDown={onPress}
6172
>
6273
<text>
63-
<span fg={frameColor}>{`╭${horizontal}╮`}</span>
74+
<span
75+
{...(resolvedFrameColor ? { fg: resolvedFrameColor } : undefined)}
76+
>{`╭${horizontal}╮`}</span>
6477
</text>
6578
<text>
66-
<span fg={frameColor}></span>
79+
<span {...(resolvedFrameColor ? { fg: resolvedFrameColor } : undefined)}>
80+
81+
</span>
6782
{normalizedSegments.map((segment, idx) => (
6883
<span
6984
key={idx}
70-
fg={segment.fg}
85+
{...(segment.fg ? { fg: segment.fg } : undefined)}
7186
bg={fillColor ?? 'transparent'}
7287
attributes={segment.attr}
7388
>
7489
{segment.text}
7590
</span>
7691
))}
77-
<span fg={frameColor}></span>
92+
<span {...(resolvedFrameColor ? { fg: resolvedFrameColor } : undefined)}>
93+
94+
</span>
7895
</text>
7996
<text>
80-
<span fg={frameColor}>{`╰${horizontal}╯`}</span>
97+
<span
98+
{...(resolvedFrameColor ? { fg: resolvedFrameColor } : undefined)}
99+
>{`╰${horizontal}╯`}</span>
81100
</text>
82101
</box>
83102
)

cli/src/components/shimmer-text.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export const ShimmerText = ({
163163
const generateColors = (length: number, colorPalette: string[]): string[] => {
164164
if (length === 0) return []
165165
if (colorPalette.length === 0) {
166-
return Array.from({ length }, () => '#ffffff')
166+
return Array.from({ length }, () => '#dbeafe')
167167
}
168168
if (colorPalette.length === 1) {
169169
return Array.from({ length }, () => colorPalette[0])

0 commit comments

Comments
 (0)