Just a whole lot of crap
This commit is contained in:
253
src/tui/components/common/ModernProgressBar.jsx
Normal file
253
src/tui/components/common/ModernProgressBar.jsx
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Modern Progress Bar Component
|
||||
* Enhanced progress bar with true color and Unicode support
|
||||
* Requirements: 12.1, 12.2, 12.3
|
||||
*/
|
||||
|
||||
const React = require("react");
|
||||
const { Box, Text } = require("ink");
|
||||
const useModernTerminal = require("../../hooks/useModernTerminal.js");
|
||||
|
||||
/**
|
||||
* Modern progress bar with enhanced features
|
||||
*/
|
||||
const ModernProgressBar = ({
|
||||
progress = 0,
|
||||
total = 100,
|
||||
width = 40,
|
||||
label = "",
|
||||
showPercentage = true,
|
||||
showNumbers = false,
|
||||
color = "#00FF00",
|
||||
backgroundColor = "#333333",
|
||||
style = "blocks",
|
||||
animated = false,
|
||||
...props
|
||||
}) => {
|
||||
const { colors, unicode, utils, capabilities } = useModernTerminal();
|
||||
const [animationFrame, setAnimationFrame] = React.useState(0);
|
||||
|
||||
// Calculate progress percentage
|
||||
const percentage = Math.min(100, Math.max(0, (progress / total) * 100));
|
||||
const filled = Math.round((percentage / 100) * width);
|
||||
const empty = width - filled;
|
||||
|
||||
// Animation effect
|
||||
React.useEffect(() => {
|
||||
if (!animated || !capabilities.enhancedUnicode) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
setAnimationFrame((frame) => (frame + 1) % 8);
|
||||
}, 150);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [animated, capabilities.enhancedUnicode]);
|
||||
|
||||
// Generate progress bar content
|
||||
const generateProgressBar = () => {
|
||||
if (style === "blocks" && capabilities.enhancedUnicode) {
|
||||
// Use Unicode block characters
|
||||
const fullChar = unicode.getChar("progress", "full", "█");
|
||||
const emptyChar = unicode.getChar("progress", "empty", "░");
|
||||
|
||||
let progressContent = "";
|
||||
|
||||
if (capabilities.trueColor) {
|
||||
// Use true colors
|
||||
const fillColor = colors.getInkColor(color);
|
||||
const bgColor = colors.getInkColor(backgroundColor);
|
||||
|
||||
progressContent = (
|
||||
<>
|
||||
<Text color={fillColor}>{fullChar.repeat(filled)}</Text>
|
||||
<Text color={bgColor}>{emptyChar.repeat(empty)}</Text>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
// Fallback to standard colors
|
||||
progressContent = (
|
||||
<>
|
||||
<Text color="green">{fullChar.repeat(filled)}</Text>
|
||||
<Text color="gray">{emptyChar.repeat(empty)}</Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return progressContent;
|
||||
}
|
||||
|
||||
// ASCII fallback
|
||||
const fillChar = "#";
|
||||
const emptyChar = "-";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text color="green">{fillChar.repeat(filled)}</Text>
|
||||
<Text color="gray">{emptyChar.repeat(empty)}</Text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Generate animated spinner if enabled
|
||||
const generateSpinner = () => {
|
||||
if (!animated) return null;
|
||||
|
||||
const spinnerChar = utils.createSpinner(animationFrame);
|
||||
return (
|
||||
<Text color="cyan" marginRight={1}>
|
||||
{spinnerChar}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
// Generate percentage display
|
||||
const generatePercentage = () => {
|
||||
if (!showPercentage) return null;
|
||||
|
||||
const percentText = `${Math.round(percentage)}%`;
|
||||
return <Text marginLeft={1}>{percentText}</Text>;
|
||||
};
|
||||
|
||||
// Generate numbers display
|
||||
const generateNumbers = () => {
|
||||
if (!showNumbers) return null;
|
||||
|
||||
const numbersText = `${progress}/${total}`;
|
||||
return (
|
||||
<Text color="gray" marginLeft={1}>
|
||||
({numbersText})
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" {...props}>
|
||||
{label && <Text marginBottom={1}>{label}</Text>}
|
||||
|
||||
<Box flexDirection="row" alignItems="center">
|
||||
{generateSpinner()}
|
||||
|
||||
<Box flexDirection="row">{generateProgressBar()}</Box>
|
||||
|
||||
{generatePercentage()}
|
||||
{generateNumbers()}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Circular progress indicator using Unicode characters
|
||||
*/
|
||||
const ModernCircularProgress = ({
|
||||
progress = 0,
|
||||
total = 100,
|
||||
size = "medium",
|
||||
color = "#00FF00",
|
||||
showPercentage = true,
|
||||
...props
|
||||
}) => {
|
||||
const { colors, unicode, capabilities } = useModernTerminal();
|
||||
|
||||
const percentage = Math.min(100, Math.max(0, (progress / total) * 100));
|
||||
|
||||
// Size configurations
|
||||
const sizeConfig = {
|
||||
small: { radius: 1, chars: ["○", "◐", "◑", "◒", "●"] },
|
||||
medium: { radius: 2, chars: ["○", "◔", "◑", "◕", "●"] },
|
||||
large: { radius: 3, chars: ["○", "◔", "◑", "◕", "●"] },
|
||||
};
|
||||
|
||||
const config = sizeConfig[size] || sizeConfig.medium;
|
||||
const charIndex = Math.floor((percentage / 100) * (config.chars.length - 1));
|
||||
const progressChar = config.chars[charIndex];
|
||||
|
||||
const displayColor = capabilities.trueColor
|
||||
? colors.getInkColor(color)
|
||||
: "green";
|
||||
|
||||
return (
|
||||
<Box flexDirection="row" alignItems="center" {...props}>
|
||||
<Text color={displayColor} fontSize={size === "large" ? 2 : 1}>
|
||||
{progressChar}
|
||||
</Text>
|
||||
|
||||
{showPercentage && <Text marginLeft={1}>{Math.round(percentage)}%</Text>}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Multi-segment progress bar
|
||||
*/
|
||||
const ModernSegmentedProgress = ({
|
||||
segments = [],
|
||||
width = 40,
|
||||
showLabels = true,
|
||||
...props
|
||||
}) => {
|
||||
const { colors, unicode, capabilities } = useModernTerminal();
|
||||
|
||||
const total = segments.reduce((sum, segment) => sum + segment.value, 0);
|
||||
|
||||
const generateSegments = () => {
|
||||
let currentPosition = 0;
|
||||
|
||||
return segments.map((segment, index) => {
|
||||
const segmentWidth = Math.round((segment.value / total) * width);
|
||||
const char = capabilities.enhancedUnicode
|
||||
? unicode.getChar("progress", "full", "█")
|
||||
: "#";
|
||||
|
||||
const segmentColor = capabilities.trueColor
|
||||
? colors.getInkColor(segment.color || "#00FF00")
|
||||
: segment.color || "green";
|
||||
|
||||
currentPosition += segmentWidth;
|
||||
|
||||
return (
|
||||
<Text key={index} color={segmentColor}>
|
||||
{char.repeat(segmentWidth)}
|
||||
</Text>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const generateLabels = () => {
|
||||
if (!showLabels) return null;
|
||||
|
||||
return (
|
||||
<Box flexDirection="row" marginTop={1} gap={2}>
|
||||
{segments.map((segment, index) => (
|
||||
<Box key={index} flexDirection="row" alignItems="center">
|
||||
<Text
|
||||
color={
|
||||
capabilities.trueColor
|
||||
? colors.getInkColor(segment.color || "#00FF00")
|
||||
: segment.color || "green"
|
||||
}
|
||||
>
|
||||
■
|
||||
</Text>
|
||||
<Text marginLeft={1} color="gray">
|
||||
{segment.label} ({segment.value})
|
||||
</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" {...props}>
|
||||
<Box flexDirection="row">{generateSegments()}</Box>
|
||||
{generateLabels()}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
ModernProgressBar,
|
||||
ModernCircularProgress,
|
||||
ModernSegmentedProgress,
|
||||
};
|
||||
Reference in New Issue
Block a user