mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-03 06:37:46 -07:00
Update banner design (#13420)
This commit is contained in:
@@ -10,11 +10,9 @@ import { Tips } from './Tips.js';
|
|||||||
import { useSettings } from '../contexts/SettingsContext.js';
|
import { useSettings } from '../contexts/SettingsContext.js';
|
||||||
import { useConfig } from '../contexts/ConfigContext.js';
|
import { useConfig } from '../contexts/ConfigContext.js';
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
import { useUIState } from '../contexts/UIStateContext.js';
|
||||||
import { Banner } from './Banner.js';
|
|
||||||
import { theme } from '../semantic-colors.js';
|
|
||||||
import { Colors } from '../colors.js';
|
|
||||||
import { persistentState } from '../../utils/persistentState.js';
|
import { persistentState } from '../../utils/persistentState.js';
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { Banner } from './Banner.js';
|
||||||
|
|
||||||
interface AppHeaderProps {
|
interface AppHeaderProps {
|
||||||
version: string;
|
version: string;
|
||||||
@@ -35,11 +33,8 @@ export const AppHeader = ({ version }: AppHeaderProps) => {
|
|||||||
warningText === '' &&
|
warningText === '' &&
|
||||||
!config.getPreviewFeatures() &&
|
!config.getPreviewFeatures() &&
|
||||||
defaultBannerShownCount < 5;
|
defaultBannerShownCount < 5;
|
||||||
const bannerText = showDefaultBanner ? defaultText : warningText;
|
|
||||||
const unescapedBannerText = bannerText.replace(/\\n/g, '\n');
|
|
||||||
|
|
||||||
const defaultColor = Colors.AccentBlue;
|
const bannerText = showDefaultBanner ? defaultText : warningText;
|
||||||
const fontColor = warningText === '' ? defaultColor : theme.status.warning;
|
|
||||||
|
|
||||||
const hasIncrementedRef = useRef(false);
|
const hasIncrementedRef = useRef(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -55,11 +50,11 @@ export const AppHeader = ({ version }: AppHeaderProps) => {
|
|||||||
{!(settings.merged.ui?.hideBanner || config.getScreenReader()) && (
|
{!(settings.merged.ui?.hideBanner || config.getScreenReader()) && (
|
||||||
<>
|
<>
|
||||||
<Header version={version} nightly={nightly} />
|
<Header version={version} nightly={nightly} />
|
||||||
{bannerVisible && unescapedBannerText && (
|
{bannerVisible && bannerText && (
|
||||||
<Banner
|
<Banner
|
||||||
width={mainAreaWidth}
|
width={mainAreaWidth}
|
||||||
bannerText={unescapedBannerText}
|
bannerText={bannerText}
|
||||||
color={fontColor}
|
isWarning={warningText !== ''}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6,24 +6,65 @@
|
|||||||
|
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
import { ThemedGradient } from './ThemedGradient.js';
|
import { ThemedGradient } from './ThemedGradient.js';
|
||||||
|
import { theme } from '../semantic-colors.js';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export function getFormattedBannerContent(
|
||||||
|
rawText: string,
|
||||||
|
isWarning: boolean,
|
||||||
|
subsequentLineColor: string,
|
||||||
|
): ReactNode {
|
||||||
|
if (isWarning) {
|
||||||
|
return (
|
||||||
|
<Text color={theme.status.warning}>{rawText.replace(/\\n/g, '\n')}</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = rawText.replace(/\\n/g, '\n');
|
||||||
|
const lines = text.split('\n');
|
||||||
|
|
||||||
|
return lines.map((line, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return (
|
||||||
|
<ThemedGradient key={index}>
|
||||||
|
<Text>{line}</Text>
|
||||||
|
</ThemedGradient>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text key={index} color={subsequentLineColor}>
|
||||||
|
{line}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
interface BannerProps {
|
interface BannerProps {
|
||||||
bannerText: string;
|
bannerText: string;
|
||||||
color: string;
|
isWarning: boolean;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Banner = ({ bannerText, color, width }: BannerProps) => (
|
export const Banner = ({ bannerText, isWarning, width }: BannerProps) => {
|
||||||
<Box
|
const subsequentLineColor = theme.text.primary;
|
||||||
flexDirection="column"
|
|
||||||
borderStyle="round"
|
const formattedBannerContent = getFormattedBannerContent(
|
||||||
borderColor={color}
|
bannerText,
|
||||||
width={width}
|
isWarning,
|
||||||
paddingLeft={1}
|
subsequentLineColor,
|
||||||
paddingRight={1}
|
);
|
||||||
>
|
|
||||||
<ThemedGradient>
|
return (
|
||||||
<Text>{bannerText}</Text>
|
<Box
|
||||||
</ThemedGradient>
|
flexDirection="column"
|
||||||
</Box>
|
borderStyle="round"
|
||||||
);
|
borderColor={isWarning ? theme.status.warning : theme.border.default}
|
||||||
|
width={width}
|
||||||
|
paddingLeft={1}
|
||||||
|
paddingRight={1}
|
||||||
|
>
|
||||||
|
{formattedBannerContent}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ describe('Gradient Crash Regression Tests', () => {
|
|||||||
|
|
||||||
it('<Banner /> should not crash when theme.ui.gradient is empty', () => {
|
it('<Banner /> should not crash when theme.ui.gradient is empty', () => {
|
||||||
const { lastFrame } = renderWithProviders(
|
const { lastFrame } = renderWithProviders(
|
||||||
<Banner bannerText="Test Banner" color="blue" width={80} />,
|
<Banner bannerText="Test Banner" isWarning={false} width={80} />,
|
||||||
{
|
{
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user