mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-23 19:44:30 -07:00
feat(ui): standardize semantic focus colors and enhance history visibility (#20745)
Co-authored-by: jacob314 <jacob314@gmail.com>
This commit is contained in:
@@ -23,6 +23,7 @@ const ansiColors: ColorsTheme = {
|
||||
Comment: 'gray',
|
||||
Gray: 'gray',
|
||||
DarkGray: 'gray',
|
||||
FocusBackground: 'black',
|
||||
GradientColors: ['cyan', 'green'],
|
||||
};
|
||||
|
||||
|
||||
@@ -4,38 +4,25 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
import tinygradient from 'tinygradient';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import {
|
||||
resolveColor,
|
||||
interpolateColor,
|
||||
getThemeTypeFromBackgroundColor,
|
||||
INK_SUPPORTED_NAMES,
|
||||
INK_NAME_TO_HEX_MAP,
|
||||
getLuminance,
|
||||
CSS_NAME_TO_HEX_MAP,
|
||||
} from './theme.js';
|
||||
|
||||
// Define the set of Ink's named colors for quick lookup
|
||||
export const INK_SUPPORTED_NAMES = new Set([
|
||||
'black',
|
||||
'red',
|
||||
'green',
|
||||
'yellow',
|
||||
'blue',
|
||||
'cyan',
|
||||
'magenta',
|
||||
'white',
|
||||
'gray',
|
||||
'grey',
|
||||
'blackbright',
|
||||
'redbright',
|
||||
'greenbright',
|
||||
'yellowbright',
|
||||
'bluebright',
|
||||
'cyanbright',
|
||||
'magentabright',
|
||||
'whitebright',
|
||||
]);
|
||||
|
||||
// Use tinycolor's built-in names map for CSS colors, excluding ones Ink supports
|
||||
export const CSS_NAME_TO_HEX_MAP = Object.fromEntries(
|
||||
Object.entries(tinycolor.names)
|
||||
.filter(([name]) => !INK_SUPPORTED_NAMES.has(name))
|
||||
.map(([name, hex]) => [name, `#${hex}`]),
|
||||
);
|
||||
export {
|
||||
resolveColor,
|
||||
interpolateColor,
|
||||
getThemeTypeFromBackgroundColor,
|
||||
INK_SUPPORTED_NAMES,
|
||||
INK_NAME_TO_HEX_MAP,
|
||||
getLuminance,
|
||||
CSS_NAME_TO_HEX_MAP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a color string is valid (hex, Ink-supported color name, or CSS color name).
|
||||
@@ -66,45 +53,6 @@ export function isValidColor(color: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a CSS color value (name or hex) into an Ink-compatible color string.
|
||||
* @param colorValue The raw color string (e.g., 'blue', '#ff0000', 'darkkhaki').
|
||||
* @returns An Ink-compatible color string (hex or name), or undefined if not resolvable.
|
||||
*/
|
||||
export function resolveColor(colorValue: string): string | undefined {
|
||||
const lowerColor = colorValue.toLowerCase();
|
||||
|
||||
// 1. Check if it's already a hex code and valid
|
||||
if (lowerColor.startsWith('#')) {
|
||||
if (/^#[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$/.test(colorValue)) {
|
||||
return lowerColor;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle hex codes without #
|
||||
if (/^[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$/.test(colorValue)) {
|
||||
return `#${lowerColor}`;
|
||||
}
|
||||
|
||||
// 2. Check if it's an Ink supported name (lowercase)
|
||||
if (INK_SUPPORTED_NAMES.has(lowerColor)) {
|
||||
return lowerColor; // Use Ink name directly
|
||||
}
|
||||
|
||||
// 3. Check if it's a known CSS name we can map to hex
|
||||
if (CSS_NAME_TO_HEX_MAP[lowerColor]) {
|
||||
return CSS_NAME_TO_HEX_MAP[lowerColor]; // Use mapped hex
|
||||
}
|
||||
|
||||
// 4. Could not resolve
|
||||
debugLogger.warn(
|
||||
`[ColorUtils] Could not resolve color "${colorValue}" to an Ink-compatible format.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "safe" background color to use in low-color terminals if the
|
||||
* terminal background is a standard black or white.
|
||||
@@ -132,73 +80,6 @@ export function getSafeLowColorBackground(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function interpolateColor(
|
||||
color1: string,
|
||||
color2: string,
|
||||
factor: number,
|
||||
) {
|
||||
if (factor <= 0 && color1) {
|
||||
return color1;
|
||||
}
|
||||
if (factor >= 1 && color2) {
|
||||
return color2;
|
||||
}
|
||||
if (!color1 || !color2) {
|
||||
return '';
|
||||
}
|
||||
const gradient = tinygradient(color1, color2);
|
||||
const color = gradient.rgbAt(factor);
|
||||
return color.toHexString();
|
||||
}
|
||||
|
||||
export function getThemeTypeFromBackgroundColor(
|
||||
backgroundColor: string | undefined,
|
||||
): 'light' | 'dark' | undefined {
|
||||
if (!backgroundColor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resolvedColor = resolveColor(backgroundColor);
|
||||
if (!resolvedColor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const luminance = getLuminance(resolvedColor);
|
||||
return luminance > 128 ? 'light' : 'dark';
|
||||
}
|
||||
|
||||
// Mapping for ANSI bright colors that are not in tinycolor's standard CSS names
|
||||
export const INK_NAME_TO_HEX_MAP: Readonly<Record<string, string>> = {
|
||||
blackbright: '#555555',
|
||||
redbright: '#ff5555',
|
||||
greenbright: '#55ff55',
|
||||
yellowbright: '#ffff55',
|
||||
bluebright: '#5555ff',
|
||||
magentabright: '#ff55ff',
|
||||
cyanbright: '#55ffff',
|
||||
whitebright: '#ffffff',
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the relative luminance of a color.
|
||||
* See https://www.w3.org/TR/WCAG20/#relativeluminancedef
|
||||
*
|
||||
* @param color Color string (hex or Ink-supported name)
|
||||
* @returns Luminance value (0-255)
|
||||
*/
|
||||
export function getLuminance(color: string): number {
|
||||
const resolved = color.toLowerCase();
|
||||
const hex = INK_NAME_TO_HEX_MAP[resolved] || resolved;
|
||||
|
||||
const colorObj = tinycolor(hex);
|
||||
if (!colorObj.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// tinycolor returns 0-1, we need 0-255
|
||||
return colorObj.getLuminance() * 255;
|
||||
}
|
||||
|
||||
// Hysteresis thresholds to prevent flickering when the background color
|
||||
// is ambiguous (near the midpoint).
|
||||
export const LIGHT_THEME_LUMINANCE_THRESHOLD = 140;
|
||||
|
||||
@@ -23,6 +23,7 @@ const githubLightColors: ColorsTheme = {
|
||||
Comment: '#998',
|
||||
Gray: '#999',
|
||||
DarkGray: interpolateColor('#999', '#f8f8f8', 0.5),
|
||||
FocusColor: '#458', // AccentBlue for GitHub branding
|
||||
GradientColors: ['#458', '#008080'],
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ const holidayColors: ColorsTheme = {
|
||||
Comment: '#8FBC8F',
|
||||
Gray: '#D7F5D3',
|
||||
DarkGray: interpolateColor('#D7F5D3', '#151B18', 0.5),
|
||||
FocusColor: '#33F9FF', // AccentCyan for neon pop
|
||||
GradientColors: ['#FF0000', '#FFFFFF', '#008000'],
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ const noColorColorsTheme: ColorsTheme = {
|
||||
DarkGray: '',
|
||||
InputBackground: '',
|
||||
MessageBackground: '',
|
||||
FocusBackground: '',
|
||||
};
|
||||
|
||||
const noColorSemanticColors: SemanticColors = {
|
||||
@@ -40,6 +41,7 @@ const noColorSemanticColors: SemanticColors = {
|
||||
primary: '',
|
||||
message: '',
|
||||
input: '',
|
||||
focus: '',
|
||||
diff: {
|
||||
added: '',
|
||||
removed: '',
|
||||
@@ -47,12 +49,13 @@ const noColorSemanticColors: SemanticColors = {
|
||||
},
|
||||
border: {
|
||||
default: '',
|
||||
focused: '',
|
||||
},
|
||||
ui: {
|
||||
comment: '',
|
||||
symbol: '',
|
||||
active: '',
|
||||
dark: '',
|
||||
focus: '',
|
||||
gradient: [],
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface SemanticColors {
|
||||
primary: string;
|
||||
message: string;
|
||||
input: string;
|
||||
focus: string;
|
||||
diff: {
|
||||
added: string;
|
||||
removed: string;
|
||||
@@ -25,12 +26,13 @@ export interface SemanticColors {
|
||||
};
|
||||
border: {
|
||||
default: string;
|
||||
focused: string;
|
||||
};
|
||||
ui: {
|
||||
comment: string;
|
||||
symbol: string;
|
||||
active: string;
|
||||
dark: string;
|
||||
focus: string;
|
||||
gradient: string[] | undefined;
|
||||
};
|
||||
status: {
|
||||
@@ -52,6 +54,7 @@ export const lightSemanticColors: SemanticColors = {
|
||||
primary: lightTheme.Background,
|
||||
message: lightTheme.MessageBackground!,
|
||||
input: lightTheme.InputBackground!,
|
||||
focus: lightTheme.FocusBackground!,
|
||||
diff: {
|
||||
added: lightTheme.DiffAdded,
|
||||
removed: lightTheme.DiffRemoved,
|
||||
@@ -59,12 +62,13 @@ export const lightSemanticColors: SemanticColors = {
|
||||
},
|
||||
border: {
|
||||
default: lightTheme.DarkGray,
|
||||
focused: lightTheme.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
comment: lightTheme.Comment,
|
||||
symbol: lightTheme.Gray,
|
||||
active: lightTheme.AccentBlue,
|
||||
dark: lightTheme.DarkGray,
|
||||
focus: lightTheme.AccentGreen,
|
||||
gradient: lightTheme.GradientColors,
|
||||
},
|
||||
status: {
|
||||
@@ -86,6 +90,7 @@ export const darkSemanticColors: SemanticColors = {
|
||||
primary: darkTheme.Background,
|
||||
message: darkTheme.MessageBackground!,
|
||||
input: darkTheme.InputBackground!,
|
||||
focus: darkTheme.FocusBackground!,
|
||||
diff: {
|
||||
added: darkTheme.DiffAdded,
|
||||
removed: darkTheme.DiffRemoved,
|
||||
@@ -93,12 +98,13 @@ export const darkSemanticColors: SemanticColors = {
|
||||
},
|
||||
border: {
|
||||
default: darkTheme.DarkGray,
|
||||
focused: darkTheme.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
comment: darkTheme.Comment,
|
||||
symbol: darkTheme.Gray,
|
||||
active: darkTheme.AccentBlue,
|
||||
dark: darkTheme.DarkGray,
|
||||
focus: darkTheme.AccentGreen,
|
||||
gradient: darkTheme.GradientColors,
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { type ColorsTheme, Theme, interpolateColor } from './theme.js';
|
||||
import { type SemanticColors } from './semantic-tokens.js';
|
||||
import { DEFAULT_SELECTION_OPACITY } from '../constants.js';
|
||||
|
||||
const solarizedDarkColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
@@ -38,6 +39,7 @@ const semanticColors: SemanticColors = {
|
||||
primary: '#002b36',
|
||||
message: '#073642',
|
||||
input: '#073642',
|
||||
focus: interpolateColor('#002b36', '#859900', DEFAULT_SELECTION_OPACITY),
|
||||
diff: {
|
||||
added: '#00382f',
|
||||
removed: '#3d0115',
|
||||
@@ -45,13 +47,14 @@ const semanticColors: SemanticColors = {
|
||||
},
|
||||
border: {
|
||||
default: '#073642',
|
||||
focused: '#586e75',
|
||||
},
|
||||
ui: {
|
||||
comment: '#586e75',
|
||||
symbol: '#93a1a1',
|
||||
active: '#268bd2',
|
||||
dark: '#073642',
|
||||
gradient: ['#268bd2', '#2aa198'],
|
||||
focus: '#859900',
|
||||
gradient: ['#268bd2', '#2aa198', '#859900'],
|
||||
},
|
||||
status: {
|
||||
success: '#859900',
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { type ColorsTheme, Theme, interpolateColor } from './theme.js';
|
||||
import { type SemanticColors } from './semantic-tokens.js';
|
||||
import { DEFAULT_SELECTION_OPACITY } from '../constants.js';
|
||||
|
||||
const solarizedLightColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
@@ -38,6 +39,7 @@ const semanticColors: SemanticColors = {
|
||||
primary: '#fdf6e3',
|
||||
message: '#eee8d5',
|
||||
input: '#eee8d5',
|
||||
focus: interpolateColor('#fdf6e3', '#859900', DEFAULT_SELECTION_OPACITY),
|
||||
diff: {
|
||||
added: '#d7f2d7',
|
||||
removed: '#f2d7d7',
|
||||
@@ -45,13 +47,14 @@ const semanticColors: SemanticColors = {
|
||||
},
|
||||
border: {
|
||||
default: '#eee8d5',
|
||||
focused: '#93a1a1',
|
||||
},
|
||||
ui: {
|
||||
comment: '#93a1a1',
|
||||
symbol: '#586e75',
|
||||
active: '#268bd2',
|
||||
dark: '#eee8d5',
|
||||
gradient: ['#268bd2', '#2aa198'],
|
||||
focus: '#859900',
|
||||
gradient: ['#268bd2', '#2aa198', '#859900'],
|
||||
},
|
||||
status: {
|
||||
success: '#859900',
|
||||
|
||||
@@ -22,16 +22,18 @@ import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { Theme, ThemeType, ColorsTheme } from './theme.js';
|
||||
import type { CustomTheme } from '@google/gemini-cli-core';
|
||||
import { createCustomTheme, validateCustomTheme } from './theme.js';
|
||||
import type { SemanticColors } from './semantic-tokens.js';
|
||||
import {
|
||||
createCustomTheme,
|
||||
validateCustomTheme,
|
||||
interpolateColor,
|
||||
getThemeTypeFromBackgroundColor,
|
||||
resolveColor,
|
||||
} from './color-utils.js';
|
||||
} from './theme.js';
|
||||
import type { SemanticColors } from './semantic-tokens.js';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
} from '../constants.js';
|
||||
import { ANSI } from './ansi.js';
|
||||
@@ -369,6 +371,11 @@ class ThemeManager {
|
||||
colors.Gray,
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
),
|
||||
FocusBackground: interpolateColor(
|
||||
this.terminalBackground,
|
||||
activeTheme.colors.FocusColor ?? activeTheme.colors.AccentGreen,
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
),
|
||||
};
|
||||
} else {
|
||||
this.cachedColors = colors;
|
||||
@@ -402,6 +409,7 @@ class ThemeManager {
|
||||
primary: this.terminalBackground,
|
||||
message: colors.MessageBackground!,
|
||||
input: colors.InputBackground!,
|
||||
focus: colors.FocusBackground!,
|
||||
},
|
||||
border: {
|
||||
...semanticColors.border,
|
||||
@@ -410,6 +418,7 @@ class ThemeManager {
|
||||
ui: {
|
||||
...semanticColors.ui,
|
||||
dark: colors.DarkGray,
|
||||
focus: colors.FocusColor ?? colors.AccentGreen,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -8,18 +8,153 @@ import type { CSSProperties } from 'react';
|
||||
|
||||
import type { SemanticColors } from './semantic-tokens.js';
|
||||
|
||||
import {
|
||||
resolveColor,
|
||||
interpolateColor,
|
||||
getThemeTypeFromBackgroundColor,
|
||||
} from './color-utils.js';
|
||||
|
||||
import type { CustomTheme } from '@google/gemini-cli-core';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
DEFAULT_BORDER_OPACITY,
|
||||
} from '../constants.js';
|
||||
import tinygradient from 'tinygradient';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
// Define the set of Ink's named colors for quick lookup
|
||||
export const INK_SUPPORTED_NAMES = new Set([
|
||||
'black',
|
||||
'red',
|
||||
'green',
|
||||
'yellow',
|
||||
'blue',
|
||||
'cyan',
|
||||
'magenta',
|
||||
'white',
|
||||
'gray',
|
||||
'grey',
|
||||
'blackbright',
|
||||
'redbright',
|
||||
'greenbright',
|
||||
'yellowbright',
|
||||
'bluebright',
|
||||
'cyanbright',
|
||||
'magentabright',
|
||||
'whitebright',
|
||||
]);
|
||||
|
||||
// Use tinycolor's built-in names map for CSS colors, excluding ones Ink supports
|
||||
export const CSS_NAME_TO_HEX_MAP = Object.fromEntries(
|
||||
Object.entries(tinycolor.names)
|
||||
.filter(([name]) => !INK_SUPPORTED_NAMES.has(name))
|
||||
.map(([name, hex]) => [name, `#${hex}`]),
|
||||
);
|
||||
|
||||
// Mapping for ANSI bright colors that are not in tinycolor's standard CSS names
|
||||
export const INK_NAME_TO_HEX_MAP: Readonly<Record<string, string>> = {
|
||||
blackbright: '#555555',
|
||||
redbright: '#ff5555',
|
||||
greenbright: '#55ff55',
|
||||
yellowbright: '#ffff55',
|
||||
bluebright: '#5555ff',
|
||||
magentabright: '#ff55ff',
|
||||
cyanbright: '#55ffff',
|
||||
whitebright: '#ffffff',
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the relative luminance of a color.
|
||||
* See https://www.w3.org/TR/WCAG20/#relativeluminancedef
|
||||
*
|
||||
* @param color Color string (hex or Ink-supported name)
|
||||
* @returns Luminance value (0-255)
|
||||
*/
|
||||
export function getLuminance(color: string): number {
|
||||
const resolved = color.toLowerCase();
|
||||
const hex = INK_NAME_TO_HEX_MAP[resolved] || resolved;
|
||||
|
||||
const colorObj = tinycolor(hex);
|
||||
if (!colorObj.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// tinycolor returns 0-1, we need 0-255
|
||||
return colorObj.getLuminance() * 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a CSS color value (name or hex) into an Ink-compatible color string.
|
||||
* @param colorValue The raw color string (e.g., 'blue', '#ff0000', 'darkkhaki').
|
||||
* @returns An Ink-compatible color string (hex or name), or undefined if not resolvable.
|
||||
*/
|
||||
export function resolveColor(colorValue: string): string | undefined {
|
||||
const lowerColor = colorValue.toLowerCase();
|
||||
|
||||
// 1. Check if it's already a hex code and valid
|
||||
if (lowerColor.startsWith('#')) {
|
||||
if (/^#[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$/.test(colorValue)) {
|
||||
return lowerColor;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle hex codes without #
|
||||
if (/^[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$/.test(colorValue)) {
|
||||
return `#${lowerColor}`;
|
||||
}
|
||||
|
||||
// 2. Check if it's an Ink supported name (lowercase)
|
||||
if (INK_SUPPORTED_NAMES.has(lowerColor)) {
|
||||
return lowerColor; // Use Ink name directly
|
||||
}
|
||||
|
||||
// 3. Check if it's a known CSS name we can map to hex
|
||||
// We can't import CSS_NAME_TO_HEX_MAP here due to circular deps,
|
||||
// but we can use tinycolor directly for named colors.
|
||||
const colorObj = tinycolor(lowerColor);
|
||||
if (colorObj.isValid()) {
|
||||
return colorObj.toHexString();
|
||||
}
|
||||
|
||||
// 4. Could not resolve
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function interpolateColor(
|
||||
color1: string,
|
||||
color2: string,
|
||||
factor: number,
|
||||
) {
|
||||
if (factor <= 0 && color1) {
|
||||
return color1;
|
||||
}
|
||||
if (factor >= 1 && color2) {
|
||||
return color2;
|
||||
}
|
||||
if (!color1 || !color2) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
const gradient = tinygradient(color1, color2);
|
||||
const color = gradient.rgbAt(factor);
|
||||
return color.toHexString();
|
||||
} catch (_e) {
|
||||
return color1;
|
||||
}
|
||||
}
|
||||
|
||||
export function getThemeTypeFromBackgroundColor(
|
||||
backgroundColor: string | undefined,
|
||||
): 'light' | 'dark' | undefined {
|
||||
if (!backgroundColor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resolvedColor = resolveColor(backgroundColor);
|
||||
if (!resolvedColor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const luminance = getLuminance(resolvedColor);
|
||||
return luminance > 128 ? 'light' : 'dark';
|
||||
}
|
||||
|
||||
export type { CustomTheme };
|
||||
|
||||
@@ -43,6 +178,8 @@ export interface ColorsTheme {
|
||||
DarkGray: string;
|
||||
InputBackground?: string;
|
||||
MessageBackground?: string;
|
||||
FocusBackground?: string;
|
||||
FocusColor?: string;
|
||||
GradientColors?: string[];
|
||||
}
|
||||
|
||||
@@ -70,7 +207,12 @@ export const lightTheme: ColorsTheme = {
|
||||
MessageBackground: interpolateColor(
|
||||
'#FAFAFA',
|
||||
'#97a0b0',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
FocusBackground: interpolateColor(
|
||||
'#FAFAFA',
|
||||
'#3CA84B',
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
@@ -99,7 +241,12 @@ export const darkTheme: ColorsTheme = {
|
||||
MessageBackground: interpolateColor(
|
||||
'#1E1E2E',
|
||||
'#6C7086',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
FocusBackground: interpolateColor(
|
||||
'#1E1E2E',
|
||||
'#A6E3A1',
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
),
|
||||
GradientColors: ['#4796E4', '#847ACE', '#C3677F'],
|
||||
};
|
||||
@@ -122,6 +269,7 @@ export const ansiTheme: ColorsTheme = {
|
||||
DarkGray: 'gray',
|
||||
InputBackground: 'black',
|
||||
MessageBackground: 'black',
|
||||
FocusBackground: 'black',
|
||||
};
|
||||
|
||||
export class Theme {
|
||||
@@ -164,7 +312,7 @@ export class Theme {
|
||||
interpolateColor(
|
||||
this.colors.Background,
|
||||
this.colors.Gray,
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
input:
|
||||
this.colors.InputBackground ??
|
||||
@@ -173,6 +321,13 @@ export class Theme {
|
||||
this.colors.Gray,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
focus:
|
||||
this.colors.FocusBackground ??
|
||||
interpolateColor(
|
||||
this.colors.Background,
|
||||
this.colors.FocusColor ?? this.colors.AccentGreen,
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
),
|
||||
diff: {
|
||||
added: this.colors.DiffAdded,
|
||||
removed: this.colors.DiffRemoved,
|
||||
@@ -180,12 +335,13 @@ export class Theme {
|
||||
},
|
||||
border: {
|
||||
default: this.colors.DarkGray,
|
||||
focused: this.colors.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
comment: this.colors.Gray,
|
||||
symbol: this.colors.AccentCyan,
|
||||
active: this.colors.AccentBlue,
|
||||
dark: this.colors.DarkGray,
|
||||
focus: this.colors.FocusColor ?? this.colors.AccentGreen,
|
||||
gradient: this.colors.GradientColors,
|
||||
},
|
||||
status: {
|
||||
@@ -292,8 +448,14 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
MessageBackground: interpolateColor(
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
customTheme.text?.secondary ?? customTheme.Gray ?? '',
|
||||
DEFAULT_BACKGROUND_OPACITY,
|
||||
DEFAULT_INPUT_BACKGROUND_OPACITY,
|
||||
),
|
||||
FocusBackground: interpolateColor(
|
||||
customTheme.background?.primary ?? customTheme.Background ?? '',
|
||||
customTheme.status?.success ?? customTheme.AccentGreen ?? '#3CA84B', // Fallback to a default green if not found
|
||||
DEFAULT_SELECTION_OPACITY,
|
||||
),
|
||||
FocusColor: customTheme.ui?.focus ?? customTheme.AccentGreen,
|
||||
GradientColors: customTheme.ui?.gradient ?? customTheme.GradientColors,
|
||||
};
|
||||
|
||||
@@ -450,6 +612,7 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
primary: customTheme.background?.primary ?? colors.Background,
|
||||
message: colors.MessageBackground!,
|
||||
input: colors.InputBackground!,
|
||||
focus: colors.FocusBackground!,
|
||||
diff: {
|
||||
added: customTheme.background?.diff?.added ?? colors.DiffAdded,
|
||||
removed: customTheme.background?.diff?.removed ?? colors.DiffRemoved,
|
||||
@@ -457,12 +620,13 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
|
||||
},
|
||||
border: {
|
||||
default: colors.DarkGray,
|
||||
focused: customTheme.border?.focused ?? colors.AccentBlue,
|
||||
},
|
||||
ui: {
|
||||
comment: customTheme.ui?.comment ?? colors.Comment,
|
||||
symbol: customTheme.ui?.symbol ?? colors.Gray,
|
||||
active: customTheme.ui?.active ?? colors.AccentBlue,
|
||||
dark: colors.DarkGray,
|
||||
focus: colors.FocusColor ?? colors.AccentGreen,
|
||||
gradient: customTheme.ui?.gradient ?? colors.GradientColors,
|
||||
},
|
||||
status: {
|
||||
|
||||
@@ -23,6 +23,7 @@ const xcodeColors: ColorsTheme = {
|
||||
Comment: '#007400',
|
||||
Gray: '#c0c0c0',
|
||||
DarkGray: interpolateColor('#c0c0c0', '#fff', 0.5),
|
||||
FocusColor: '#1c00cf', // AccentBlue for more vibrance
|
||||
GradientColors: ['#1c00cf', '#007400'],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user