summaryrefslogtreecommitdiff
path: root/packages/cli/src
diff options
context:
space:
mode:
authorJacob Richman <[email protected]>2025-06-23 23:43:17 +0000
committerGitHub <[email protected]>2025-06-23 16:43:17 -0700
commitf741630572824d4d5f25a0849b2cd78a6b874c47 (patch)
tree671c2d46b4eec9ea633a6ab5045cfbbb15230101 /packages/cli/src
parent8c6545bf9d7e51012b44e4adbacfd24147b2a386 (diff)
Polish Theme Dialog (#1356)
Diffstat (limited to 'packages/cli/src')
-rw-r--r--packages/cli/src/ui/components/Header.tsx25
-rw-r--r--packages/cli/src/ui/components/ThemeDialog.tsx197
-rw-r--r--packages/cli/src/ui/components/shared/RadioButtonSelect.tsx13
3 files changed, 144 insertions, 91 deletions
diff --git a/packages/cli/src/ui/components/Header.tsx b/packages/cli/src/ui/components/Header.tsx
index 4a632142..375faf07 100644
--- a/packages/cli/src/ui/components/Header.tsx
+++ b/packages/cli/src/ui/components/Header.tsx
@@ -30,17 +30,22 @@ export const Header: React.FC<HeaderProps> = ({
terminalWidth >= widthOfLongLogo ? longAsciiLogo : shortAsciiLogo;
}
+ const artWidth = getAsciiArtWidth(displayTitle);
+
return (
- <>
- <Box marginBottom={1} alignItems="flex-start">
- {Colors.GradientColors ? (
- <Gradient colors={Colors.GradientColors}>
- <Text>{displayTitle}</Text>
- </Gradient>
- ) : (
+ <Box
+ marginBottom={1}
+ alignItems="flex-start"
+ width={artWidth}
+ flexShrink={0}
+ >
+ {Colors.GradientColors ? (
+ <Gradient colors={Colors.GradientColors}>
<Text>{displayTitle}</Text>
- )}
- </Box>
- </>
+ </Gradient>
+ ) : (
+ <Text>{displayTitle}</Text>
+ )}
+ </Box>
);
};
diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx
index 1fa6bee8..ba7ec1bb 100644
--- a/packages/cli/src/ui/components/ThemeDialog.tsx
+++ b/packages/cli/src/ui/components/ThemeDialog.tsx
@@ -115,95 +115,144 @@ export function ThemeDialog({
1,
);
+ const DAILOG_PADDING = 2;
+ const selectThemeHeight = themeItems.length + 1;
+ const SCOPE_SELECTION_HEIGHT = 4; // Height for the scope selection section + margin.
+ const SPACE_BETWEEN_THEME_SELECTION_AND_APPLY_TO = 1;
+ const TAB_TO_SELECT_HEIGHT = 2;
+ availableTerminalHeight = availableTerminalHeight ?? Number.MAX_SAFE_INTEGER;
+ availableTerminalHeight -= 2; // Top and bottom borders.
+ availableTerminalHeight -= TAB_TO_SELECT_HEIGHT;
+
+ let totalLeftHandSideHeight =
+ DAILOG_PADDING +
+ selectThemeHeight +
+ SCOPE_SELECTION_HEIGHT +
+ SPACE_BETWEEN_THEME_SELECTION_AND_APPLY_TO;
+
+ let showScopeSelection = true;
+ let includePadding = true;
+
+ // Remove content from the LHS that can be ommitted if it exceeds the available height.
+ if (totalLeftHandSideHeight > availableTerminalHeight) {
+ includePadding = false;
+ totalLeftHandSideHeight -= DAILOG_PADDING;
+ }
+
+ if (totalLeftHandSideHeight > availableTerminalHeight) {
+ // First, try hiding the scope selection
+ totalLeftHandSideHeight -= SCOPE_SELECTION_HEIGHT;
+ showScopeSelection = false;
+ }
+
+ // Don't focus the scope selection if it is hidden due to height constraints.
+ const currenFocusedSection = !showScopeSelection ? 'theme' : focusedSection;
+
// Vertical space taken by elements other than the two code blocks in the preview pane.
- // Includes "Preview" title, borders, padding, and margin between blocks.
- const PREVIEW_PANE_FIXED_VERTICAL_SPACE = 7;
- const availableTerminalHeightCodeBlock = availableTerminalHeight
- ? Math.max(
- Math.floor(
- (availableTerminalHeight - PREVIEW_PANE_FIXED_VERTICAL_SPACE) / 2,
- ),
- 2,
- )
- : undefined;
+ // Includes "Preview" title, borders, and margin between blocks.
+ const PREVIEW_PANE_FIXED_VERTICAL_SPACE = 8;
+
+ // The right column doesn't need to ever be shorter than the left column.
+ availableTerminalHeight = Math.max(
+ availableTerminalHeight,
+ totalLeftHandSideHeight,
+ );
+ const availableTerminalHeightCodeBlock =
+ availableTerminalHeight -
+ PREVIEW_PANE_FIXED_VERTICAL_SPACE -
+ (includePadding ? 2 : 0) * 2;
+ // Give slightly more space to the code block as it is 3 lines longer.
+ const diffHeight = Math.floor(availableTerminalHeightCodeBlock / 2) - 1;
+ const codeBlockHeight = Math.ceil(availableTerminalHeightCodeBlock / 2) + 1;
+
return (
<Box
borderStyle="round"
borderColor={Colors.Gray}
- flexDirection="row"
- padding={1}
+ flexDirection="column"
+ paddingTop={includePadding ? 1 : 0}
+ paddingBottom={includePadding ? 1 : 0}
+ paddingLeft={1}
+ paddingRight={1}
width="100%"
>
- {/* Left Column: Selection */}
- <Box flexDirection="column" width="45%" paddingRight={2}>
- <Text bold={focusedSection === 'theme'}>
- {focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '}
- <Text color={Colors.Gray}>{otherScopeModifiedMessage}</Text>
- </Text>
- <RadioButtonSelect
- key={selectInputKey}
- items={themeItems}
- initialIndex={initialThemeIndex}
- onSelect={handleThemeSelect}
- onHighlight={onHighlight}
- isFocused={focusedSection === 'theme'}
- />
-
- {/* Scope Selection */}
- <Box marginTop={1} flexDirection="column">
- <Text bold={focusedSection === 'scope'}>
- {focusedSection === 'scope' ? '> ' : ' '}Apply To
+ <Box flexDirection="row">
+ {/* Left Column: Selection */}
+ <Box flexDirection="column" width="45%" paddingRight={2}>
+ <Text bold={currenFocusedSection === 'theme'} wrap="truncate">
+ {currenFocusedSection === 'theme' ? '> ' : ' '}Select Theme{' '}
+ <Text color={Colors.Gray}>{otherScopeModifiedMessage}</Text>
</Text>
<RadioButtonSelect
- items={scopeItems}
- initialIndex={0} // Default to User Settings
- onSelect={handleScopeSelect}
- onHighlight={handleScopeHighlight}
- isFocused={focusedSection === 'scope'}
+ key={selectInputKey}
+ items={themeItems}
+ initialIndex={initialThemeIndex}
+ onSelect={handleThemeSelect}
+ onHighlight={onHighlight}
+ isFocused={currenFocusedSection === 'theme'}
/>
- </Box>
- <Box marginTop={1}>
- <Text color={Colors.Gray}>
- (Use Enter to select, Tab to change focus)
- </Text>
+ {/* Scope Selection */}
+ {showScopeSelection && (
+ <Box marginTop={1} flexDirection="column">
+ <Text bold={currenFocusedSection === 'scope'} wrap="truncate">
+ {currenFocusedSection === 'scope' ? '> ' : ' '}Apply To
+ </Text>
+ <RadioButtonSelect
+ items={scopeItems}
+ initialIndex={0} // Default to User Settings
+ onSelect={handleScopeSelect}
+ onHighlight={handleScopeHighlight}
+ isFocused={currenFocusedSection === 'scope'}
+ />
+ </Box>
+ )}
</Box>
- </Box>
- {/* Right Column: Preview */}
- <Box flexDirection="column" width="55%" paddingLeft={2}>
- <Text bold>Preview</Text>
- <Box
- borderStyle="single"
- borderColor={Colors.Gray}
- padding={1}
- flexDirection="column"
- >
- {colorizeCode(
- `# function
-def fibonacci(n):
- a, b = 0, 1
- for _ in range(n):
- a, b = b, a + b
- return a`,
- 'python',
- availableTerminalHeightCodeBlock,
- colorizeCodeWidth,
- )}
- <Box marginTop={1} />
- <DiffRenderer
- diffContent={`--- a/old_file.txt
-+++ b/new_file.txt
-@@ -1,4 +1,5 @@
- This is a context line.
--This line was deleted.
-+This line was added.
-`}
- availableTerminalHeight={availableTerminalHeightCodeBlock}
- terminalWidth={colorizeCodeWidth}
- />
+ {/* Right Column: Preview */}
+ <Box flexDirection="column" width="55%" paddingLeft={2}>
+ <Text bold>Preview</Text>
+ <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
+-+++ b/new_file.txt
+-@@ -1,4 +1,5 @@
+- This is a context line.
+--This line was deleted.
+-+This line was added.
+-`}
+ availableTerminalHeight={diffHeight}
+ terminalWidth={colorizeCodeWidth}
+ />
+ </Box>
</Box>
</Box>
+ <Box marginTop={1}>
+ <Text color={Colors.Gray} wrap="truncate">
+ (Use Enter to select
+ {showScopeSelection ? ', Tab to change focus' : ''})
+ </Text>
+ </Box>
</Box>
);
}
diff --git a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
index 71077f1c..fab0615c 100644
--- a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
+++ b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
@@ -5,7 +5,7 @@
*/
import React from 'react';
-import { Text } from 'ink';
+import { Text, Box } from 'ink';
import SelectInput, {
type ItemProps as InkSelectItemProps,
type IndicatorProps as InkSelectIndicatorProps,
@@ -78,12 +78,11 @@ export function RadioButtonSelect<T>({
isSelected = false,
}: InkSelectIndicatorProps): React.JSX.Element {
return (
- <Text
- color={isSelected ? Colors.AccentGreen : Colors.Foreground}
- wrap="truncate"
- >
- {isSelected ? '● ' : '○ '}
- </Text>
+ <Box minWidth={2} flexShrink={0}>
+ <Text color={isSelected ? Colors.AccentGreen : Colors.Foreground}>
+ {isSelected ? '●' : '○'}
+ </Text>
+ </Box>
);
}