summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/App.tsx
diff options
context:
space:
mode:
authorTaylor Mullen <[email protected]>2025-04-22 18:57:47 -0700
committerN. Taylor Mullen <[email protected]>2025-04-22 22:08:13 -0700
commit4c2a5045a0d209cfda5723a4dc84fe59670b558e (patch)
tree2a874aa35a524f683a39f89d5fc288b0a09596f7 /packages/cli/src/ui/App.tsx
parente163e024996ff8bb1152284322831c4f35696801 (diff)
Add theming support.
- Added a number of common themes to our support matrix: - AtomOneDark - Dracula - VS - GitHub - GoogleCode - XCode - ... Admittedly these all were randomly picked, we could probably curate these better... - Added a new `ThemeDialog` UI that can be accessed via `/theme`. It shows your currentlyt available themes and allows you to change them freely. It does **not**: - Save the theme between sessions - Allow you to hit escape - Show a preview prior to selection. - These themes are from reacts highlight js library. Fixes https://b.corp.google.com/issues/412797985
Diffstat (limited to 'packages/cli/src/ui/App.tsx')
-rw-r--r--packages/cli/src/ui/App.tsx64
1 files changed, 45 insertions, 19 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index 43a1d1e6..48184cea 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -4,17 +4,19 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useState, useMemo } from 'react';
+import React, { useState, useMemo, useCallback } from 'react';
import { Box, Text } from 'ink';
import { StreamingState, type HistoryItem } from './types.js';
import { useGeminiStream } from './hooks/useGeminiStream.js';
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
import { useInputHistory } from './hooks/useInputHistory.js';
+import { useThemeCommand } from './hooks/useThemeCommand.js';
import { Header } from './components/Header.js';
import { HistoryDisplay } from './components/HistoryDisplay.js';
import { LoadingIndicator } from './components/LoadingIndicator.js';
import { InputPrompt } from './components/InputPrompt.js';
import { Footer } from './components/Footer.js';
+import { ThemeDialog } from './components/ThemeDialog.js';
import { ITermDetectionWarning } from './utils/itermDetection.js';
import {
useStartupWarnings,
@@ -22,13 +24,13 @@ import {
} from './hooks/useAppEffects.js';
import { shortenPath, type Config } from '@gemini-code/server';
import { Colors } from './colors.js';
+import { Tips } from './components/Tips.js';
interface AppProps {
config: Config;
}
export const App = ({ config }: AppProps) => {
- // Destructured prop
const [history, setHistory] = useState<HistoryItem[]>([]);
const [startupWarnings, setStartupWarnings] = useState<string[]>([]);
const { streamingState, submitQuery, initError, debugMessage } =
@@ -36,9 +38,24 @@ export const App = ({ config }: AppProps) => {
const { elapsedTime, currentLoadingPhrase } =
useLoadingIndicator(streamingState);
+ const { isThemeDialogOpen, openThemeDialog, handleThemeSelect } =
+ useThemeCommand();
+
useStartupWarnings(setStartupWarnings);
useInitializationErrorEffect(initError, history, setHistory);
+ const handleFinalSubmit = useCallback(
+ (submittedValue: string) => {
+ const trimmedValue = submittedValue.trim();
+ if (trimmedValue === '/theme') {
+ openThemeDialog();
+ } else if (trimmedValue.length > 0) {
+ submitQuery(submittedValue);
+ }
+ },
+ [openThemeDialog, submitQuery],
+ );
+
const userMessages = useMemo(
() =>
history
@@ -56,13 +73,16 @@ export const App = ({ config }: AppProps) => {
const { query, handleSubmit: handleHistorySubmit } = useInputHistory({
userMessages,
- onSubmit: submitQuery,
+ onSubmit: handleFinalSubmit,
isActive: isInputActive,
});
+ // --- Render Logic ---
+
return (
<Box flexDirection="column" marginBottom={1} width="100%">
<Header />
+ <Tips />
{startupWarnings.length > 0 && (
<Box
@@ -112,25 +132,31 @@ export const App = ({ config }: AppProps) => {
</Box>
)}
- <Box flexDirection="column">
- <HistoryDisplay history={history} onSubmit={submitQuery} />
- <LoadingIndicator
- isLoading={streamingState === StreamingState.Responding}
- currentLoadingPhrase={currentLoadingPhrase}
- elapsedTime={elapsedTime}
- />
- </Box>
-
- {isInputActive && (
+ {isThemeDialogOpen ? (
+ <ThemeDialog onSelect={handleThemeSelect} />
+ ) : (
<>
- <Box>
- <Text color={Colors.SubtleComment}>cwd: </Text>
- <Text color={Colors.LightBlue}>
- {shortenPath(config.getTargetDir(), /*maxLength*/ 70)}
- </Text>
+ <Box flexDirection="column">
+ <HistoryDisplay history={history} onSubmit={submitQuery} />
+ <LoadingIndicator
+ isLoading={streamingState === StreamingState.Responding}
+ currentLoadingPhrase={currentLoadingPhrase}
+ elapsedTime={elapsedTime}
+ />
</Box>
- <InputPrompt onSubmit={handleHistorySubmit} />
+ {isInputActive && (
+ <>
+ <Box>
+ <Text color={Colors.SubtleComment}>cwd: </Text>
+ <Text color={Colors.LightBlue}>
+ {shortenPath(config.getTargetDir(), /*maxLength*/ 70)}
+ </Text>
+ </Box>
+
+ <InputPrompt onSubmit={handleHistorySubmit} />
+ </>
+ )}
</>
)}