Private/RenderPanel.ps1
|
function Render-InTUIPanel { <# .SYNOPSIS Renders content inside a Unicode box with gradient top/bottom borders. Replaces Format-SpectrePanel. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Content, [Parameter()] [string]$Title = '', [Parameter()] [string]$BorderColor = 'Blue' ) $palette = Get-InTUIColorPalette $reset = $palette.Reset $innerWidth = Get-InTUIConsoleInnerWidth # Map border color name to palette $borderAnsi = switch ($BorderColor.ToLower()) { 'blue' { $palette.Blue } 'green' { $palette.Green } 'red' { $palette.Red } 'yellow' { $palette.Yellow } 'cyan' { $palette.Cyan } 'cyan1' { $palette.Cyan } 'grey' { $palette.Grey } 'mauve' { $palette.Mauve } default { $palette.Blue } } # Box characters $topLeft = [char]0x256D $topRight = [char]0x256E $bottomLeft = [char]0x2570 $bottomRight = [char]0x256F $horizontal = [char]0x2500 $vertical = [char]0x2502 # Match accordion box layout: 2-space indent + border + innerWidth + border = WindowWidth $boxWidth = $innerWidth + 2 $contentWidth = $boxWidth - 4 # 2 border + 2 padding $indent = ' ' # Top border with optional title if ($Title) { $plainTitle = Strip-InTUIMarkup -Text $Title $ansiTitle = ConvertFrom-InTUIMarkup -Text $Title $titleDisplayWidth = Measure-InTUIDisplayWidth -Text $plainTitle $lineLen = $boxWidth - 4 - $titleDisplayWidth $leftLine = [Math]::Max(1, [int]([Math]::Floor($lineLen / 2))) $rightLine = [Math]::Max(1, $lineLen - $leftLine) Write-Host "$indent$borderAnsi$topLeft$([string]::new($horizontal, $leftLine))$reset $ansiTitle $borderAnsi$([string]::new($horizontal, $rightLine))$topRight$reset" } else { Write-Host "$indent$borderAnsi$topLeft$([string]::new($horizontal, ($boxWidth - 2)))$topRight$reset" } # Content lines $lines = $Content -split "`n" foreach ($line in $lines) { $line = $line.TrimEnd("`r") $plainLine = Strip-InTUIMarkup -Text $line $ansiLine = ConvertFrom-InTUIMarkup -Text $line $displayWidth = Measure-InTUIDisplayWidth -Text $plainLine # Truncate based on visual display width if ($displayWidth -gt $contentWidth) { # Walk the plain text to find the cut point at the right visual column $cutLen = 0 $cutWidth = 0 for ($ci = 0; $ci -lt $plainLine.Length; $ci++) { $charWidth = Measure-InTUIDisplayWidth -Text ([string]$plainLine[$ci]) if (($cutWidth + $charWidth) -gt ($contentWidth - 3)) { break } $cutWidth += $charWidth $cutLen++ } $plainLine = $plainLine.Substring(0, $cutLen) + '...' $ansiLine = $plainLine $displayWidth = $cutWidth + 3 } $padRight = [Math]::Max(0, $contentWidth - $displayWidth) Write-Host "$indent$borderAnsi$vertical$reset $ansiLine$reset$(' ' * $padRight) $borderAnsi$vertical$reset" } # Bottom border Write-Host "$indent$borderAnsi$bottomLeft$([string]::new($horizontal, ($boxWidth - 2)))$bottomRight$reset" } |