update header display for narrow screen

This commit is contained in:
tanzhenxin 2026-01-16 14:45:07 +08:00
parent 881e7d038b
commit 758e5c0992

View file

@ -10,7 +10,7 @@ import Gradient from 'ink-gradient';
import { AuthType, shortenPath, tildeifyPath } from '@qwen-code/qwen-code-core';
import { theme } from '../semantic-colors.js';
import { shortAsciiLogo } from './AsciiArt.js';
import { getAsciiArtWidth } from '../utils/textUtils.js';
import { getAsciiArtWidth, getCachedStringWidth } from '../utils/textUtils.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
interface HeaderProps {
@ -21,15 +21,38 @@ interface HeaderProps {
workingDirectory: string;
}
function titleizeAuthType(value: string): string {
return value
.split(/[-_]/g)
.filter(Boolean)
.map((part) => {
if (part.toLowerCase() === 'ai') {
return 'AI';
}
return part.charAt(0).toUpperCase() + part.slice(1);
})
.join(' ');
}
// Format auth type for display
function formatAuthType(authType?: AuthType): string {
if (!authType) {
return 'Unknown';
}
switch (authType) {
case AuthType.QWEN_OAUTH:
return 'Qwen OAuth';
case AuthType.USE_OPENAI:
return 'OpenAI';
case AuthType.USE_GEMINI:
return 'Gemini';
case AuthType.USE_VERTEX_AI:
return 'Vertex AI';
case AuthType.USE_ANTHROPIC:
return 'Anthropic';
default:
return 'Unknown';
return titleizeAuthType(String(authType));
}
}
@ -48,30 +71,53 @@ export const Header: React.FC<HeaderProps> = ({
// Calculate available space properly:
// First determine if logo can be shown, then use remaining space for path
const logoGap = 4; // Gap between logo and info panel
const infoPanelPadding = 4; // paddingX={1} on each side + borders = ~4 chars
const containerMarginX = 2; // marginLeft + marginRight on the outer container
const logoGap = 2; // Gap between logo and info panel
const infoPanelPaddingX = 1;
const infoPanelBorderWidth = 2; // left + right border
const infoPanelChromeWidth = infoPanelBorderWidth + infoPanelPaddingX * 2;
const minPathLength = 40; // Minimum readable path length
const minInfoPanelWidth = minPathLength + infoPanelPadding;
const minInfoPanelWidth = minPathLength + infoPanelChromeWidth;
const availableTerminalWidth = Math.max(
0,
terminalWidth - containerMarginX * 2,
);
// Check if we have enough space for logo + gap + minimum info panel
const showLogo = terminalWidth >= logoWidth + logoGap + minInfoPanelWidth;
const showLogo =
availableTerminalWidth >= logoWidth + logoGap + minInfoPanelWidth;
// Calculate available width for info panel (use all remaining space)
const availableInfoPanelWidth = showLogo
? terminalWidth - logoWidth - logoGap
: terminalWidth;
? availableTerminalWidth - logoWidth - logoGap
: availableTerminalWidth;
// Calculate max path length (subtract padding/borders from available space)
const maxPathLength = Math.max(
minPathLength,
availableInfoPanelWidth - infoPanelPadding,
0,
availableInfoPanelWidth - infoPanelChromeWidth,
);
// Now shorten the path to fit the available space
const displayPath = shortenPath(
tildeifyPath(workingDirectory),
maxPathLength,
const infoPanelContentWidth = Math.max(
0,
availableInfoPanelWidth - infoPanelChromeWidth,
);
const authModelText = `${formattedAuthType} | ${model}`;
const authHintText = ' (/auth to change)';
const showAuthHint =
infoPanelContentWidth > 0 &&
getCachedStringWidth(authModelText + authHintText) <= infoPanelContentWidth;
// Now shorten the path to fit the available space
const tildeifiedPath = tildeifyPath(workingDirectory);
const shortenedPath = shortenPath(tildeifiedPath, Math.max(3, maxPathLength));
const displayPath =
maxPathLength <= 0
? ''
: shortenedPath.length > maxPathLength
? shortenedPath.slice(0, maxPathLength)
: shortenedPath;
// Use theme gradient colors if available, otherwise use text colors (excluding primary)
const gradientColors = theme.ui.gradient || [
@ -81,7 +127,12 @@ export const Header: React.FC<HeaderProps> = ({
];
return (
<Box flexDirection="row" alignItems="center" marginLeft={2} marginRight={2}>
<Box
flexDirection="row"
alignItems="center"
marginX={containerMarginX}
width={availableTerminalWidth}
>
{/* Left side: ASCII logo (only if enough space) */}
{showLogo && (
<>
@ -91,7 +142,7 @@ export const Header: React.FC<HeaderProps> = ({
</Gradient>
</Box>
{/* Fixed gap between logo and info panel */}
<Box width={4} />
<Box width={logoGap} />
</>
)}
@ -100,7 +151,7 @@ export const Header: React.FC<HeaderProps> = ({
flexDirection="column"
borderStyle="round"
borderColor={theme.border.default}
paddingX={1}
paddingX={infoPanelPaddingX}
flexGrow={1}
>
{/* Title line: >_ Qwen Code (v{version}) */}
@ -114,10 +165,10 @@ export const Header: React.FC<HeaderProps> = ({
<Text> </Text>
{/* Auth and Model line */}
<Text>
<Text color={theme.text.secondary}>
{formattedAuthType} | {model}
</Text>
<Text color={theme.text.secondary}> (/auth to change)</Text>
<Text color={theme.text.secondary}>{authModelText}</Text>
{showAuthHint && (
<Text color={theme.text.secondary}>{authHintText}</Text>
)}
</Text>
{/* Directory line */}
<Text color={theme.text.secondary}>{displayPath}</Text>