src/UI/03-Goto.ps1
|
# 03-Goto.ps1 — the g goto layer (design-system-v2 §4): pressing g anywhere # re-renders the current view with a small accent-bordered panel appended; # the next key jumps to a named screen. Identical on every screen, so the # per-screen switch letters are freed for verbs. # chord → destination registry. Tests assert completeness. function script:Get-PSMMGotoTable { [ordered]@{ 'h' = @{ Target = 'home'; Label = 'home' } 'g' = @{ Target = 'gallery'; Label = 'gallery' } 'f' = @{ Target = 'files'; Label = 'files' } 'p' = @{ Target = 'paths'; Label = 'paths' } 't' = @{ Target = 'tasks'; Label = 'tasks' } 'c' = @{ Target = 'conflicts'; Label = 'conflicts' } 'x' = @{ Target = 'cleanup'; Label = 'cleanup' } 'm' = @{ Target = 'unmanaged'; Label = 'unmanaged' } '?' = @{ Target = 'help'; Label = 'keys' } } } # The overlay panel: title, three-column chord grid, footer. function script:Build-PSMMGotoPanel { $table = Get-PSMMGotoTable $cells = @(foreach ($k in $table.Keys) { "[$script:PSMM_ColKey on $script:PSMM_ColCapsuleDim] $k [/] [$script:PSMM_ColMute]$($table[$k].Label)[/]" }) $g = [Spectre.Console.Grid]::new() for ($c = 0; $c -lt 3; $c++) { $col = [Spectre.Console.GridColumn]::new() $col.Padding = [Spectre.Console.Padding]::new(0, 0, 4, 0) [void]$g.AddColumn($col) } for ($r = 0; $r -lt 3; $r++) { [void][Spectre.Console.GridExtensions]::AddRow($g, [string[]]@($cells[(3 * $r)..(3 * $r + 2)])) } $items = [System.Collections.Generic.List[Spectre.Console.Rendering.IRenderable]]::new() $items.Add([Spectre.Console.Markup]::new( "[$script:PSMM_ColAccent on $script:PSMM_ColCapsule] g [/] [default]goto[/] [$script:PSMM_ColDim]$([char]0x2014) next key jumps, from anywhere[/]")) $items.Add($g) $items.Add([Spectre.Console.Markup]::new( "[$script:PSMM_ColDim]esc cancels $([char]0x00B7) anything else is swallowed[/]")) $panel = [Spectre.Console.Panel]::new([Spectre.Console.Rows]::new($items)) $panel.Border = [Spectre.Console.BoxBorder]::Rounded $panel.BorderStyle = [Spectre.Console.Style]::Parse($script:PSMM_ColAccent) $panel } # Show the overlay under the current view and read the second key. # Returns the destination string, or $null (esc / unknown key swallowed / # hard quit). $Context: a LiveDisplayContext when called from a live loop; # without one the frame is written directly (non-live screens). function script:Read-PSMMGotoKey { param( $BaseRenderable, $Context ) $items = [System.Collections.Generic.List[Spectre.Console.Rendering.IRenderable]]::new() if ($BaseRenderable) { $items.Add($BaseRenderable) } $items.Add((Build-PSMMGotoPanel)) $frame = [Spectre.Console.Rows]::new($items) if ($Context) { $Context.UpdateTarget($frame); $Context.Refresh() } else { Clear-PSMMScreen; Write-PSMMRenderable $frame } $k2 = [Console]::ReadKey($true) if (Test-PSMMHardQuitKey $k2) { $script:PSMM_UI.HardQuit = $true; return $null } if ($k2.Key -eq [ConsoleKey]::Escape) { return $null } $table = Get-PSMMGotoTable $key = "$($k2.KeyChar)".ToLowerInvariant() if ($key -and $table.Contains($key)) { return $table[$key].Target } $null # anything else is swallowed } |