Skip to content

Commit d1241b0

Browse files
committed
Small improvements to native terminal colors
1 parent b33f19e commit d1241b0

File tree

6 files changed

+108
-6
lines changed

6 files changed

+108
-6
lines changed

cli/src/app.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { useTerminalDimensions } from './hooks/use-terminal-dimensions'
1616
import { useTerminalFocus } from './hooks/use-terminal-focus'
1717
import { useTheme } from './hooks/use-theme'
1818
import { getProjectRoot } from './project-files'
19+
import { getLogoBlockColor, getLogoAccentColor } from './utils/theme-system'
1920
import { useChatStore } from './state/chat-store'
2021
import { openFileAtPath } from './utils/open-file'
2122

@@ -50,10 +51,11 @@ export const App = ({
5051

5152
// Sheen animation state for the logo
5253
const [sheenPosition, setSheenPosition] = useState(0)
53-
const blockColor = theme.name === 'dark' ? '#ffffff' : '#000000'
54+
const blockColor = getLogoBlockColor(theme.name)
55+
const accentColor = getLogoAccentColor(theme.name)
5456
const { applySheenToChar } = useSheenAnimation({
5557
logoColor: theme.foreground,
56-
accentColor: theme.primary,
58+
accentColor,
5759
blockColor,
5860
terminalWidth,
5961
sheenPosition,
@@ -62,7 +64,7 @@ export const App = ({
6264

6365
const { component: logoComponent } = useLogo({
6466
availableWidth: contentMaxWidth,
65-
accentColor: theme.primary,
67+
accentColor,
6668
blockColor,
6769
applySheenToChar,
6870
})

cli/src/components/login-modal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useLoginPolling } from '../hooks/use-login-polling'
1010
import { useLogo } from '../hooks/use-logo'
1111
import { useSheenAnimation } from '../hooks/use-sheen-animation'
1212
import { useTheme } from '../hooks/use-theme'
13+
import { getLogoBlockColor, getLogoAccentColor } from '../utils/theme-system'
1314
import {
1415
formatUrl,
1516
generateFingerprintId,
@@ -234,10 +235,11 @@ export const LoginModal = ({
234235
}, [loginUrl, copyToClipboard])
235236

236237
// Use custom hook for sheen animation
237-
const blockColor = theme.name === 'dark' ? '#ffffff' : '#000000'
238+
const blockColor = getLogoBlockColor(theme.name)
239+
const accentColor = getLogoAccentColor(theme.name)
238240
const { applySheenToChar } = useSheenAnimation({
239241
logoColor: theme.foreground,
240-
accentColor: theme.primary,
242+
accentColor,
241243
blockColor,
242244
terminalWidth: renderer?.width,
243245
sheenPosition,

cli/src/components/multiline-input.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111

1212
import { InputCursor } from './input-cursor'
1313
import { useTheme } from '../hooks/use-theme'
14+
import { supportsTruecolor } from '../utils/theme-system'
1415
import { useChatStore } from '../state/chat-store'
1516
import { logger } from '../utils/logger'
1617
import { clamp } from '../utils/math'
@@ -1048,7 +1049,7 @@ export const MultilineInput = forwardRef<
10481049
visible={true}
10491050
focused={focused}
10501051
shouldBlink={effectiveShouldBlinkCursor}
1051-
color={theme.info}
1052+
color={supportsTruecolor() ? theme.info : 'lime'}
10521053
key={lastActivity}
10531054
/>
10541055
)}

cli/src/types/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type CliEnv = BaseEnv & {
2222
ZED_NODE_ENV?: string
2323
ZED_TERM?: string
2424
ZED_SHELL?: string
25+
COLORTERM?: string
2526

2627
// VS Code family detection
2728
VSCODE_THEME_KIND?: string

cli/src/utils/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const getCliEnv = (): CliEnv => ({
2222
ZED_NODE_ENV: process.env.ZED_NODE_ENV,
2323
ZED_TERM: process.env.ZED_TERM,
2424
ZED_SHELL: process.env.ZED_SHELL,
25+
COLORTERM: process.env.COLORTERM,
2526

2627
// VS Code family detection
2728
VSCODE_THEME_KIND: process.env.VSCODE_THEME_KIND,
@@ -79,6 +80,7 @@ export const createTestCliEnv = (overrides: Partial<CliEnv> = {}): CliEnv => ({
7980
ZED_NODE_ENV: undefined,
8081
ZED_TERM: undefined,
8182
ZED_SHELL: undefined,
83+
COLORTERM: undefined,
8284
VSCODE_THEME_KIND: undefined,
8385
VSCODE_COLOR_THEME_KIND: undefined,
8486
VSCODE_GIT_IPC_HANDLE: undefined,

cli/src/utils/theme-system.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,100 @@ import type {
1212
ThemeName,
1313
} from '../types/theme-system'
1414

15+
/**
16+
* Check if the terminal supports truecolor (24-bit color).
17+
* Terminals like macOS Terminal.app only support 256 colors and cannot
18+
* render hex colors properly - they need ANSI color name fallbacks.
19+
*/
20+
// Cache the truecolor support result since it won't change during runtime
21+
let _truecolorSupport: boolean | null = null
22+
23+
export function supportsTruecolor(env: CliEnv = getCliEnv()): boolean {
24+
if (_truecolorSupport !== null) {
25+
return _truecolorSupport
26+
}
27+
28+
const termProgram = env.TERM_PROGRAM?.toLowerCase() ?? ''
29+
30+
// Terminal.app (Apple_Terminal) does NOT support truecolor - only 256 colors
31+
if (termProgram === 'apple_terminal') {
32+
_truecolorSupport = false
33+
return false
34+
}
35+
36+
const colorterm = env.COLORTERM?.toLowerCase()
37+
if (colorterm === 'truecolor' || colorterm === '24bit') {
38+
_truecolorSupport = true
39+
return true
40+
}
41+
42+
// Some terminals that are known to support truecolor
43+
const truecolorTerminals = [
44+
'iterm.app',
45+
'hyper',
46+
'wezterm',
47+
'alacritty',
48+
'kitty',
49+
'ghostty',
50+
'vscode',
51+
]
52+
53+
if (truecolorTerminals.some(t => termProgram.includes(t))) {
54+
_truecolorSupport = true
55+
return true
56+
}
57+
58+
// Check TERM for known truecolor-capable values
59+
const term = env.TERM?.toLowerCase() ?? ''
60+
if (term.includes('truecolor') || term.includes('24bit')) {
61+
_truecolorSupport = true
62+
return true
63+
}
64+
65+
// xterm-kitty, alacritty, etc.
66+
if (term === 'xterm-kitty' || term === 'alacritty' || term.includes('ghostty')) {
67+
_truecolorSupport = true
68+
return true
69+
}
70+
71+
_truecolorSupport = false
72+
return false
73+
}
74+
75+
76+
77+
/**
78+
* Get the block color for the logo based on theme and terminal capabilities.
79+
* In dark mode: white (#ffffff or 'white')
80+
* In light mode: black (#000000 or 'black')
81+
*/
82+
export function getLogoBlockColor(
83+
themeName: ThemeName,
84+
env: CliEnv = getCliEnv(),
85+
): string {
86+
const isTruecolor = supportsTruecolor(env)
87+
if (themeName === 'dark') {
88+
return isTruecolor ? '#ffffff' : 'white'
89+
}
90+
return isTruecolor ? '#000000' : 'black'
91+
}
92+
93+
/**
94+
* Get the accent color for the logo based on theme and terminal capabilities.
95+
* Returns the primary green color with appropriate fallback.
96+
*/
97+
export function getLogoAccentColor(
98+
themeName: ThemeName,
99+
env: CliEnv = getCliEnv(),
100+
): string {
101+
const isTruecolor = supportsTruecolor(env)
102+
// The primary green color - 'lime' is CSS bright green
103+
if (themeName === 'dark') {
104+
return isTruecolor ? '#9EFC62' : 'lime'
105+
}
106+
return isTruecolor ? '#65A83E' : 'green'
107+
}
108+
15109
const IDE_THEME_INFERENCE = {
16110
dark: [
17111
'dark',

0 commit comments

Comments
 (0)