/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import React, { useState } from 'react'; import { Box, Text, useInput } from 'ink'; import { Colors } from '../colors.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 | undefined, scope: SettingScope) => void; /** Callback function when a theme is highlighted */ 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.User, ); // Generate theme items const themeItems = themeManager.getAvailableThemes().map((theme) => { const typeString = theme.type.charAt(0).toUpperCase() + theme.type.slice(1); return { label: theme.name, value: theme.name, themeNameDisplay: theme.name, themeTypeDisplay: typeString, }; }); const [selectInputKey, setSelectInputKey] = useState(Date.now()); // Determine which radio button should be initially selected in the theme list // This should reflect the theme *saved* for the selected scope, or the default const initialThemeIndex = themeItems.findIndex( (item) => item.value === (settings.merged.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 ( {/* Left Column: Selection */} {focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '} {otherScopeModifiedMessage} {/* Scope Selection */} {focusedSection === 'scope' ? '> ' : ' '}Apply To (Use ↑/↓ arrows and Enter to select, Tab to change focus) {/* Right Column: Preview */} Preview {colorizeCode( `# Source code print("Hello, World!") `, 'python', )} ); }