Polish Theme Dialog (#1356)

This commit is contained in:
Jacob Richman 2025-06-23 23:43:17 +00:00 committed by GitHub
parent 8c6545bf9d
commit f741630572
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 144 additions and 91 deletions

View File

@ -30,17 +30,22 @@ export const Header: React.FC<HeaderProps> = ({
terminalWidth >= widthOfLongLogo ? longAsciiLogo : shortAsciiLogo; terminalWidth >= widthOfLongLogo ? longAsciiLogo : shortAsciiLogo;
} }
const artWidth = getAsciiArtWidth(displayTitle);
return ( return (
<> <Box
<Box marginBottom={1} alignItems="flex-start"> marginBottom={1}
{Colors.GradientColors ? ( alignItems="flex-start"
<Gradient colors={Colors.GradientColors}> width={artWidth}
<Text>{displayTitle}</Text> flexShrink={0}
</Gradient> >
) : ( {Colors.GradientColors ? (
<Gradient colors={Colors.GradientColors}>
<Text>{displayTitle}</Text> <Text>{displayTitle}</Text>
)} </Gradient>
</Box> ) : (
</> <Text>{displayTitle}</Text>
)}
</Box>
); );
}; };

View File

@ -115,94 +115,143 @@ export function ThemeDialog({
1, 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. // Vertical space taken by elements other than the two code blocks in the preview pane.
// Includes "Preview" title, borders, padding, and margin between blocks. // Includes "Preview" title, borders, and margin between blocks.
const PREVIEW_PANE_FIXED_VERTICAL_SPACE = 7; const PREVIEW_PANE_FIXED_VERTICAL_SPACE = 8;
const availableTerminalHeightCodeBlock = availableTerminalHeight
? Math.max( // The right column doesn't need to ever be shorter than the left column.
Math.floor( availableTerminalHeight = Math.max(
(availableTerminalHeight - PREVIEW_PANE_FIXED_VERTICAL_SPACE) / 2, availableTerminalHeight,
), totalLeftHandSideHeight,
2, );
) const availableTerminalHeightCodeBlock =
: undefined; 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 ( return (
<Box <Box
borderStyle="round" borderStyle="round"
borderColor={Colors.Gray} borderColor={Colors.Gray}
flexDirection="row" flexDirection="column"
padding={1} paddingTop={includePadding ? 1 : 0}
paddingBottom={includePadding ? 1 : 0}
paddingLeft={1}
paddingRight={1}
width="100%" width="100%"
> >
{/* Left Column: Selection */} <Box flexDirection="row">
<Box flexDirection="column" width="45%" paddingRight={2}> {/* Left Column: Selection */}
<Text bold={focusedSection === 'theme'}> <Box flexDirection="column" width="45%" paddingRight={2}>
{focusedSection === 'theme' ? '> ' : ' '}Select Theme{' '} <Text bold={currenFocusedSection === 'theme'} wrap="truncate">
<Text color={Colors.Gray}>{otherScopeModifiedMessage}</Text> {currenFocusedSection === 'theme' ? '> ' : ' '}Select Theme{' '}
</Text> <Text color={Colors.Gray}>{otherScopeModifiedMessage}</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
</Text> </Text>
<RadioButtonSelect <RadioButtonSelect
items={scopeItems} key={selectInputKey}
initialIndex={0} // Default to User Settings items={themeItems}
onSelect={handleScopeSelect} initialIndex={initialThemeIndex}
onHighlight={handleScopeHighlight} onSelect={handleThemeSelect}
isFocused={focusedSection === 'scope'} onHighlight={onHighlight}
isFocused={currenFocusedSection === 'theme'}
/> />
{/* 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>
<Box marginTop={1}> {/* Right Column: Preview */}
<Text color={Colors.Gray}> <Box flexDirection="column" width="55%" paddingLeft={2}>
(Use Enter to select, Tab to change focus) <Text bold>Preview</Text>
</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> </Box>
<Box marginTop={1}>
{/* Right Column: Preview */} <Text color={Colors.Gray} wrap="truncate">
<Box flexDirection="column" width="55%" paddingLeft={2}> (Use Enter to select
<Text bold>Preview</Text> {showScopeSelection ? ', Tab to change focus' : ''})
<Box </Text>
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}
/>
</Box>
</Box> </Box>
</Box> </Box>
); );

View File

@ -5,7 +5,7 @@
*/ */
import React from 'react'; import React from 'react';
import { Text } from 'ink'; import { Text, Box } from 'ink';
import SelectInput, { import SelectInput, {
type ItemProps as InkSelectItemProps, type ItemProps as InkSelectItemProps,
type IndicatorProps as InkSelectIndicatorProps, type IndicatorProps as InkSelectIndicatorProps,
@ -78,12 +78,11 @@ export function RadioButtonSelect<T>({
isSelected = false, isSelected = false,
}: InkSelectIndicatorProps): React.JSX.Element { }: InkSelectIndicatorProps): React.JSX.Element {
return ( return (
<Text <Box minWidth={2} flexShrink={0}>
color={isSelected ? Colors.AccentGreen : Colors.Foreground} <Text color={isSelected ? Colors.AccentGreen : Colors.Foreground}>
wrap="truncate" {isSelected ? '●' : '○'}
> </Text>
{isSelected ? '● ' : '○ '} </Box>
</Text>
); );
} }