mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
refactor(ui): Update and simplify use of gray colors in themes (#20141)
This commit is contained in:
@@ -53,6 +53,12 @@ export const Colors: ColorsTheme = {
|
||||
get DarkGray() {
|
||||
return themeManager.getColors().DarkGray;
|
||||
},
|
||||
get InputBackground() {
|
||||
return themeManager.getColors().InputBackground;
|
||||
},
|
||||
get MessageBackground() {
|
||||
return themeManager.getColors().MessageBackground;
|
||||
},
|
||||
get GradientColors() {
|
||||
return themeManager.getActiveTheme().colors.GradientColors;
|
||||
},
|
||||
|
||||
@@ -96,6 +96,8 @@ describe('<Header />', () => {
|
||||
},
|
||||
background: {
|
||||
primary: '',
|
||||
message: '',
|
||||
input: '',
|
||||
diff: { added: '', removed: '' },
|
||||
},
|
||||
border: {
|
||||
|
||||
@@ -56,10 +56,6 @@ import {
|
||||
} from '../utils/commandUtils.js';
|
||||
import * as path from 'node:path';
|
||||
import { SCREEN_READER_USER_PREFIX } from '../textConstants.js';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
} from '../constants.js';
|
||||
import { getSafeLowColorBackground } from '../themes/color-utils.js';
|
||||
import { isLowColorDepth } from '../utils/terminalUtils.js';
|
||||
import { useShellFocusState } from '../contexts/ShellFocusContext.js';
|
||||
@@ -226,7 +222,6 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
backgroundShells,
|
||||
backgroundShellHeight,
|
||||
shortcutsHelpVisible,
|
||||
hintMode,
|
||||
} = useUIState();
|
||||
const [suppressCompletion, setSuppressCompletion] = useState(false);
|
||||
const { handlePress: registerPlainTabPress, resetCount: resetPlainTabPress } =
|
||||
@@ -1422,14 +1417,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
/>
|
||||
) : null}
|
||||
<HalfLinePaddedBox
|
||||
backgroundBaseColor={
|
||||
hintMode ? theme.text.accent : theme.text.secondary
|
||||
}
|
||||
backgroundOpacity={
|
||||
showCursor
|
||||
? DEFAULT_INPUT_BACKGROUND_OPACITY
|
||||
: DEFAULT_BACKGROUND_OPACITY
|
||||
}
|
||||
backgroundBaseColor={theme.background.input}
|
||||
backgroundOpacity={1}
|
||||
useBackgroundColor={useBackgroundColor}
|
||||
>
|
||||
<Box
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
calculateTransformedLine,
|
||||
} from '../shared/text-buffer.js';
|
||||
import { HalfLinePaddedBox } from '../shared/HalfLinePaddedBox.js';
|
||||
import { DEFAULT_BACKGROUND_OPACITY } from '../../constants.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
|
||||
interface UserMessageProps {
|
||||
@@ -52,8 +51,8 @@ export const UserMessage: React.FC<UserMessageProps> = ({ text, width }) => {
|
||||
|
||||
return (
|
||||
<HalfLinePaddedBox
|
||||
backgroundBaseColor={theme.text.secondary}
|
||||
backgroundOpacity={DEFAULT_BACKGROUND_OPACITY}
|
||||
backgroundBaseColor={theme.background.message}
|
||||
backgroundOpacity={1}
|
||||
useBackgroundColor={useBackgroundColor}
|
||||
>
|
||||
<Box
|
||||
|
||||
@@ -8,7 +8,6 @@ import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { HalfLinePaddedBox } from '../shared/HalfLinePaddedBox.js';
|
||||
import { DEFAULT_BACKGROUND_OPACITY } from '../../constants.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
|
||||
interface UserShellMessageProps {
|
||||
@@ -28,8 +27,8 @@ export const UserShellMessage: React.FC<UserShellMessageProps> = ({
|
||||
|
||||
return (
|
||||
<HalfLinePaddedBox
|
||||
backgroundBaseColor={theme.text.secondary}
|
||||
backgroundOpacity={DEFAULT_BACKGROUND_OPACITY}
|
||||
backgroundBaseColor={theme.background.message}
|
||||
backgroundOpacity={1}
|
||||
useBackgroundColor={useBackgroundColor}
|
||||
>
|
||||
<Box
|
||||
|
||||
@@ -37,7 +37,7 @@ export const EXPAND_HINT_DURATION_MS = 5000;
|
||||
|
||||
export const DEFAULT_BACKGROUND_OPACITY = 0.16;
|
||||
export const DEFAULT_INPUT_BACKGROUND_OPACITY = 0.24;
|
||||
export const DEFAULT_BORDER_OPACITY = 0.2;
|
||||
export const DEFAULT_BORDER_OPACITY = 0.4;
|
||||
|
||||
export const KEYBOARD_SHORTCUTS_URL =
|
||||
'https://geminicli.com/docs/cli/keyboard-shortcuts/';
|
||||
|
||||
@@ -24,6 +24,8 @@ const noColorColorsTheme: ColorsTheme = {
|
||||
Comment: '',
|
||||
Gray: '',
|
||||
DarkGray: '',
|
||||
InputBackground: '',
|
||||
MessageBackground: '',
|
||||
};
|
||||
|
||||
const noColorSemanticColors: SemanticColors = {
|
||||
@@ -36,6 +38,8 @@ const noColorSemanticColors: SemanticColors = {
|
||||
},
|
||||
background: {
|
||||
primary: '',
|
||||
message: '',
|
||||
input: '',
|
||||
diff: {
|
||||
added: '',
|
||||
removed: '',
|
||||
|
||||
@@ -16,6 +16,8 @@ export interface SemanticColors {
|
||||
};
|
||||
background: {
|
||||
primary: string;
|
||||
message: string;
|
||||
input: string;
|
||||
diff: {
|
||||
added: string;
|
||||
removed: string;
|
||||
@@ -48,13 +50,15 @@ export const lightSemanticColors: SemanticColors = {
|
||||
},
|
||||
background: {
|
||||
primary: lightTheme.Background,
|
||||
message: lightTheme.MessageBackground!,
|
||||
input: lightTheme.InputBackground!,
|
||||
diff: {
|
||||
added: lightTheme.DiffAdded,
|
||||
removed: lightTheme.DiffRemoved,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
default: lightTheme.Gray,
|
||||
default: lightTheme.DarkGray,
|
||||
focused: lightTheme.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
@@ -80,13 +84,15 @@ export const darkSemanticColors: SemanticColors = {
|
||||
},
|
||||
background: {
|
||||
primary: darkTheme.Background,
|
||||
message: darkTheme.MessageBackground!,
|
||||
input: darkTheme.InputBackground!,
|
||||
diff: {
|
||||
added: darkTheme.DiffAdded,
|
||||
removed: darkTheme.DiffRemoved,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
default: darkTheme.Gray,
|
||||
default: darkTheme.DarkGray,
|
||||
focused: darkTheme.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
|
||||
@@ -36,6 +36,8 @@ const semanticColors: SemanticColors = {
|
||||
},
|
||||
background: {
|
||||
primary: '#002b36',
|
||||
message: '#073642',
|
||||
input: '#073642',
|
||||
diff: {
|
||||
added: '#00382f',
|
||||
removed: '#3d0115',
|
||||
|
||||
@@ -36,6 +36,8 @@ const semanticColors: SemanticColors = {
|
||||
},
|
||||
background: {
|
||||
primary: '#fdf6e3',
|
||||
message: '#eee8d5',
|
||||
input: '#eee8d5',
|
||||
diff: {
|
||||
added: '#d7f2d7',
|
||||
removed: '#f2d7d7',
|
||||
|
||||
@@ -29,7 +29,11 @@ import {
|
||||
getThemeTypeFromBackgroundColor,
|
||||
resolveColor,
|
||||
} from './color-utils.js';
|
||||
import { DEFAULT_BORDER_OPACITY } from '../constants.js';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
} from '../constants.js';
|
||||
import { ANSI } from './ansi.js';
|
||||
import { ANSILight } from './ansi-light.js';
|
||||
import { NoColorTheme } from './no-color.js';
|
||||
@@ -310,7 +314,21 @@ class ThemeManager {
|
||||
this.cachedColors = {
|
||||
...colors,
|
||||
Background: this.terminalBackground,
|
||||
DarkGray: interpolateColor(colors.Gray, this.terminalBackground, 0.5),
|
||||
DarkGray: interpolateColor(
|
||||
this.terminalBackground,
|
||||
colors.Gray,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
),
|
||||
InputBackground: interpolateColor(
|
||||
this.terminalBackground,
|
||||
colors.Gray,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
MessageBackground: interpolateColor(
|
||||
this.terminalBackground,
|
||||
colors.Gray,
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
};
|
||||
} else {
|
||||
this.cachedColors = colors;
|
||||
@@ -336,27 +354,22 @@ class ThemeManager {
|
||||
this.terminalBackground &&
|
||||
this.isThemeCompatible(activeTheme, this.terminalBackground)
|
||||
) {
|
||||
const colors = this.getColors();
|
||||
this.cachedSemanticColors = {
|
||||
...semanticColors,
|
||||
background: {
|
||||
...semanticColors.background,
|
||||
primary: this.terminalBackground,
|
||||
message: colors.MessageBackground!,
|
||||
input: colors.InputBackground!,
|
||||
},
|
||||
border: {
|
||||
...semanticColors.border,
|
||||
default: interpolateColor(
|
||||
this.terminalBackground,
|
||||
activeTheme.colors.Gray,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
),
|
||||
default: colors.DarkGray,
|
||||
},
|
||||
ui: {
|
||||
...semanticColors.ui,
|
||||
dark: interpolateColor(
|
||||
activeTheme.colors.Gray,
|
||||
this.terminalBackground,
|
||||
0.5,
|
||||
),
|
||||
dark: colors.DarkGray,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -37,11 +37,11 @@ describe('createCustomTheme', () => {
|
||||
|
||||
it('should interpolate DarkGray when not provided', () => {
|
||||
const theme = createCustomTheme(baseTheme);
|
||||
// Interpolate between Gray (#cccccc) and Background (#000000) at 0.5
|
||||
// Interpolate between Background (#000000) and Gray (#cccccc) at 0.4
|
||||
// #cccccc is RGB(204, 204, 204)
|
||||
// #000000 is RGB(0, 0, 0)
|
||||
// Midpoint is RGB(102, 102, 102) which is #666666
|
||||
expect(theme.colors.DarkGray).toBe('#666666');
|
||||
// Result is RGB(82, 82, 82) which is #525252
|
||||
expect(theme.colors.DarkGray).toBe('#525252');
|
||||
});
|
||||
|
||||
it('should use provided DarkGray', () => {
|
||||
@@ -64,8 +64,8 @@ describe('createCustomTheme', () => {
|
||||
},
|
||||
};
|
||||
const theme = createCustomTheme(customTheme);
|
||||
// Should be interpolated between #cccccc and #000000 at 0.5 -> #666666
|
||||
expect(theme.colors.DarkGray).toBe('#666666');
|
||||
// Should be interpolated between #000000 and #cccccc at 0.4 -> #525252
|
||||
expect(theme.colors.DarkGray).toBe('#525252');
|
||||
});
|
||||
|
||||
it('should prefer text.secondary over Gray for interpolation', () => {
|
||||
@@ -81,8 +81,8 @@ describe('createCustomTheme', () => {
|
||||
},
|
||||
};
|
||||
const theme = createCustomTheme(customTheme);
|
||||
// Interpolate between #cccccc and #000000 -> #666666
|
||||
expect(theme.colors.DarkGray).toBe('#666666');
|
||||
// Interpolate between #000000 and #cccccc -> #525252
|
||||
expect(theme.colors.DarkGray).toBe('#525252');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,11 @@ import {
|
||||
} from './color-utils.js';
|
||||
|
||||
import type { CustomTheme } from '@google/gemini-cli-core';
|
||||
import { DEFAULT_BORDER_OPACITY } from '../constants.js';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
} from '../constants.js';
|
||||
|
||||
export type { CustomTheme };
|
||||
|
||||
@@ -37,6 +41,8 @@ export interface ColorsTheme {
|
||||
Comment: string;
|
||||
Gray: string;
|
||||
DarkGray: string;
|
||||
InputBackground?: string;
|
||||
MessageBackground?: string;
|
||||
GradientColors?: string[];
|
||||
}
|
||||
|
||||
@@ -55,7 +61,17 @@ export const lightTheme: ColorsTheme = {
|
||||
DiffRemoved: '#FFCCCC',
|
||||
Comment: '#008000',
|
||||
Gray: '#97a0b0',
|
||||
DarkGray: interpolateColor('#97a0b0', '#FAFAFA', 0.5),
|
||||
DarkGray: interpolateColor('#FAFAFA', '#97a0b0', DEFAULT_BORDER_OPACITY),
|
||||
InputBackground: interpolateColor(
|
||||
'#FAFAFA',
|
||||
'#97a0b0',
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
MessageBackground: interpolateColor(
|
||||
'#FAFAFA',
|
||||
'#97a0b0',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
|
||||
@@ -74,7 +90,17 @@ export const darkTheme: ColorsTheme = {
|
||||
DiffRemoved: '#430000',
|
||||
Comment: '#6C7086',
|
||||
Gray: '#6C7086',
|
||||
DarkGray: interpolateColor('#6C7086', '#1E1E2E', 0.5),
|
||||
DarkGray: interpolateColor('#1E1E2E', '#6C7086', DEFAULT_BORDER_OPACITY),
|
||||
InputBackground: interpolateColor(
|
||||
'#1E1E2E',
|
||||
'#6C7086',
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
MessageBackground: interpolateColor(
|
||||
'#1E1E2E',
|
||||
'#6C7086',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
|
||||
@@ -94,6 +120,8 @@ export const ansiTheme: ColorsTheme = {
|
||||
Comment: 'gray',
|
||||
Gray: 'gray',
|
||||
DarkGray: 'gray',
|
||||
InputBackground: 'black',
|
||||
MessageBackground: 'black',
|
||||
};
|
||||
|
||||
export class Theme {
|
||||
@@ -131,17 +159,27 @@ export class Theme {
|
||||
},
|
||||
background: {
|
||||
primary: this.colors.Background,
|
||||
message:
|
||||
this.colors.MessageBackground ??
|
||||
interpolateColor(
|
||||
this.colors.Background,
|
||||
this.colors.Gray,
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
input:
|
||||
this.colors.InputBackground ??
|
||||
interpolateColor(
|
||||
this.colors.Background,
|
||||
this.colors.Gray,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
diff: {
|
||||
added: this.colors.DiffAdded,
|
||||
removed: this.colors.DiffRemoved,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
default: interpolateColor(
|
||||
this.colors.Background,
|
||||
this.colors.Gray,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
),
|
||||
default: this.colors.DarkGray,
|
||||
focused: this.colors.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
@@ -242,10 +280,20 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
DarkGray:
|
||||
customTheme.DarkGray ??
|
||||
interpolateColor(
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
0.5,
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
),
|
||||
InputBackground: interpolateColor(
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
MessageBackground: interpolateColor(
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
GradientColors: customTheme.ui?.gradient ?? customTheme.GradientColors,
|
||||
};
|
||||
|
||||
@@ -400,19 +448,15 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
},
|
||||
background: {
|
||||
primary: customTheme.background?.primary ?? colors.Background,
|
||||
message: colors.MessageBackground!,
|
||||
input: colors.InputBackground!,
|
||||
diff: {
|
||||
added: customTheme.background?.diff?.added ?? colors.DiffAdded,
|
||||
removed: customTheme.background?.diff?.removed ?? colors.DiffRemoved,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
default:
|
||||
customTheme.border?.default ??
|
||||
interpolateColor(
|
||||
colors.Background,
|
||||
colors.Gray,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
),
|
||||
default: colors.DarkGray,
|
||||
focused: customTheme.border?.focused ?? colors.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
|
||||
Reference in New Issue
Block a user