Files
PriceUpdaterAppv2/src/tui/components/common/ModernProgressBar.jsx

254 lines
6.0 KiB
JavaScript

/**
* 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,
};