private/Menu.ps1
|
# FR-018: interactive checklist menu. Supports two equivalent ways to select an item - # a direct shortcut keypress (case-insensitive) or Up/Down arrow navigation + Enter. Renders # the banner (FR-022) above the list on every screen, not only once. function Show-OctaMenu { <# $Items: array of @{ Key = '1'; Label = 'Telemetry'; Description = '...' } Returns the Key of the chosen item. #> [CmdletBinding()] param( [Parameter(Mandatory)][object[]]$Items, [Parameter(Mandatory)][string]$Header, [string]$NavHint = 'Up/Down to navigate - Enter to select - or press the number/letter directly' ) $selectedIndex = 0 while ($true) { Clear-Host Show-OctaBanner Write-Host $Header Write-Host '' for ($i = 0; $i -lt $Items.Count; $i++) { $item = $Items[$i] $pointer = if ($i -eq $selectedIndex) { '>' } else { ' ' } Write-Host ("{0} {1} {2,-22}{3}" -f $pointer, $item.Key.ToString().ToUpperInvariant(), $item.Label, $item.Description) } Write-Host '' Write-Host $NavHint $key = [Console]::ReadKey($true) switch ($key.Key) { 'UpArrow' { $selectedIndex = ($selectedIndex - 1 + $Items.Count) % $Items.Count } 'DownArrow' { $selectedIndex = ($selectedIndex + 1) % $Items.Count } 'Enter' { return $Items[$selectedIndex].Key } default { $typed = $key.KeyChar.ToString().ToLowerInvariant() $match = $Items | Where-Object { $_.Key.ToString().ToLowerInvariant() -eq $typed } if ($match) { return $match[0].Key } } } } } |