diff --git a/packages/cli/src/config/footerItems.ts b/packages/cli/src/config/footerItems.ts
index b9ba040c9f..a0752de4e2 100644
--- a/packages/cli/src/config/footerItems.ts
+++ b/packages/cli/src/config/footerItems.ts
@@ -61,12 +61,6 @@ export const ALL_ITEMS = [
export type FooterItemId = (typeof ALL_ITEMS)[number]['id'];
-export interface FooterItem {
- id: string;
- header: string;
- description: string;
-}
-
export const DEFAULT_ORDER = [
'cwd',
'git-branch',
diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx
index ea2d63de1f..c51c2e279a 100644
--- a/packages/cli/src/ui/components/Footer.tsx
+++ b/packages/cli/src/ui/components/Footer.tsx
@@ -101,6 +101,52 @@ const CorgiIndicator: React.FC = () => (
);
+export interface FooterRowItem {
+ key: string;
+ header: string;
+ element: React.ReactNode;
+}
+
+const COLUMN_GAP = 3;
+
+export const FooterRow: React.FC<{
+ items: FooterRowItem[];
+ showLabels: boolean;
+}> = ({ items, showLabels }) => {
+ const elements: React.ReactNode[] = [];
+
+ items.forEach((item, idx) => {
+ if (idx > 0 && !showLabels) {
+ elements.push(
+
+ ·
+ ,
+ );
+ }
+
+ elements.push(
+
+ {showLabels && (
+
+ {item.header}
+
+ )}
+ {item.element}
+ ,
+ );
+ });
+
+ return (
+
+ {elements}
+
+ );
+};
+
function isFooterItemId(id: string): id is FooterItemId {
return ALL_ITEMS.some((i) => i.id === id);
}
@@ -251,21 +297,19 @@ export const Footer: React.FC = () => {
break;
}
case 'context-remaining': {
- if (!settings.merged.ui.footer.hideContextPercentage) {
- addCol(
- id,
- header,
- () => (
-
- ),
- 10, // "100% left" is 9 chars
- );
- }
+ addCol(
+ id,
+ header,
+ () => (
+
+ ),
+ 10, // "100% left" is 9 chars
+ );
break;
}
case 'quota': {
@@ -366,7 +410,6 @@ export const Footer: React.FC = () => {
}
// --- Width Fitting Logic ---
- const COLUMN_GAP = 3;
let currentWidth = 2; // Initial padding
const columnsToRender: FooterColumn[] = [];
let droppedAny = false;
@@ -396,58 +439,26 @@ export const Footer: React.FC = () => {
);
const excessSpace = Math.max(0, terminalWidth - totalBudgeted);
- const finalElements: React.ReactNode[] = [];
-
- columnsToRender.forEach((col, idx) => {
- if (idx > 0 && !showLabels) {
- finalElements.push(
-
- ·
- ,
- );
- }
-
+ const rowItems: FooterRowItem[] = columnsToRender.map((col) => {
const maxWidth = col.id === 'cwd' ? 20 + excessSpace : col.width;
- finalElements.push(
-
- {showLabels && (
-
- {col.header}
-
- )}
- {col.element(maxWidth)}
- ,
- );
+ return {
+ key: col.id,
+ header: col.header,
+ element: col.element(maxWidth),
+ };
});
if (droppedAny) {
- if (!showLabels) {
- finalElements.push(
-
- ·
- ,
- );
- }
- finalElements.push(
-
- {showLabels && }
-
- …
-
- ,
- );
+ rowItems.push({
+ key: 'ellipsis',
+ header: '',
+ element: …,
+ });
}
return (
-
- {finalElements}
+
+
);
};
diff --git a/packages/cli/src/ui/components/FooterConfigDialog.tsx b/packages/cli/src/ui/components/FooterConfigDialog.tsx
index f887c8db0b..d2e779487a 100644
--- a/packages/cli/src/ui/components/FooterConfigDialog.tsx
+++ b/packages/cli/src/ui/components/FooterConfigDialog.tsx
@@ -14,6 +14,7 @@ import { keyMatchers, Command } from '../keyMatchers.js';
import { TextInput } from './shared/TextInput.js';
import { useFuzzyList } from '../hooks/useFuzzyList.js';
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
+import { FooterRow, type FooterRowItem } from './Footer.js';
import {
ALL_ITEMS,
DEFAULT_ORDER,
@@ -316,98 +317,47 @@ export const FooterConfigDialog: React.FC = ({
const getColor = (id: string, defaultColor?: string) =>
id === activeId ? 'white' : defaultColor || itemColor;
- // Mock values for preview
- const mockValues: Record<
- string,
- { header: string; data: React.ReactNode }
- > = {
- cwd: {
- header: 'Path',
- data: ~/project/path,
- },
- 'git-branch': {
- header: 'Branch',
- data: main,
- },
- 'sandbox-status': {
- header: '/docs',
- data: docker,
- },
- 'model-name': {
- header: '/model',
- data: (
- gemini-2.5-pro
- ),
- },
- 'context-remaining': {
- header: 'Context',
- data: (
- 85% left
- ),
- },
- quota: {
- header: '/stats',
- data: daily 97%,
- },
- 'memory-usage': {
- header: 'Memory',
- data: ,
- },
- 'session-id': {
- header: 'Session',
- data: 769992f9,
- },
- 'code-changes': {
- header: 'Diff',
- data: (
-
-
- +12
-
-
- -4
-
- ),
- },
- 'token-count': {
- header: 'Tokens',
- data: (
- 1.5k tokens
- ),
- },
+ // Mock data for preview (headers come from ALL_ITEMS)
+ const mockData: Record = {
+ cwd: ~/project/path,
+ 'git-branch': main,
+ 'sandbox-status': (
+ docker
+ ),
+ 'model-name': (
+ gemini-2.5-pro
+ ),
+ 'context-remaining': (
+ 85% left
+ ),
+ quota: daily 97%,
+ 'memory-usage': ,
+ 'session-id': (
+ 769992f9
+ ),
+ 'code-changes': (
+
+
+ +12
+
+
+ -4
+
+ ),
+ 'token-count': (
+ 1.5k tokens
+ ),
};
- const previewElements: React.ReactNode[] = [];
+ const rowItems: FooterRowItem[] = itemsToPreview
+ .filter((id: string) => mockData[id])
+ .map((id: string) => ({
+ key: id,
+ header: ALL_ITEMS.find((i) => i.id === id)?.header ?? id,
+ element: mockData[id],
+ }));
- itemsToPreview.forEach((id: string, idx: number) => {
- const mock = mockValues[id];
- if (!mock) return;
-
- if (idx > 0 && !showLabels) {
- previewElements.push(
-
- ·
- ,
- );
- }
-
- previewElements.push(
-
- {showLabels && (
-
- {mock.header}
-
- )}
- {mock.data}
- ,
- );
- });
-
- return (
-
- {previewElements}
-
- );
+ return ;
}, [orderedIds, selectedIds, activeId, isResetFocused, showLabels]);
return (