diff options
Diffstat (limited to 'packages/cli/src/ui/components')
4 files changed, 123 insertions, 73 deletions
diff --git a/packages/cli/src/ui/components/SuggestionsDisplay.tsx b/packages/cli/src/ui/components/SuggestionsDisplay.tsx index f0626fa9..ba25f2b6 100644 --- a/packages/cli/src/ui/components/SuggestionsDisplay.tsx +++ b/packages/cli/src/ui/components/SuggestionsDisplay.tsx @@ -5,6 +5,7 @@ */ import { Box, Text } from 'ink'; +import { Colors } from '../colors.js'; export interface Suggestion { label: string; value: string; @@ -48,7 +49,7 @@ export function SuggestionsDisplay({ return ( <Box borderStyle="round" flexDirection="column" paddingX={1} width={width}> - {scrollOffset > 0 && <Text color="gray">▲</Text>} + {scrollOffset > 0 && <Text color={Colors.Foreground}>▲</Text>} {visibleSuggestions.map((suggestion, index) => { const originalIndex = startIndex + index; @@ -56,8 +57,8 @@ export function SuggestionsDisplay({ return ( <Text key={`${suggestion}-${originalIndex}`} - color={isActive ? 'black' : 'white'} - backgroundColor={isActive ? 'blue' : undefined} + color={isActive ? Colors.Background : Colors.Foreground} + backgroundColor={isActive ? Colors.AccentBlue : undefined} > {suggestion.label} </Text> diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx index 7e8c5afd..20686040 100644 --- a/packages/cli/src/ui/components/ThemeDialog.tsx +++ b/packages/cli/src/ui/components/ThemeDialog.tsx @@ -32,16 +32,22 @@ export function ThemeDialog({ SettingScope.User, ); - const themeItems = themeManager.getAvailableThemes().map((theme) => ({ - label: theme.active ? `${theme.name} (Active)` : theme.name, - value: theme.name, - })); + // Generate theme items + const themeItems = themeManager.getAvailableThemes().map((theme) => { + const typeString = theme.type.charAt(0).toUpperCase() + theme.type.slice(1); + return { + label: theme.name, + value: theme.name, + themeNameDisplay: theme.name, + themeTypeDisplay: typeString, + }; + }); const [selectInputKey, setSelectInputKey] = useState(Date.now()); + // Determine which radio button should be initially selected in the theme list + // This should reflect the theme *saved* for the selected scope, or the default const initialThemeIndex = themeItems.findIndex( - (item) => - item.value === - (settings.forScope(selectedScope).settings.theme || DEFAULT_THEME.name), + (item) => item.value === (settings.merged.theme || DEFAULT_THEME.name), ); const scopeItems = [ @@ -88,45 +94,49 @@ export function ThemeDialog({ return ( <Box borderStyle="round" - borderColor={Colors.AccentCyan} - flexDirection="column" + borderColor={Colors.AccentPurple} + flexDirection="row" padding={1} - width="50%" + width="100%" > - <Text bold={focusedSection === 'theme'}> - {focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '} - <Text color={Colors.SubtleComment}>{otherScopeModifiedMessage}</Text> - </Text> - - <RadioButtonSelect - key={selectInputKey} - items={themeItems} - initialIndex={initialThemeIndex} - onSelect={handleThemeSelect} // Use the wrapper handler - onHighlight={onHighlight} - isFocused={focusedSection === 'theme'} - /> - {/* Scope Selection */} - <Box marginTop={1} flexDirection="column"> - <Text bold={focusedSection === 'scope'}> - {focusedSection === 'scope' ? '> ' : ' '}Apply To + {/* Left Column: Selection */} + <Box flexDirection="column" width="50%" paddingRight={2}> + <Text bold={focusedSection === 'theme'}> + {focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '} + <Text color={Colors.SubtleComment}>{otherScopeModifiedMessage}</Text> </Text> <RadioButtonSelect - items={scopeItems} - initialIndex={0} // Default to User Settings - onSelect={handleScopeSelect} - onHighlight={handleScopeHighlight} - isFocused={focusedSection === 'scope'} + key={selectInputKey} + items={themeItems} + initialIndex={initialThemeIndex} + onSelect={handleThemeSelect} + onHighlight={onHighlight} + isFocused={focusedSection === 'theme'} /> - </Box> - <Box marginTop={1}> - <Text color={Colors.SubtleComment}> - (Use ↑/↓ arrows and Enter to select, Tab to change focus) - </Text> + {/* Scope Selection */} + <Box marginTop={1} flexDirection="column"> + <Text bold={focusedSection === 'scope'}> + {focusedSection === 'scope' ? '> ' : ' '}Apply To + </Text> + <RadioButtonSelect + items={scopeItems} + initialIndex={0} // Default to User Settings + onSelect={handleScopeSelect} + onHighlight={handleScopeHighlight} + isFocused={focusedSection === 'scope'} + /> + </Box> + + <Box marginTop={1}> + <Text color={Colors.SubtleComment}> + (Use ↑/↓ arrows and Enter to select, Tab to change focus) + </Text> + </Box> </Box> - <Box marginTop={1} flexDirection="column"> + {/* Right Column: Preview */} + <Box flexDirection="column" width="50%" paddingLeft={3}> <Text bold>Preview</Text> <Box borderStyle="single" diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 401b8ee0..a9a51232 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -27,7 +27,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ const hasPending = !toolCalls.every( (t) => t.status === ToolCallStatus.Success, ); - const borderColor = hasPending ? Colors.AccentYellow : Colors.AccentCyan; + const borderColor = hasPending ? Colors.AccentYellow : Colors.AccentPurple; return ( <Box diff --git a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx index 3db8b678..377be3e3 100644 --- a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx +++ b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx @@ -27,7 +27,12 @@ export interface RadioSelectItem<T> { */ export interface RadioButtonSelectProps<T> { /** An array of items to display as radio options. */ - items: Array<RadioSelectItem<T>>; + items: Array< + RadioSelectItem<T> & { + themeNameDisplay?: string; + themeTypeDisplay?: string; + } + >; /** The initial index selected */ initialIndex?: number; @@ -43,33 +48,6 @@ export interface RadioButtonSelectProps<T> { } /** - * Custom indicator component displaying radio button style (◉/○). - */ -function RadioIndicator({ - isSelected = false, -}: InkSelectIndicatorProps): React.JSX.Element { - return ( - <Box marginRight={1}> - <Text color={isSelected ? Colors.AccentGreen : Colors.Gray}> - {isSelected ? '◉' : '○'} - </Text> - </Box> - ); -} - -/** - * Custom item component for displaying the label with appropriate color. - */ -function RadioItem({ - isSelected = false, - label, -}: InkSelectItemProps): React.JSX.Element { - return ( - <Text color={isSelected ? Colors.AccentGreen : Colors.Gray}>{label}</Text> - ); -} - -/** * A specialized SelectInput component styled to look like radio buttons. * It uses '◉' for selected and '○' for unselected items. * @@ -80,7 +58,7 @@ export function RadioButtonSelect<T>({ initialIndex, onSelect, onHighlight, - isFocused, + isFocused, // This prop indicates if the current RadioButtonSelect group is focused }: RadioButtonSelectProps<T>): React.JSX.Element { const handleSelect = (item: RadioSelectItem<T>) => { onSelect(item.value); @@ -90,11 +68,72 @@ export function RadioButtonSelect<T>({ onHighlight(item.value); } }; + + /** + * Custom indicator component displaying radio button style (◉/○). + * Color changes based on whether the item is selected and if its group is focused. + */ + function DynamicRadioIndicator({ + isSelected = false, + }: InkSelectIndicatorProps): React.JSX.Element { + let indicatorColor = Colors.Foreground; // Default for not selected + if (isSelected) { + if (isFocused) { + // Group is focused, selected item is AccentGreen + indicatorColor = Colors.AccentGreen; + } else { + // Group is NOT focused, selected item is Foreground + indicatorColor = Colors.Foreground; + } + } + return ( + <Box marginRight={1}> + <Text color={indicatorColor}>{isSelected ? '●' : '○'}</Text> + </Box> + ); + } + + /** + * Custom item component for displaying the label. + * Color changes based on whether the item is selected and if its group is focused. + * Now also handles displaying theme type with custom color. + */ + function CustomThemeItemComponent( + props: InkSelectItemProps, + ): React.JSX.Element { + const { isSelected = false, label } = props; + const itemWithThemeProps = props as typeof props & { + themeNameDisplay?: string; + themeTypeDisplay?: string; + }; + + let textColor = Colors.Foreground; + if (isSelected) { + textColor = isFocused ? Colors.AccentGreen : Colors.Foreground; + } + + if ( + itemWithThemeProps.themeNameDisplay && + itemWithThemeProps.themeTypeDisplay + ) { + return ( + <Text color={textColor}> + {itemWithThemeProps.themeNameDisplay}{' '} + <Text color={Colors.SubtleComment}> + {itemWithThemeProps.themeTypeDisplay} + </Text> + </Text> + ); + } + + return <Text color={textColor}>{label}</Text>; + } + initialIndex = initialIndex ?? 0; return ( <SelectInput - indicatorComponent={RadioIndicator} - itemComponent={RadioItem} + indicatorComponent={DynamicRadioIndicator} + itemComponent={CustomThemeItemComponent} items={items} initialIndex={initialIndex} onSelect={handleSelect} |
