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

View File

@@ -106,6 +106,7 @@ describe('<Header />', () => {
comment: '',
symbol: '',
dark: '',
focus: '',
gradient: undefined,
},
status: {

View File

@@ -8,6 +8,7 @@ import type React from 'react';
import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { Box, Text } from 'ink';
import { Colors } from '../colors.js';
import { theme } from '../semantic-colors.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { useKeypress } from '../hooks/useKeypress.js';
import path from 'node:path';
@@ -436,7 +437,7 @@ const SessionItem = ({
if (isDisabled) {
return Colors.Gray;
}
return isActive ? Colors.AccentPurple : c;
return isActive ? theme.ui.focus : c;
};
const prefix = isActive ? ' ' : ' ';

View File

@@ -84,7 +84,7 @@ export function SuggestionsDisplay({
const originalIndex = startIndex + index;
const isActive = originalIndex === activeIndex;
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 labelElement = (
<ExpandableText

View File

@@ -117,8 +117,8 @@ export function BaseSelectionList<
let numberColor = theme.text.primary;
if (isSelected) {
titleColor = theme.status.success;
numberColor = theme.status.success;
titleColor = theme.ui.focus;
numberColor = theme.ui.focus;
} else if (item.disabled) {
titleColor = theme.text.secondary;
numberColor = theme.text.secondary;
@@ -141,7 +141,7 @@ export function BaseSelectionList<
{/* Radio button indicator */}
<Box minWidth={2} flexShrink={0}>
<Text
color={isSelected ? theme.status.success : theme.text.primary}
color={isSelected ? theme.ui.focus : theme.text.primary}
aria-hidden
>
{isSelected ? '●' : ' '}

View File

@@ -517,9 +517,7 @@ export function BaseSettingsDialog({
<Box marginX={1} flexDirection="row" alignItems="flex-start">
<Box minWidth={2} flexShrink={0}>
<Text
color={
isActive ? theme.status.success : theme.text.secondary
}
color={isActive ? theme.ui.focus : theme.text.secondary}
>
{isActive ? '●' : ''}
</Text>
@@ -536,9 +534,7 @@ export function BaseSettingsDialog({
minWidth={0}
>
<Text
color={
isActive ? theme.status.success : theme.text.primary
}
color={isActive ? theme.ui.focus : theme.text.primary}
>
{item.label}
{item.scopeMessage && (
@@ -557,7 +553,7 @@ export function BaseSettingsDialog({
<Text
color={
isActive
? theme.status.success
? theme.ui.focus
: item.isGreyedOut
? theme.text.secondary
: theme.text.primary

View File

@@ -49,6 +49,7 @@ const noColorSemanticColors: SemanticColors = {
comment: '',
symbol: '',
dark: '',
focus: '',
gradient: [],
},
status: {

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { lightTheme, darkTheme } from './theme.js';
import { lightTheme, darkTheme, ansiTheme } from './theme.js';
export interface SemanticColors {
text: {
@@ -29,6 +29,7 @@ export interface SemanticColors {
comment: string;
symbol: string;
dark: string;
focus: string;
gradient: string[] | undefined;
};
status: {
@@ -61,6 +62,7 @@ export const lightSemanticColors: SemanticColors = {
comment: lightTheme.Comment,
symbol: lightTheme.Gray,
dark: lightTheme.DarkGray,
focus: lightTheme.AccentBlue,
gradient: lightTheme.GradientColors,
},
status: {
@@ -93,6 +95,7 @@ export const darkSemanticColors: SemanticColors = {
comment: darkTheme.Comment,
symbol: darkTheme.Gray,
dark: darkTheme.DarkGray,
focus: darkTheme.AccentBlue,
gradient: darkTheme.GradientColors,
},
status: {
@@ -101,3 +104,36 @@ export const darkSemanticColors: SemanticColors = {
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,
},
};

View File

@@ -148,6 +148,7 @@ export class Theme {
comment: this.colors.Gray,
symbol: this.colors.AccentCyan,
dark: this.colors.DarkGray,
focus: this.colors.AccentBlue,
gradient: this.colors.GradientColors,
},
status: {
@@ -419,6 +420,7 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
comment: customTheme.ui?.comment ?? colors.Comment,
symbol: customTheme.ui?.symbol ?? colors.Gray,
dark: colors.DarkGray,
focus: customTheme.ui?.focus ?? colors.AccentBlue,
gradient: customTheme.ui?.gradient ?? colors.GradientColors,
},
status: {

View File

@@ -233,6 +233,7 @@ export interface CustomTheme {
ui?: {
comment?: string;
symbol?: string;
focus?: string;
gradient?: string[];
};
status?: {