From ae387b61a9c1c700b33f85fc191636bd1be5cba6 Mon Sep 17 00:00:00 2001 From: Billy Biggs Date: Mon, 29 Sep 2025 16:22:47 -0700 Subject: [PATCH] Reduce margin on narrow screens, flow the footer contents (#8042) --- packages/cli/src/ui/App.tsx | 25 +++++++- .../src/ui/components/ContextUsageDisplay.tsx | 8 ++- .../cli/src/ui/components/Footer.test.tsx | 35 +++++------ packages/cli/src/ui/components/Footer.tsx | 62 ++++++++----------- .../__snapshots__/Footer.test.tsx.snap | 15 +---- .../cli/src/ui/layouts/DefaultAppLayout.tsx | 6 +- packages/cli/src/utils/math.ts | 14 +++++ 7 files changed, 91 insertions(+), 74 deletions(-) create mode 100644 packages/cli/src/utils/math.ts diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 54684a8c2c..ea8482a161 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -5,15 +5,34 @@ */ import { useIsScreenReaderEnabled } from 'ink'; +import { useTerminalSize } from './hooks/useTerminalSize.js'; +import { lerp } from '../utils/math.js'; import { useUIState } from './contexts/UIStateContext.js'; import { StreamingContext } from './contexts/StreamingContext.js'; import { QuittingDisplay } from './components/QuittingDisplay.js'; import { ScreenReaderAppLayout } from './layouts/ScreenReaderAppLayout.js'; import { DefaultAppLayout } from './layouts/DefaultAppLayout.js'; +const getContainerWidth = (terminalWidth: number): string => { + if (terminalWidth <= 80) { + return '98%'; + } + if (terminalWidth >= 132) { + return '90%'; + } + + // Linearly interpolate between 80 columns (98%) and 132 columns (90%). + const t = (terminalWidth - 80) / (132 - 80); + const percentage = lerp(98, 90, t); + + return `${Math.round(percentage)}%`; +}; + export const App = () => { const uiState = useUIState(); const isScreenReaderEnabled = useIsScreenReaderEnabled(); + const { columns } = useTerminalSize(); + const containerWidth = getContainerWidth(columns); if (uiState.quittingMessages) { return ; @@ -21,7 +40,11 @@ export const App = () => { return ( - {isScreenReaderEnabled ? : } + {isScreenReaderEnabled ? ( + + ) : ( + + )} ); }; diff --git a/packages/cli/src/ui/components/ContextUsageDisplay.tsx b/packages/cli/src/ui/components/ContextUsageDisplay.tsx index d7d8c063f0..25dad9c7e3 100644 --- a/packages/cli/src/ui/components/ContextUsageDisplay.tsx +++ b/packages/cli/src/ui/components/ContextUsageDisplay.tsx @@ -11,15 +11,21 @@ import { tokenLimit } from '@google/gemini-cli-core'; export const ContextUsageDisplay = ({ promptTokenCount, model, + terminalWidth, }: { promptTokenCount: number; model: string; + terminalWidth: number; }) => { const percentage = promptTokenCount / tokenLimit(model); + const percentageLeft = ((1 - percentage) * 100).toFixed(0); + + const label = terminalWidth < 100 ? '%' : '% context left'; return ( - ({((1 - percentage) * 100).toFixed(0)}% context left) + ({percentageLeft} + {label}) ); }; diff --git a/packages/cli/src/ui/components/Footer.test.tsx b/packages/cli/src/ui/components/Footer.test.tsx index 3c0a4d9b96..31f256d5c6 100644 --- a/packages/cli/src/ui/components/Footer.test.tsx +++ b/packages/cli/src/ui/components/Footer.test.tsx @@ -9,7 +9,6 @@ import { describe, it, expect, vi } from 'vitest'; import { Footer } from './Footer.js'; import * as useTerminalSize from '../hooks/useTerminalSize.js'; import { tildeifyPath } from '@google/gemini-cli-core'; -import path from 'node:path'; import { type UIState, UIStateContext } from '../contexts/UIStateContext.js'; import { ConfigContext } from '../contexts/ConfigContext.js'; import { SettingsContext } from '../contexts/SettingsContext.js'; @@ -103,34 +102,22 @@ describe('