diff --git a/packages/cli/src/ui/components/ColorsDisplay.tsx b/packages/cli/src/ui/components/ColorsDisplay.tsx index 598915ec81..ecc60cdd30 100644 --- a/packages/cli/src/ui/components/ColorsDisplay.tsx +++ b/packages/cli/src/ui/components/ColorsDisplay.tsx @@ -36,6 +36,22 @@ interface ColorsDisplayProps { 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 = ({ activeTheme, }) => { @@ -53,54 +69,40 @@ export const ColorsDisplay: React.FC = ({ }; } - // Flatten and categorize the SemanticColors object - for (const [category, subColors] of Object.entries(semanticColors)) { - if (category === 'ui' && 'gradient' in subColors) { - continue; - } + /** + * Recursively flattens the semanticColors object. + */ + 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)) { - const fullName = `${category}.${name}`; - - if (value === undefined || value === null) { + if (key === 'gradient' && Array.isArray(value)) { + // Gradient handled separately continue; } if (typeof value === 'object' && !Array.isArray(value)) { - for (const [diffName, diffValue] of Object.entries(value)) { - 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, - }); - } - } - } + flattenColors(value, newPath); } else if (typeof value === 'string') { - if (category === 'background') { + if (newPath.startsWith('background.')) { backgroundRows.push({ type: 'background', - name: fullName, + name: newPath, value, }); } else { standardRows.push({ type: 'standard', - name: fullName, + name: newPath, value, }); } } } - } + }; + + flattenColors(semanticColors); // Final order: Backgrounds first, then Standards, then Gradient const allRows: ColorRow[] = [ @@ -218,7 +220,7 @@ function renderBackgroundRow({ name, value }: BackgroundColorRow) { justifyContent="center" paddingX={1} > - + {value || 'default'} diff --git a/packages/cli/src/ui/components/__snapshots__/ThemeDialog.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/ThemeDialog.test.tsx.snap index 80a169ef04..232c5099b2 100644 --- a/packages/cli/src/ui/components/__snapshots__/ThemeDialog.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/ThemeDialog.test.tsx.snap @@ -44,6 +44,9 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal │ │ (blank) text.response │ │ │ │ #3d3f51 border.default │ │ │ │ #89B4FA border.focused │ │ +│ │ #6C7086 ui.comment │ │ +│ │ #89DCEB ui.symbol │ │ +│ │ #3d3f51 ui.dark │ │ │ │ #F38BA8 status.error │ │ │ │ #A6E3A1 status.success │ │ │ │ #F9E2AF status.warning │ │ @@ -102,6 +105,9 @@ exports[`Initial Theme Selection > should default to a light theme when terminal │ │ (blank) text.response │ │ │ │ #d2d6dc border.default │ │ │ │ #3B82F6 border.focused │ │ +│ │ #97a0b0 ui.comment │ │ +│ │ #06B6D4 ui.symbol │ │ +│ │ #d2d6dc ui.dark │ │ │ │ #DD4C4C status.error │ │ │ │ #3CA84B status.success │ │ │ │ #D5A40A status.warning │ │ @@ -160,6 +166,9 @@ exports[`Initial Theme Selection > should use the theme from settings even if te │ │ (blank) text.response │ │ │ │ #3d3f51 border.default │ │ │ │ #89B4FA border.focused │ │ +│ │ #6C7086 ui.comment │ │ +│ │ #89DCEB ui.symbol │ │ +│ │ #3d3f51 ui.dark │ │ │ │ #F38BA8 status.error │ │ │ │ #A6E3A1 status.success │ │ │ │ #F9E2AF status.warning │ │ @@ -232,6 +241,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode │ │ (blank) text.response │ │ │ │ #3d3f51 border.default │ │ │ │ #89B4FA border.focused │ │ +│ │ #6C7086 ui.comment │ │ +│ │ #6C7086 ui.symbol │ │ +│ │ #3d3f51 ui.dark │ │ │ │ #F38BA8 status.error │ │ │ │ #A6E3A1 status.success │ │ │ │ #F9E2AF status.warning │ │