diff options
| author | Ali Al Jufairi <[email protected]> | 2025-07-20 16:51:18 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-20 07:51:18 +0000 |
| commit | 76b935d598b895240b9bc2b182eb9f1e1b24be0d (patch) | |
| tree | cc76fb76a8655f7ab9a064b6c2af750726dd2478 /packages/cli/src/ui/components/ThemeDialog.tsx | |
| parent | c0bfa388c571342265915f8de888a43190c82759 (diff) | |
Feature custom themes logic (#2639)
Co-authored-by: Jacob Richman <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/components/ThemeDialog.tsx')
| -rw-r--r-- | packages/cli/src/ui/components/ThemeDialog.tsx | 125 |
1 files changed, 78 insertions, 47 deletions
diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx index be8c52a1..41c39b63 100644 --- a/packages/cli/src/ui/components/ThemeDialog.tsx +++ b/packages/cli/src/ui/components/ThemeDialog.tsx @@ -36,22 +36,45 @@ export function ThemeDialog({ SettingScope.User, ); - const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1); + // Track the currently highlighted theme name + const [highlightedThemeName, setHighlightedThemeName] = useState< + string | undefined + >(settings.merged.theme || DEFAULT_THEME.name); + // Generate theme items filtered by selected scope + const customThemes = + selectedScope === SettingScope.User + ? settings.user.settings.customThemes || {} + : settings.merged.customThemes || {}; + const builtInThemes = themeManager + .getAvailableThemes() + .filter((theme) => theme.type !== 'custom'); + const customThemeNames = Object.keys(customThemes); + const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1); // Generate theme items - const themeItems = themeManager.getAvailableThemes().map((theme) => ({ - label: theme.name, - value: theme.name, - themeNameDisplay: theme.name, - themeTypeDisplay: capitalize(theme.type), - })); + const themeItems = [ + ...builtInThemes.map((theme) => ({ + label: theme.name, + value: theme.name, + themeNameDisplay: theme.name, + themeTypeDisplay: capitalize(theme.type), + })), + ...customThemeNames.map((name) => ({ + label: name, + value: name, + themeNameDisplay: name, + themeTypeDisplay: 'Custom', + })), + ]; 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 + // Find the index of the selected theme, but only if it exists in the list + const selectedThemeName = settings.merged.theme || DEFAULT_THEME.name; const initialThemeIndex = themeItems.findIndex( - (item) => item.value === (settings.merged.theme || DEFAULT_THEME.name), + (item) => item.value === selectedThemeName, ); + // If not found, fallback to the first theme + const safeInitialThemeIndex = initialThemeIndex >= 0 ? initialThemeIndex : 0; const scopeItems = [ { label: 'User Settings', value: SettingScope.User }, @@ -66,6 +89,11 @@ export function ThemeDialog({ [onSelect, selectedScope], ); + const handleThemeHighlight = (themeName: string) => { + setHighlightedThemeName(themeName); + onHighlight(themeName); + }; + const handleScopeHighlight = useCallback((scope: SettingScope) => { setSelectedScope(scope); setSelectInputKey(Date.now()); @@ -182,7 +210,6 @@ export function ThemeDialog({ // The code block is slightly longer than the diff, so give it more space. const codeBlockHeight = Math.ceil(availableHeightForPanes * 0.6); const diffHeight = Math.floor(availableHeightForPanes * 0.4); - const themeType = capitalize(themeManager.getActiveTheme().type); return ( <Box borderStyle="round" @@ -204,9 +231,9 @@ export function ThemeDialog({ <RadioButtonSelect key={selectInputKey} items={themeItems} - initialIndex={initialThemeIndex} + initialIndex={safeInitialThemeIndex} onSelect={handleThemeSelect} - onHighlight={onHighlight} + onHighlight={handleThemeHighlight} isFocused={currenFocusedSection === 'theme'} maxItemsToShow={8} showScrollArrows={true} @@ -233,40 +260,44 @@ export function ThemeDialog({ {/* Right Column: Preview */} <Box flexDirection="column" width="55%" paddingLeft={2}> - <Text bold>{themeType} Theme Preview</Text> - <Box - borderStyle="single" - borderColor={Colors.Gray} - paddingTop={includePadding ? 1 : 0} - paddingBottom={includePadding ? 1 : 0} - paddingLeft={1} - paddingRight={1} - flexDirection="column" - > - {colorizeCode( - `# python function -def fibonacci(n): - a, b = 0, 1 - for _ in range(n): - a, b = b, a + b - return a`, - 'python', - codeBlockHeight, - colorizeCodeWidth, - )} - <Box marginTop={1} /> - <DiffRenderer - diffContent={`--- a/util.py -+++ b/util.py -@@ -1,3 +1,3 @@ - def greet(name): -- print("Hello, " + name) -+ print(f"Hello, {name}!") -`} - availableTerminalHeight={diffHeight} - terminalWidth={colorizeCodeWidth} - /> - </Box> + <Text bold>Preview</Text> + {/* Get the Theme object for the highlighted theme, fallback to default if not found */} + {(() => { + const previewTheme = + themeManager.getTheme( + highlightedThemeName || DEFAULT_THEME.name, + ) || DEFAULT_THEME; + return ( + <Box + borderStyle="single" + borderColor={Colors.Gray} + paddingTop={includePadding ? 1 : 0} + paddingBottom={includePadding ? 1 : 0} + paddingLeft={1} + paddingRight={1} + flexDirection="column" + > + {colorizeCode( + `# function +-def fibonacci(n): +- a, b = 0, 1 +- for _ in range(n): +- a, b = b, a + b +- return a`, + 'python', + codeBlockHeight, + colorizeCodeWidth, + )} + <Box marginTop={1} /> + <DiffRenderer + diffContent={`--- a/old_file.txt\n+++ b/new_file.txt\n@@ -1,6 +1,7 @@\n # function\n-def fibonacci(n):\n- a, b = 0, 1\n- for _ in range(n):\n- a, b = b, a + b\n- return a\n+def fibonacci(n):\n+ a, b = 0, 1\n+ for _ in range(n):\n+ a, b = b, a + b\n+ return a\n+\n+print(fibonacci(10))\n`} + availableTerminalHeight={diffHeight} + terminalWidth={colorizeCodeWidth} + theme={previewTheme} + /> + </Box> + ); + })()} </Box> </Box> <Box marginTop={1}> |
