mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
refactor(ui): implement recursive color flattening and improve contrast in colors visualizer
This commit is contained in:
@@ -36,6 +36,22 @@ interface ColorsDisplayProps {
|
|||||||
activeTheme: Theme;
|
activeTheme: Theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines a contrasting text color (black or white) based on the background color's luminance.
|
||||||
|
*/
|
||||||
|
function getContrastingTextColor(hex: string): string {
|
||||||
|
if (!hex || !hex.startsWith('#') || hex.length < 7) {
|
||||||
|
// Fallback for invalid hex codes or named colors
|
||||||
|
return theme.text.primary;
|
||||||
|
}
|
||||||
|
const r = parseInt(hex.slice(1, 3), 16);
|
||||||
|
const g = parseInt(hex.slice(3, 5), 16);
|
||||||
|
const b = parseInt(hex.slice(5, 7), 16);
|
||||||
|
// Using YIQ formula to determine luminance
|
||||||
|
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
|
return yiq >= 128 ? '#000000' : '#FFFFFF';
|
||||||
|
}
|
||||||
|
|
||||||
export const ColorsDisplay: React.FC<ColorsDisplayProps> = ({
|
export const ColorsDisplay: React.FC<ColorsDisplayProps> = ({
|
||||||
activeTheme,
|
activeTheme,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -53,54 +69,40 @@ export const ColorsDisplay: React.FC<ColorsDisplayProps> = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten and categorize the SemanticColors object
|
/**
|
||||||
for (const [category, subColors] of Object.entries(semanticColors)) {
|
* Recursively flattens the semanticColors object.
|
||||||
if (category === 'ui' && 'gradient' in subColors) {
|
*/
|
||||||
continue;
|
const flattenColors = (obj: object, path: string = '') => {
|
||||||
}
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
if (value === undefined || value === null) continue;
|
||||||
|
const newPath = path ? `${path}.${key}` : key;
|
||||||
|
|
||||||
for (const [name, value] of Object.entries(subColors)) {
|
if (key === 'gradient' && Array.isArray(value)) {
|
||||||
const fullName = `${category}.${name}`;
|
// Gradient handled separately
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||||
for (const [diffName, diffValue] of Object.entries(value)) {
|
flattenColors(value, newPath);
|
||||||
if (typeof diffValue === 'string') {
|
|
||||||
if (category === 'background') {
|
|
||||||
backgroundRows.push({
|
|
||||||
type: 'background',
|
|
||||||
name: `${fullName}.${diffName}`,
|
|
||||||
value: diffValue,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
standardRows.push({
|
|
||||||
type: 'standard',
|
|
||||||
name: `${fullName}.${diffName}`,
|
|
||||||
value: diffValue,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
if (category === 'background') {
|
if (newPath.startsWith('background.')) {
|
||||||
backgroundRows.push({
|
backgroundRows.push({
|
||||||
type: 'background',
|
type: 'background',
|
||||||
name: fullName,
|
name: newPath,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
standardRows.push({
|
standardRows.push({
|
||||||
type: 'standard',
|
type: 'standard',
|
||||||
name: fullName,
|
name: newPath,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
flattenColors(semanticColors);
|
||||||
|
|
||||||
// Final order: Backgrounds first, then Standards, then Gradient
|
// Final order: Backgrounds first, then Standards, then Gradient
|
||||||
const allRows: ColorRow[] = [
|
const allRows: ColorRow[] = [
|
||||||
@@ -218,7 +220,7 @@ function renderBackgroundRow({ name, value }: BackgroundColorRow) {
|
|||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
paddingX={1}
|
paddingX={1}
|
||||||
>
|
>
|
||||||
<Text color={theme.text.primary} bold wrap="truncate">
|
<Text color={getContrastingTextColor(value)} bold wrap="truncate">
|
||||||
{value || 'default'}
|
{value || 'default'}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal
|
|||||||
│ │ (blank) text.response │ │
|
│ │ (blank) text.response │ │
|
||||||
│ │ #3d3f51 border.default │ │
|
│ │ #3d3f51 border.default │ │
|
||||||
│ │ #89B4FA border.focused │ │
|
│ │ #89B4FA border.focused │ │
|
||||||
|
│ │ #6C7086 ui.comment │ │
|
||||||
|
│ │ #89DCEB ui.symbol │ │
|
||||||
|
│ │ #3d3f51 ui.dark │ │
|
||||||
│ │ #F38BA8 status.error │ │
|
│ │ #F38BA8 status.error │ │
|
||||||
│ │ #A6E3A1 status.success │ │
|
│ │ #A6E3A1 status.success │ │
|
||||||
│ │ #F9E2AF status.warning │ │
|
│ │ #F9E2AF status.warning │ │
|
||||||
@@ -102,6 +105,9 @@ exports[`Initial Theme Selection > should default to a light theme when terminal
|
|||||||
│ │ (blank) text.response │ │
|
│ │ (blank) text.response │ │
|
||||||
│ │ #d2d6dc border.default │ │
|
│ │ #d2d6dc border.default │ │
|
||||||
│ │ #3B82F6 border.focused │ │
|
│ │ #3B82F6 border.focused │ │
|
||||||
|
│ │ #97a0b0 ui.comment │ │
|
||||||
|
│ │ #06B6D4 ui.symbol │ │
|
||||||
|
│ │ #d2d6dc ui.dark │ │
|
||||||
│ │ #DD4C4C status.error │ │
|
│ │ #DD4C4C status.error │ │
|
||||||
│ │ #3CA84B status.success │ │
|
│ │ #3CA84B status.success │ │
|
||||||
│ │ #D5A40A status.warning │ │
|
│ │ #D5A40A status.warning │ │
|
||||||
@@ -160,6 +166,9 @@ exports[`Initial Theme Selection > should use the theme from settings even if te
|
|||||||
│ │ (blank) text.response │ │
|
│ │ (blank) text.response │ │
|
||||||
│ │ #3d3f51 border.default │ │
|
│ │ #3d3f51 border.default │ │
|
||||||
│ │ #89B4FA border.focused │ │
|
│ │ #89B4FA border.focused │ │
|
||||||
|
│ │ #6C7086 ui.comment │ │
|
||||||
|
│ │ #89DCEB ui.symbol │ │
|
||||||
|
│ │ #3d3f51 ui.dark │ │
|
||||||
│ │ #F38BA8 status.error │ │
|
│ │ #F38BA8 status.error │ │
|
||||||
│ │ #A6E3A1 status.success │ │
|
│ │ #A6E3A1 status.success │ │
|
||||||
│ │ #F9E2AF status.warning │ │
|
│ │ #F9E2AF status.warning │ │
|
||||||
@@ -232,6 +241,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
|||||||
│ │ (blank) text.response │ │
|
│ │ (blank) text.response │ │
|
||||||
│ │ #3d3f51 border.default │ │
|
│ │ #3d3f51 border.default │ │
|
||||||
│ │ #89B4FA border.focused │ │
|
│ │ #89B4FA border.focused │ │
|
||||||
|
│ │ #6C7086 ui.comment │ │
|
||||||
|
│ │ #6C7086 ui.symbol │ │
|
||||||
|
│ │ #3d3f51 ui.dark │ │
|
||||||
│ │ #F38BA8 status.error │ │
|
│ │ #F38BA8 status.error │ │
|
||||||
│ │ #A6E3A1 status.success │ │
|
│ │ #A6E3A1 status.success │ │
|
||||||
│ │ #F9E2AF status.warning │ │
|
│ │ #F9E2AF status.warning │ │
|
||||||
|
|||||||
Reference in New Issue
Block a user