feat(ui): standardize FOCUS color to Blue across all themes and selection components

This commit is contained in:
Keith Guerin
2026-02-27 11:55:20 -08:00
parent 81cd2561dc
commit 9efa855642
9 changed files with 51 additions and 13 deletions
@@ -106,6 +106,7 @@ describe('<Header />', () => {
comment: '', comment: '',
symbol: '', symbol: '',
dark: '', dark: '',
focus: '',
gradient: undefined, gradient: undefined,
}, },
status: { status: {
@@ -8,6 +8,7 @@ import type React from 'react';
import { useState, useCallback, useMemo, useEffect, useRef } from 'react'; import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { Box, Text } from 'ink'; import { Box, Text } from 'ink';
import { Colors } from '../colors.js'; import { Colors } from '../colors.js';
import { theme } from '../semantic-colors.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js'; import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { useKeypress } from '../hooks/useKeypress.js'; import { useKeypress } from '../hooks/useKeypress.js';
import path from 'node:path'; import path from 'node:path';
@@ -436,7 +437,7 @@ const SessionItem = ({
if (isDisabled) { if (isDisabled) {
return Colors.Gray; return Colors.Gray;
} }
return isActive ? Colors.AccentPurple : c; return isActive ? theme.ui.focus : c;
}; };
const prefix = isActive ? ' ' : ' '; const prefix = isActive ? ' ' : ' ';
@@ -84,7 +84,7 @@ export function SuggestionsDisplay({
const originalIndex = startIndex + index; const originalIndex = startIndex + index;
const isActive = originalIndex === activeIndex; const isActive = originalIndex === activeIndex;
const isExpanded = originalIndex === expandedIndex; const isExpanded = originalIndex === expandedIndex;
const textColor = isActive ? theme.text.accent : theme.text.secondary; const textColor = isActive ? theme.ui.focus : theme.text.secondary;
const isLong = suggestion.value.length >= MAX_WIDTH; const isLong = suggestion.value.length >= MAX_WIDTH;
const labelElement = ( const labelElement = (
<ExpandableText <ExpandableText
@@ -117,8 +117,8 @@ export function BaseSelectionList<
let numberColor = theme.text.primary; let numberColor = theme.text.primary;
if (isSelected) { if (isSelected) {
titleColor = theme.status.success; titleColor = theme.ui.focus;
numberColor = theme.status.success; numberColor = theme.ui.focus;
} else if (item.disabled) { } else if (item.disabled) {
titleColor = theme.text.secondary; titleColor = theme.text.secondary;
numberColor = theme.text.secondary; numberColor = theme.text.secondary;
@@ -141,7 +141,7 @@ export function BaseSelectionList<
{/* Radio button indicator */} {/* Radio button indicator */}
<Box minWidth={2} flexShrink={0}> <Box minWidth={2} flexShrink={0}>
<Text <Text
color={isSelected ? theme.status.success : theme.text.primary} color={isSelected ? theme.ui.focus : theme.text.primary}
aria-hidden aria-hidden
> >
{isSelected ? '●' : ' '} {isSelected ? '●' : ' '}
@@ -517,9 +517,7 @@ export function BaseSettingsDialog({
<Box marginX={1} flexDirection="row" alignItems="flex-start"> <Box marginX={1} flexDirection="row" alignItems="flex-start">
<Box minWidth={2} flexShrink={0}> <Box minWidth={2} flexShrink={0}>
<Text <Text
color={ color={isActive ? theme.ui.focus : theme.text.secondary}
isActive ? theme.status.success : theme.text.secondary
}
> >
{isActive ? '●' : ''} {isActive ? '●' : ''}
</Text> </Text>
@@ -536,9 +534,7 @@ export function BaseSettingsDialog({
minWidth={0} minWidth={0}
> >
<Text <Text
color={ color={isActive ? theme.ui.focus : theme.text.primary}
isActive ? theme.status.success : theme.text.primary
}
> >
{item.label} {item.label}
{item.scopeMessage && ( {item.scopeMessage && (
@@ -557,7 +553,7 @@ export function BaseSettingsDialog({
<Text <Text
color={ color={
isActive isActive
? theme.status.success ? theme.ui.focus
: item.isGreyedOut : item.isGreyedOut
? theme.text.secondary ? theme.text.secondary
: theme.text.primary : theme.text.primary
+1
View File
@@ -49,6 +49,7 @@ const noColorSemanticColors: SemanticColors = {
comment: '', comment: '',
symbol: '', symbol: '',
dark: '', dark: '',
focus: '',
gradient: [], gradient: [],
}, },
status: { status: {
+37 -1
View File
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import { lightTheme, darkTheme } from './theme.js'; import { lightTheme, darkTheme, ansiTheme } from './theme.js';
export interface SemanticColors { export interface SemanticColors {
text: { text: {
@@ -29,6 +29,7 @@ export interface SemanticColors {
comment: string; comment: string;
symbol: string; symbol: string;
dark: string; dark: string;
focus: string;
gradient: string[] | undefined; gradient: string[] | undefined;
}; };
status: { status: {
@@ -61,6 +62,7 @@ export const lightSemanticColors: SemanticColors = {
comment: lightTheme.Comment, comment: lightTheme.Comment,
symbol: lightTheme.Gray, symbol: lightTheme.Gray,
dark: lightTheme.DarkGray, dark: lightTheme.DarkGray,
focus: lightTheme.AccentBlue,
gradient: lightTheme.GradientColors, gradient: lightTheme.GradientColors,
}, },
status: { status: {
@@ -93,6 +95,7 @@ export const darkSemanticColors: SemanticColors = {
comment: darkTheme.Comment, comment: darkTheme.Comment,
symbol: darkTheme.Gray, symbol: darkTheme.Gray,
dark: darkTheme.DarkGray, dark: darkTheme.DarkGray,
focus: darkTheme.AccentBlue,
gradient: darkTheme.GradientColors, gradient: darkTheme.GradientColors,
}, },
status: { status: {
@@ -101,3 +104,36 @@ export const darkSemanticColors: SemanticColors = {
warning: darkTheme.AccentYellow, warning: darkTheme.AccentYellow,
}, },
}; };
export const ansiSemanticColors: SemanticColors = {
text: {
primary: ansiTheme.Foreground,
secondary: ansiTheme.Gray,
link: ansiTheme.AccentBlue,
accent: ansiTheme.AccentPurple,
response: ansiTheme.Foreground,
},
background: {
primary: ansiTheme.Background,
diff: {
added: ansiTheme.DiffAdded,
removed: ansiTheme.DiffRemoved,
},
},
border: {
default: ansiTheme.Gray,
focused: ansiTheme.AccentBlue,
},
ui: {
comment: ansiTheme.Comment,
symbol: ansiTheme.Gray,
dark: ansiTheme.DarkGray,
focus: ansiTheme.AccentBlue,
gradient: ansiTheme.GradientColors,
},
status: {
error: ansiTheme.AccentRed,
success: ansiTheme.AccentGreen,
warning: ansiTheme.AccentYellow,
},
};
+2
View File
@@ -148,6 +148,7 @@ export class Theme {
comment: this.colors.Gray, comment: this.colors.Gray,
symbol: this.colors.AccentCyan, symbol: this.colors.AccentCyan,
dark: this.colors.DarkGray, dark: this.colors.DarkGray,
focus: this.colors.AccentBlue,
gradient: this.colors.GradientColors, gradient: this.colors.GradientColors,
}, },
status: { status: {
@@ -419,6 +420,7 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
comment: customTheme.ui?.comment ?? colors.Comment, comment: customTheme.ui?.comment ?? colors.Comment,
symbol: customTheme.ui?.symbol ?? colors.Gray, symbol: customTheme.ui?.symbol ?? colors.Gray,
dark: colors.DarkGray, dark: colors.DarkGray,
focus: customTheme.ui?.focus ?? colors.AccentBlue,
gradient: customTheme.ui?.gradient ?? colors.GradientColors, gradient: customTheme.ui?.gradient ?? colors.GradientColors,
}, },
status: { status: {
+1
View File
@@ -233,6 +233,7 @@ export interface CustomTheme {
ui?: { ui?: {
comment?: string; comment?: string;
symbol?: string; symbol?: string;
focus?: string;
gradient?: string[]; gradient?: string[];
}; };
status?: { status?: {