/** * 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 = ( <> {fullChar.repeat(filled)} {emptyChar.repeat(empty)} ); } else { // Fallback to standard colors progressContent = ( <> {fullChar.repeat(filled)} {emptyChar.repeat(empty)} ); } return progressContent; } // ASCII fallback const fillChar = "#"; const emptyChar = "-"; return ( <> {fillChar.repeat(filled)} {emptyChar.repeat(empty)} ); }; // Generate animated spinner if enabled const generateSpinner = () => { if (!animated) return null; const spinnerChar = utils.createSpinner(animationFrame); return ( {spinnerChar} ); }; // Generate percentage display const generatePercentage = () => { if (!showPercentage) return null; const percentText = `${Math.round(percentage)}%`; return {percentText}; }; // Generate numbers display const generateNumbers = () => { if (!showNumbers) return null; const numbersText = `${progress}/${total}`; return ( ({numbersText}) ); }; return ( {label && {label}} {generateSpinner()} {generateProgressBar()} {generatePercentage()} {generateNumbers()} ); }; /** * 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 ( {progressChar} {showPercentage && {Math.round(percentage)}%} ); }; /** * 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 ( {char.repeat(segmentWidth)} ); }); }; const generateLabels = () => { if (!showLabels) return null; return ( {segments.map((segment, index) => ( {segment.label} ({segment.value}) ))} ); }; return ( {generateSegments()} {generateLabels()} ); }; module.exports = { ModernProgressBar, ModernCircularProgress, ModernSegmentedProgress, };