mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-16 00:51:25 -07:00
Add DarkGray to the ColorTheme. (#12420)
This commit is contained in:
@@ -50,6 +50,9 @@ export const Colors: ColorsTheme = {
|
||||
get Gray() {
|
||||
return themeManager.getActiveTheme().colors.Gray;
|
||||
},
|
||||
get DarkGray() {
|
||||
return themeManager.getActiveTheme().colors.DarkGray;
|
||||
},
|
||||
get GradientColors() {
|
||||
return themeManager.getActiveTheme().colors.GradientColors;
|
||||
},
|
||||
|
||||
@@ -22,6 +22,7 @@ const ansiLightColors: ColorsTheme = {
|
||||
DiffRemoved: '#FFE5E5',
|
||||
Comment: 'gray',
|
||||
Gray: 'gray',
|
||||
DarkGray: 'gray',
|
||||
GradientColors: ['blue', 'green'],
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ const ansiColors: ColorsTheme = {
|
||||
DiffRemoved: '#4D0000',
|
||||
Comment: 'gray',
|
||||
Gray: 'gray',
|
||||
DarkGray: 'gray',
|
||||
GradientColors: ['cyan', 'green'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const atomOneDarkColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -21,6 +22,7 @@ const atomOneDarkColors: ColorsTheme = {
|
||||
DiffRemoved: '#562B2F',
|
||||
Comment: '#5c6370',
|
||||
Gray: '#5c6370',
|
||||
DarkGray: interpolateColor('#5c6370', '#282c34', 0.5),
|
||||
GradientColors: ['#61aeee', '#98c379'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const ayuLightColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
@@ -21,6 +22,7 @@ const ayuLightColors: ColorsTheme = {
|
||||
DiffRemoved: '#FFCCCC',
|
||||
Comment: '#ABADB1',
|
||||
Gray: '#a6aaaf',
|
||||
DarkGray: interpolateColor('#a6aaaf', '#f8f9fa', 0.5),
|
||||
GradientColors: ['#399ee6', '#86b300'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const ayuDarkColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -21,6 +22,7 @@ const ayuDarkColors: ColorsTheme = {
|
||||
DiffRemoved: '#3D1215',
|
||||
Comment: '#646A71',
|
||||
Gray: '#3D4149',
|
||||
DarkGray: interpolateColor('#3D4149', '#0b0e14', 0.5),
|
||||
GradientColors: ['#FFB454', '#F26D78'],
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
isValidColor,
|
||||
resolveColor,
|
||||
interpolateColor,
|
||||
CSS_NAME_TO_HEX_MAP,
|
||||
INK_SUPPORTED_NAMES,
|
||||
} from './color-utils.js';
|
||||
@@ -218,4 +219,19 @@ describe('Color Utils', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolateColor', () => {
|
||||
it('should interpolate between two colors', () => {
|
||||
// Midpoint between black (#000000) and white (#ffffff) should be gray
|
||||
expect(interpolateColor('#000000', '#ffffff', 0.5)).toBe('#7f7f7f');
|
||||
});
|
||||
|
||||
it('should return start color when factor is 0', () => {
|
||||
expect(interpolateColor('#ff0000', '#0000ff', 0)).toBe('#ff0000');
|
||||
});
|
||||
|
||||
it('should return end color when factor is 1', () => {
|
||||
expect(interpolateColor('#ff0000', '#0000ff', 1)).toBe('#0000ff');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
import tinygradient from 'tinygradient';
|
||||
|
||||
// Mapping from common CSS color names (lowercase) to hex codes (lowercase)
|
||||
// Excludes names directly supported by Ink
|
||||
@@ -231,3 +232,13 @@ export function resolveColor(colorValue: string): string | undefined {
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function interpolateColor(
|
||||
color1: string,
|
||||
color2: string,
|
||||
factor: number,
|
||||
) {
|
||||
const gradient = tinygradient(color1, color2);
|
||||
const color = gradient.rgbAt(factor);
|
||||
return color.toHexString();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const draculaColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -21,6 +22,7 @@ const draculaColors: ColorsTheme = {
|
||||
DiffRemoved: '#6e1818',
|
||||
Comment: '#6272a4',
|
||||
Gray: '#6272a4',
|
||||
DarkGray: interpolateColor('#6272a4', '#282a36', 0.5),
|
||||
GradientColors: ['#ff79c6', '#8be9fd'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const githubDarkColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -21,6 +22,7 @@ const githubDarkColors: ColorsTheme = {
|
||||
DiffRemoved: '#502125',
|
||||
Comment: '#6A737D',
|
||||
Gray: '#6A737D',
|
||||
DarkGray: interpolateColor('#6A737D', '#24292e', 0.5),
|
||||
GradientColors: ['#79B8FF', '#85E89D'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const githubLightColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
@@ -21,6 +22,7 @@ const githubLightColors: ColorsTheme = {
|
||||
DiffRemoved: '#FFCCCC',
|
||||
Comment: '#998',
|
||||
Gray: '#999',
|
||||
DarkGray: interpolateColor('#999', '#f8f8f8', 0.5),
|
||||
GradientColors: ['#458', '#008080'],
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme, lightTheme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const googleCodeColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
@@ -21,6 +22,7 @@ const googleCodeColors: ColorsTheme = {
|
||||
DiffRemoved: '#FEDEDE',
|
||||
Comment: '#5f6368',
|
||||
Gray: lightTheme.Gray,
|
||||
DarkGray: interpolateColor(lightTheme.Gray, '#ffffff', 0.5),
|
||||
GradientColors: ['#066', '#606'],
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ const noColorColorsTheme: ColorsTheme = {
|
||||
DiffRemoved: '',
|
||||
Comment: '',
|
||||
Gray: '',
|
||||
DarkGray: '',
|
||||
};
|
||||
|
||||
const noColorSemanticColors: SemanticColors = {
|
||||
@@ -46,6 +47,7 @@ const noColorSemanticColors: SemanticColors = {
|
||||
ui: {
|
||||
comment: '',
|
||||
symbol: '',
|
||||
dark: '',
|
||||
gradient: [],
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface SemanticColors {
|
||||
ui: {
|
||||
comment: string;
|
||||
symbol: string;
|
||||
dark: string;
|
||||
gradient: string[] | undefined;
|
||||
};
|
||||
status: {
|
||||
@@ -57,6 +58,7 @@ export const lightSemanticColors: SemanticColors = {
|
||||
ui: {
|
||||
comment: lightTheme.Comment,
|
||||
symbol: lightTheme.Gray,
|
||||
dark: lightTheme.DarkGray,
|
||||
gradient: lightTheme.GradientColors,
|
||||
},
|
||||
status: {
|
||||
@@ -87,6 +89,7 @@ export const darkSemanticColors: SemanticColors = {
|
||||
ui: {
|
||||
comment: darkTheme.Comment,
|
||||
symbol: darkTheme.Gray,
|
||||
dark: darkTheme.DarkGray,
|
||||
gradient: darkTheme.GradientColors,
|
||||
},
|
||||
status: {
|
||||
@@ -117,6 +120,7 @@ export const ansiSemanticColors: SemanticColors = {
|
||||
ui: {
|
||||
comment: ansiTheme.Comment,
|
||||
symbol: ansiTheme.Gray,
|
||||
dark: ansiTheme.DarkGray,
|
||||
gradient: ansiTheme.GradientColors,
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* @author Ahmad Awais <https://twitter.com/mrahmadawais/>
|
||||
*/
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const shadesOfPurpleColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -26,6 +27,7 @@ const shadesOfPurpleColors: ColorsTheme = {
|
||||
DiffRemoved: '#572244',
|
||||
Comment: '#B362FF', // Comment color (same as AccentPurple)
|
||||
Gray: '#726c86', // Gray color
|
||||
DarkGray: interpolateColor('#726c86', '#2d2b57', 0.5),
|
||||
GradientColors: ['#4d21fc', '#847ace', '#ff628c'],
|
||||
};
|
||||
|
||||
|
||||
@@ -8,9 +8,80 @@ import { describe, it, expect } from 'vitest';
|
||||
import * as themeModule from './theme.js';
|
||||
import { themeManager } from './theme-manager.js';
|
||||
|
||||
const { validateCustomTheme } = themeModule;
|
||||
const { validateCustomTheme, createCustomTheme } = themeModule;
|
||||
type CustomTheme = themeModule.CustomTheme;
|
||||
|
||||
describe('createCustomTheme', () => {
|
||||
const baseTheme: CustomTheme = {
|
||||
type: 'custom',
|
||||
name: 'Test Theme',
|
||||
Background: '#000000',
|
||||
Foreground: '#ffffff',
|
||||
LightBlue: '#ADD8E6',
|
||||
AccentBlue: '#0000FF',
|
||||
AccentPurple: '#800080',
|
||||
AccentCyan: '#00FFFF',
|
||||
AccentGreen: '#008000',
|
||||
AccentYellow: '#FFFF00',
|
||||
AccentRed: '#FF0000',
|
||||
DiffAdded: '#00FF00',
|
||||
DiffRemoved: '#FF0000',
|
||||
Comment: '#808080',
|
||||
Gray: '#cccccc',
|
||||
// DarkGray intentionally omitted to test fallback
|
||||
};
|
||||
|
||||
it('should interpolate DarkGray when not provided', () => {
|
||||
const theme = createCustomTheme(baseTheme);
|
||||
// Interpolate between Gray (#cccccc) and Background (#000000) at 0.5
|
||||
// #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');
|
||||
});
|
||||
|
||||
it('should use provided DarkGray', () => {
|
||||
const theme = createCustomTheme({
|
||||
...baseTheme,
|
||||
DarkGray: '#123456',
|
||||
});
|
||||
expect(theme.colors.DarkGray).toBe('#123456');
|
||||
});
|
||||
|
||||
it('should interpolate DarkGray when text.secondary is provided but DarkGray is not', () => {
|
||||
const customTheme: CustomTheme = {
|
||||
type: 'custom',
|
||||
name: 'Test',
|
||||
text: {
|
||||
secondary: '#cccccc', // Gray source
|
||||
},
|
||||
background: {
|
||||
primary: '#000000', // Background source
|
||||
},
|
||||
};
|
||||
const theme = createCustomTheme(customTheme);
|
||||
// Should be interpolated between #cccccc and #000000 at 0.5 -> #666666
|
||||
expect(theme.colors.DarkGray).toBe('#666666');
|
||||
});
|
||||
|
||||
it('should prefer text.secondary over Gray for interpolation', () => {
|
||||
const customTheme: CustomTheme = {
|
||||
type: 'custom',
|
||||
name: 'Test',
|
||||
text: {
|
||||
secondary: '#cccccc', // Should be used
|
||||
},
|
||||
Gray: '#aaaaaa', // Should be ignored
|
||||
background: {
|
||||
primary: '#000000',
|
||||
},
|
||||
};
|
||||
const theme = createCustomTheme(customTheme);
|
||||
// Interpolate between #cccccc and #000000 -> #666666
|
||||
expect(theme.colors.DarkGray).toBe('#666666');
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateCustomTheme', () => {
|
||||
const validTheme: CustomTheme = {
|
||||
type: 'custom',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import type { SemanticColors } from './semantic-tokens.js';
|
||||
import { resolveColor } from './color-utils.js';
|
||||
import { resolveColor, interpolateColor } from './color-utils.js';
|
||||
|
||||
export type ThemeType = 'light' | 'dark' | 'ansi' | 'custom';
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ColorsTheme {
|
||||
DiffRemoved: string;
|
||||
Comment: string;
|
||||
Gray: string;
|
||||
DarkGray: string;
|
||||
GradientColors?: string[];
|
||||
}
|
||||
|
||||
@@ -74,13 +75,14 @@ export interface CustomTheme {
|
||||
DiffRemoved?: string;
|
||||
Comment?: string;
|
||||
Gray?: string;
|
||||
DarkGray?: string;
|
||||
GradientColors?: string[];
|
||||
}
|
||||
|
||||
export const lightTheme: ColorsTheme = {
|
||||
type: 'light',
|
||||
Background: '#FAFAFA',
|
||||
Foreground: '',
|
||||
Foreground: '#383A42',
|
||||
LightBlue: '#89BDCD',
|
||||
AccentBlue: '#3B82F6',
|
||||
AccentPurple: '#8B5CF6',
|
||||
@@ -92,13 +94,14 @@ export const lightTheme: ColorsTheme = {
|
||||
DiffRemoved: '#FFCCCC',
|
||||
Comment: '#008000',
|
||||
Gray: '#97a0b0',
|
||||
DarkGray: interpolateColor('#97a0b0', '#FAFAFA', 0.5),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
|
||||
export const darkTheme: ColorsTheme = {
|
||||
type: 'dark',
|
||||
Background: '#1E1E2E',
|
||||
Foreground: '',
|
||||
Foreground: '#CDD6F4',
|
||||
LightBlue: '#ADD8E6',
|
||||
AccentBlue: '#89B4FA',
|
||||
AccentPurple: '#CBA6F7',
|
||||
@@ -110,6 +113,7 @@ export const darkTheme: ColorsTheme = {
|
||||
DiffRemoved: '#430000',
|
||||
Comment: '#6C7086',
|
||||
Gray: '#6C7086',
|
||||
DarkGray: interpolateColor('#6C7086', '#1E1E2E', 0.5),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
|
||||
@@ -128,6 +132,7 @@ export const ansiTheme: ColorsTheme = {
|
||||
DiffRemoved: 'red',
|
||||
Comment: 'gray',
|
||||
Gray: 'gray',
|
||||
DarkGray: 'gray',
|
||||
};
|
||||
|
||||
export class Theme {
|
||||
@@ -176,6 +181,7 @@ export class Theme {
|
||||
ui: {
|
||||
comment: this.colors.Gray,
|
||||
symbol: this.colors.AccentCyan,
|
||||
dark: this.colors.DarkGray,
|
||||
gradient: this.colors.GradientColors,
|
||||
},
|
||||
status: {
|
||||
@@ -267,6 +273,13 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
customTheme.background?.diff?.removed ?? customTheme.DiffRemoved ?? '',
|
||||
Comment: customTheme.ui?.comment ?? customTheme.Comment ?? '',
|
||||
Gray: customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
DarkGray:
|
||||
customTheme.DarkGray ??
|
||||
interpolateColor(
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
0.5,
|
||||
),
|
||||
GradientColors: customTheme.ui?.gradient ?? customTheme.GradientColors,
|
||||
};
|
||||
|
||||
@@ -429,6 +442,7 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
ui: {
|
||||
comment: customTheme.ui?.comment ?? colors.Comment,
|
||||
symbol: customTheme.ui?.symbol ?? colors.Gray,
|
||||
dark: colors.DarkGray,
|
||||
gradient: customTheme.ui?.gradient ?? colors.GradientColors,
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const xcodeColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
@@ -21,6 +22,7 @@ const xcodeColors: ColorsTheme = {
|
||||
DiffRemoved: '#FEDEDE',
|
||||
Comment: '#007400',
|
||||
Gray: '#c0c0c0',
|
||||
DarkGray: interpolateColor('#c0c0c0', '#fff', 0.5),
|
||||
GradientColors: ['#1c00cf', '#007400'],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user