summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/components/ThemeDialog.tsx
diff options
context:
space:
mode:
authorAli Al Jufairi <[email protected]>2025-07-20 16:51:18 +0900
committerGitHub <[email protected]>2025-07-20 07:51:18 +0000
commit76b935d598b895240b9bc2b182eb9f1e1b24be0d (patch)
treecc76fb76a8655f7ab9a064b6c2af750726dd2478 /packages/cli/src/ui/components/ThemeDialog.tsx
parentc0bfa388c571342265915f8de888a43190c82759 (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.tsx125
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}>