diff options
| author | Jacob Richman <[email protected]> | 2025-05-01 10:34:07 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-05-01 10:34:07 -0700 |
| commit | 7e8f379dfbd4d70050ce301a42a38ba9c1f052f4 (patch) | |
| tree | 7d712dd0b3b6b246bc7dd92048cc91c5317a3a47 /packages/cli/src/ui/components/ThemeDialog.tsx | |
| parent | a18eea8c23dfb6759472d6b0bb80e13c2d6ef736 (diff) | |
Save settings to ~/.gemini/settings.json and optionally /your/workspace/.gemini/settings.json (#237)
Diffstat (limited to 'packages/cli/src/ui/components/ThemeDialog.tsx')
| -rw-r--r-- | packages/cli/src/ui/components/ThemeDialog.tsx | 98 |
1 files changed, 85 insertions, 13 deletions
diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx index 62ede336..7e8c5afd 100644 --- a/packages/cli/src/ui/components/ThemeDialog.tsx +++ b/packages/cli/src/ui/components/ThemeDialog.tsx @@ -4,33 +4,87 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; -import { Box, Text } from 'ink'; +import React, { useState } from 'react'; +import { Box, Text, useInput } from 'ink'; import { Colors } from '../colors.js'; -import { themeManager } from '../themes/theme-manager.js'; +import { themeManager, DEFAULT_THEME } from '../themes/theme-manager.js'; import { RadioButtonSelect } from './shared/RadioButtonSelect.js'; import { DiffRenderer } from './messages/DiffRenderer.js'; import { colorizeCode } from '../utils/CodeColorizer.js'; +import { LoadedSettings, SettingScope } from '../../config/settings.js'; interface ThemeDialogProps { /** Callback function when a theme is selected */ - onSelect: (themeName: string) => void; + onSelect: (themeName: string | undefined, scope: SettingScope) => void; /** Callback function when a theme is highlighted */ - onHighlight: (themeName: string) => void; + onHighlight: (themeName: string | undefined) => void; + /** The settings object */ + settings: LoadedSettings; } export function ThemeDialog({ onSelect, onHighlight, + settings, }: ThemeDialogProps): React.JSX.Element { + const [selectedScope, setSelectedScope] = useState<SettingScope>( + SettingScope.User, + ); + const themeItems = themeManager.getAvailableThemes().map((theme) => ({ label: theme.active ? `${theme.name} (Active)` : theme.name, value: theme.name, })); - const initialIndex = themeItems.findIndex( - (item) => item.value === themeManager.getActiveTheme().name, + const [selectInputKey, setSelectInputKey] = useState(Date.now()); + + const initialThemeIndex = themeItems.findIndex( + (item) => + item.value === + (settings.forScope(selectedScope).settings.theme || DEFAULT_THEME.name), + ); + + const scopeItems = [ + { label: 'User Settings', value: SettingScope.User }, + { label: 'Workspace Settings', value: SettingScope.Workspace }, + ]; + + const handleThemeSelect = (themeName: string) => { + onSelect(themeName, selectedScope); + }; + + const handleScopeHighlight = (scope: SettingScope) => { + setSelectedScope(scope); + setSelectInputKey(Date.now()); + }; + + const handleScopeSelect = (scope: SettingScope) => { + handleScopeHighlight(scope); + setFocusedSection('theme'); // Reset focus to theme section + }; + + const [focusedSection, setFocusedSection] = useState<'theme' | 'scope'>( + 'theme', ); + + useInput((input, key) => { + if (key.tab) { + setFocusedSection((prev) => (prev === 'theme' ? 'scope' : 'theme')); + } + }); + + let otherScopeModifiedMessage = ''; + const otherScope = + selectedScope === SettingScope.User + ? SettingScope.Workspace + : SettingScope.User; + if (settings.forScope(otherScope).settings.theme !== undefined) { + otherScopeModifiedMessage = + settings.forScope(selectedScope).settings.theme !== undefined + ? `(Also modified in ${otherScope})` + : `(Modified in ${otherScope})`; + } + return ( <Box borderStyle="round" @@ -39,18 +93,36 @@ export function ThemeDialog({ padding={1} width="50%" > - <Box marginBottom={1}> - <Text bold>Select Theme</Text> - </Box> + <Text bold={focusedSection === 'theme'}> + {focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '} + <Text color={Colors.SubtleComment}>{otherScopeModifiedMessage}</Text> + </Text> + <RadioButtonSelect + key={selectInputKey} items={themeItems} - initialIndex={initialIndex} - onSelect={onSelect} + initialIndex={initialThemeIndex} + onSelect={handleThemeSelect} // Use the wrapper handler onHighlight={onHighlight} + isFocused={focusedSection === 'theme'} /> + {/* Scope Selection */} + <Box marginTop={1} flexDirection="column"> + <Text bold={focusedSection === 'scope'}> + {focusedSection === 'scope' ? '> ' : ' '}Apply To + </Text> + <RadioButtonSelect + items={scopeItems} + initialIndex={0} // Default to User Settings + onSelect={handleScopeSelect} + onHighlight={handleScopeHighlight} + isFocused={focusedSection === 'scope'} + /> + </Box> + <Box marginTop={1}> <Text color={Colors.SubtleComment}> - (Use ↑/↓ arrows and Enter to select) + (Use ↑/↓ arrows and Enter to select, Tab to change focus) </Text> </Box> |
