mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-22 20:14:58 -07:00
ui(polish) blend background color with theme (#18802)
This commit is contained in:
@@ -1549,7 +1549,6 @@ describe('InputPrompt', () => {
|
||||
{ color: 'black', name: 'black' },
|
||||
{ color: '#000000', name: '#000000' },
|
||||
{ color: '#000', name: '#000' },
|
||||
{ color: undefined, name: 'default (black)' },
|
||||
{ color: 'white', name: 'white' },
|
||||
{ color: '#ffffff', name: '#ffffff' },
|
||||
{ color: '#fff', name: '#fff' },
|
||||
@@ -1619,6 +1618,11 @@ describe('InputPrompt', () => {
|
||||
|
||||
const { stdout, unmount } = renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
{
|
||||
uiState: {
|
||||
terminalBackgroundColor: 'black',
|
||||
} as Partial<UIState>,
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -222,7 +222,6 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
terminalWidth,
|
||||
activePtyId,
|
||||
history,
|
||||
terminalBackgroundColor,
|
||||
backgroundShells,
|
||||
backgroundShellHeight,
|
||||
shortcutsHelpVisible,
|
||||
@@ -1352,7 +1351,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
|
||||
const useBackgroundColor = config.getUseBackgroundColor();
|
||||
const isLowColor = isLowColorDepth();
|
||||
const terminalBg = terminalBackgroundColor || 'black';
|
||||
const terminalBg = theme.background.primary || 'black';
|
||||
|
||||
// We should fallback to lines if the background color is disabled OR if it is
|
||||
// enabled but we are in a low color depth terminal where we don't have a safe
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useCallback, useState } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { themeManager, DEFAULT_THEME } from '../themes/theme-manager.js';
|
||||
import { pickDefaultThemeName } from '../themes/theme.js';
|
||||
import { pickDefaultThemeName, type Theme } from '../themes/theme.js';
|
||||
import { RadioButtonSelect } from './shared/RadioButtonSelect.js';
|
||||
import { DiffRenderer } from './messages/DiffRenderer.js';
|
||||
import { colorizeCode } from '../utils/CodeColorizer.js';
|
||||
@@ -27,7 +27,10 @@ import { useUIState } from '../contexts/UIStateContext.js';
|
||||
|
||||
interface ThemeDialogProps {
|
||||
/** Callback function when a theme is selected */
|
||||
onSelect: (themeName: string, scope: LoadableSettingScope) => void;
|
||||
onSelect: (
|
||||
themeName: string,
|
||||
scope: LoadableSettingScope,
|
||||
) => void | Promise<void>;
|
||||
|
||||
/** Callback function when the dialog is cancelled */
|
||||
onCancel: () => void;
|
||||
@@ -40,24 +43,21 @@ interface ThemeDialogProps {
|
||||
terminalWidth: number;
|
||||
}
|
||||
|
||||
import {
|
||||
getThemeTypeFromBackgroundColor,
|
||||
resolveColor,
|
||||
} from '../themes/color-utils.js';
|
||||
import { resolveColor } from '../themes/color-utils.js';
|
||||
|
||||
function generateThemeItem(
|
||||
name: string,
|
||||
typeDisplay: string,
|
||||
themeType: string,
|
||||
themeBackground: string | undefined,
|
||||
fullTheme: Theme | undefined,
|
||||
terminalBackgroundColor: string | undefined,
|
||||
terminalThemeType: 'light' | 'dark' | undefined,
|
||||
) {
|
||||
const isCompatible =
|
||||
themeType === 'custom' ||
|
||||
terminalThemeType === undefined ||
|
||||
themeType === 'ansi' ||
|
||||
themeType === terminalThemeType;
|
||||
const isCompatible = fullTheme
|
||||
? themeManager.isThemeCompatible(fullTheme, terminalBackgroundColor)
|
||||
: true;
|
||||
|
||||
const themeBackground = fullTheme
|
||||
? resolveColor(fullTheme.colors.Background)
|
||||
: undefined;
|
||||
|
||||
const isBackgroundMatch =
|
||||
terminalBackgroundColor &&
|
||||
@@ -111,26 +111,17 @@ export function ThemeDialog({
|
||||
|
||||
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
||||
|
||||
const terminalThemeType = getThemeTypeFromBackgroundColor(
|
||||
terminalBackgroundColor,
|
||||
);
|
||||
|
||||
// Generate theme items
|
||||
const themeItems = themeManager
|
||||
.getAvailableThemes()
|
||||
.map((theme) => {
|
||||
const fullTheme = themeManager.getTheme(theme.name);
|
||||
const themeBackground = fullTheme
|
||||
? resolveColor(fullTheme.colors.Background)
|
||||
: undefined;
|
||||
|
||||
return generateThemeItem(
|
||||
theme.name,
|
||||
capitalize(theme.type),
|
||||
theme.type,
|
||||
themeBackground,
|
||||
fullTheme,
|
||||
terminalBackgroundColor,
|
||||
terminalThemeType,
|
||||
);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
@@ -149,8 +140,8 @@ export function ThemeDialog({
|
||||
const safeInitialThemeIndex = initialThemeIndex >= 0 ? initialThemeIndex : 0;
|
||||
|
||||
const handleThemeSelect = useCallback(
|
||||
(themeName: string) => {
|
||||
onSelect(themeName, selectedScope);
|
||||
async (themeName: string) => {
|
||||
await onSelect(themeName, selectedScope);
|
||||
refreshStatic();
|
||||
},
|
||||
[onSelect, selectedScope, refreshStatic],
|
||||
@@ -166,8 +157,8 @@ export function ThemeDialog({
|
||||
}, []);
|
||||
|
||||
const handleScopeSelect = useCallback(
|
||||
(scope: LoadableSettingScope) => {
|
||||
onSelect(highlightedThemeName, scope);
|
||||
async (scope: LoadableSettingScope) => {
|
||||
await onSelect(highlightedThemeName, scope);
|
||||
refreshStatic();
|
||||
},
|
||||
[onSelect, highlightedThemeName, refreshStatic],
|
||||
|
||||
@@ -90,18 +90,18 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
||||
│ │
|
||||
│ > Select Theme Preview │
|
||||
│ ▲ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ 1. ANSI Dark │ │ │
|
||||
│ 2. ANSI Light Light │ 1 # function │ │
|
||||
│ 3. Atom One Dark │ 2 def fibonacci(n): │ │
|
||||
│ 4. Ayu Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Ayu Light Light │ 4 for _ in range(n): │ │
|
||||
│ ● 6. Default Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Default Light Light │ 6 return a │ │
|
||||
│ 8. Dracula Dark │ │ │
|
||||
│ 9. GitHub Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. GitHub Light Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Google Code Light │ │ │
|
||||
│ 12. Holiday Dark └────────────────────────────────────────────────────────────┘ │
|
||||
│ ● 1. ANSI Dark (Matches terminal) │ │ │
|
||||
│ 2. Atom One Dark │ 1 # function │ │
|
||||
│ 3. Ayu Dark │ 2 def fibonacci(n): │ │
|
||||
│ 4. Default Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. ANSI Light Light (Incompatible) │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Ayu Light Light (Incompatible) │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Default Light Light (Incompatible) │ │ │
|
||||
│ 12. GitHub Light Light (Incompatible) └────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
|
||||
@@ -8,6 +8,7 @@ import type React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Box, Text, useIsScreenReaderEnabled } from 'ink';
|
||||
import { useUIState } from '../../contexts/UIStateContext.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import {
|
||||
interpolateColor,
|
||||
resolveColor,
|
||||
@@ -52,8 +53,8 @@ const HalfLinePaddedBoxInternal: React.FC<HalfLinePaddedBoxProps> = ({
|
||||
backgroundOpacity,
|
||||
children,
|
||||
}) => {
|
||||
const { terminalWidth, terminalBackgroundColor } = useUIState();
|
||||
const terminalBg = terminalBackgroundColor || 'black';
|
||||
const { terminalWidth } = useUIState();
|
||||
const terminalBg = theme.background.primary || 'black';
|
||||
|
||||
const isLowColor = isLowColorDepth();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user