Functions/Public/Write-MenuLine.ps1
|
<#
================================================================================ ORION DESIGN - POWERSHELL UI FRAMEWORK | Write-MenuLine Function ================================================================================ Author: Sune Alexandersen Narud Date: February 5, 2026 Module: OrionDesign v3.0.0 Category: Interactive Display Dependencies: OrionDesign Theme System, Global Width Configuration FUNCTION PURPOSE: Writes a single menu line with optional right-aligned suffix information. Designed for building custom menus with consistent styling and alignment. Respects OrionMaxWidth and theme colors like Write-Action/Write-ActionResult. USE CASES: • Building custom interactive menus with count indicators • Displaying numbered lists with statistics • Creating navigation menus showing item counts • Building dashboards with menu-style navigation LAYOUT STRUCTURE: ┌────────────────────────────────────────────────────────────────────────────┐ │ [Indent] [Number]. [Title] [SuffixNumber] [Suffix] │ │ ↑ ↑ ↑ ↑ ↑ │ │ Margin Accent Text Accent Text │ │ (1 sp) Color Color Color Color │ └────────────────────────────────────────────────────────────────────────────┘ HLD INTEGRATION: ┌─ MENU LINE ─────────┐ ┌─ LINE DISPLAY ──┐ ┌─ OUTPUT ─┐ │ Write-MenuLine │◄──►│ Left: Number+ │───►│ Single │ │ • MenuNumber │ │ Text │ │ Styled │ │ • Text │ │ Right: Suffix+ │ │ Menu │ │ • SuffixNumber │ │ Number │ │ Line │ │ • Suffix │ │ Width-aware │ │ │ └─────────────────────┘ └─────────────────┘ └──────────┘ THEME INTEGRATION: • MenuNumber uses theme 'Accent' color (Cyan in Default theme) • Period "." uses theme 'Muted' color for subtle separation • Text uses theme 'Text' color (White in Default theme) • SuffixNumber uses theme 'Accent' color (matches MenuNumber) • Suffix uses theme 'Text' color (matches Text) • All colors can be overridden via parameters WIDTH & ALIGNMENT: • Respects OrionMaxWidth global setting (default: 100) • Left margin controlled by -Indent parameter (default: 1) • Right margin equals left margin for symmetry • Suffix is right-aligned like Write-ActionResult ================================================================================ #> <# .SYNOPSIS Writes a single styled menu line with optional right-aligned suffix. .DESCRIPTION The Write-MenuLine function outputs a single menu line with a number and title on the left, and an optional suffix with number on the right (right-aligned). If SuffixNumber is 0 or empty, only the MenuNumber and Text are displayed. This function is designed for building custom menus where you need more control than Write-Menu provides. It respects OrionMaxWidth for alignment and uses theme colors for consistent styling across your application. OUTPUT FORMAT: When SuffixNumber is provided and non-zero: [Indent][Number]. [Text] [SuffixNumber] [Suffix] When SuffixNumber is 0 or empty: [Indent][Number]. [Text] THEME COLORS USED: - MenuNumber: Accent color (cyan by default) - Period (.): Muted color (dark gray) - Text: Text color (white by default) - SuffixNumber: Accent color (matches MenuNumber) - Suffix: Text color (matches Text) ALIGNMENT: - Left margin: Controlled by -Indent (default 1 space) - Right margin: Same as left margin for symmetry - Suffix: Right-aligned to (OrionMaxWidth - RightMargin) .PARAMETER MenuNumber The menu option number or identifier displayed on the left side. Can be a number (1, 2, 3) or text (A, B, X). Displayed in the theme's Accent color. .PARAMETER Text The menu option text or description displayed after the number. This is the main text the user sees for the menu option. Displayed in the theme's Text color. .PARAMETER SuffixNumber Optional count or number to display on the right side. If this is 0, empty, or not provided, no suffix is displayed. Useful for showing item counts, statistics, or status numbers. Displayed in the theme's Accent color (matches MenuNumber). .PARAMETER Suffix Optional text label displayed after SuffixNumber on the right. Typically a unit or description like "users", "items", "pending". Only displayed if SuffixNumber is provided and non-zero. Displayed in the theme's Text color (matches Text). .PARAMETER Indent Number of spaces for left margin (and right margin for symmetry). Defaults to 1, matching Write-Action's default behavior. Set to 0 for no indentation. .PARAMETER Muted Switch to display the entire menu line in the theme's Muted color. Useful for indicating disabled, unavailable, or inactive menu options. When enabled, overrides all color settings (MenuNumberColor, TextColor, SuffixColor). .PARAMETER MenuNumberColor Override color for the MenuNumber. Accepts any valid PowerShell console color. Defaults to theme Accent color if not specified. .PARAMETER TextColor Override color for the Text. Accepts any valid PowerShell console color. Defaults to theme Text color if not specified. .PARAMETER SuffixColor Override color for both SuffixNumber and Suffix text. Accepts any valid PowerShell console color. Defaults to Accent for SuffixNumber and Text for Suffix if not specified. .INPUTS None. You cannot pipe objects to Write-MenuLine. .OUTPUTS None. Write-MenuLine writes directly to the host console. .EXAMPLE Write-MenuLine -MenuNumber 1 -Text "View Users" Outputs a simple menu line without suffix: 1. View Users .EXAMPLE Write-MenuLine -MenuNumber 1 -Text "View Users" -SuffixNumber 142 -Suffix "users" Outputs a menu line with right-aligned count: 1. View Users 142 users .EXAMPLE Write-MenuLine -MenuNumber 2 -Text "Pending Approvals" -SuffixNumber 5 -Suffix "pending" Outputs: 2. Pending Approvals 5 pending .EXAMPLE Write-MenuLine -MenuNumber 3 -Text "Archived Items" -SuffixNumber 0 When SuffixNumber is 0, no suffix is displayed: 3. Archived Items .EXAMPLE Write-MenuLine -MenuNumber "X" -Text "Exit" -TextColor "DarkGray" Using a letter instead of number, with custom color: X. Exit .EXAMPLE # Building a custom menu with counts $menuItems = @( @{ Num = 1; Title = "Active Users"; Count = 142 }, @{ Num = 2; Title = "Pending Requests"; Count = 5 }, @{ Num = 3; Title = "Completed Tasks"; Count = 89 } ) Write-Separator -Text "User Management" -Style Double foreach ($item in $menuItems) { Write-MenuLine -MenuNumber $item.Num -Text $item.Title -SuffixNumber $item.Count } Write-MenuLine -MenuNumber "X" -Text "Exit" -TextColor DarkGray Outputs: ═══ User Management ═══════════════════════════════════════════════════════════════ 1. Active Users 142 2. Pending Requests 5 3. Completed Tasks 89 X. Exit .EXAMPLE # Using with different themes Set-OrionTheme -Preset Matrix Write-MenuLine -MenuNumber 1 -Text "Decrypt Files" -SuffixNumber 50 -Suffix "files" With Matrix theme, colors change to green/dark green aesthetic. .EXAMPLE # Custom indentation Write-MenuLine -MenuNumber 1 -Text "Main Option" -Indent 0 Write-MenuLine -MenuNumber "1a" -Text "Sub Option" -Indent 4 Write-MenuLine -MenuNumber "1b" -Text "Sub Option" -Indent 4 Creates hierarchical menu structure: 1. Main Option 1a. Sub Option 1b. Sub Option .EXAMPLE # Using -Muted for disabled/unavailable options Write-MenuLine -MenuNumber 1 -Text "Available Option" -SuffixNumber 10 -Suffix "items" Write-MenuLine -MenuNumber 2 -Text "Disabled Option" -SuffixNumber 0 -Muted Write-MenuLine -MenuNumber 3 -Text "Another Available" -SuffixNumber 5 -Suffix "items" The muted line appears in dark gray, indicating it's unavailable: 1. Available Option 10 items 2. Disabled Option 3. Another Available 5 items .NOTES DESIGN PHILOSOPHY: This function is designed for building custom menus with consistent OrionDesign styling. Use it in loops or custom menu builders where the interactive Write-Menu function doesn't fit your use case. COMPARISON WITH WRITE-MENU: - Write-Menu: Full interactive menu with keyboard navigation and selection - Write-MenuLine: Single line output for building custom non-interactive menus ALIGNMENT SYSTEM: Uses the same margin system as Write-Action/Write-ActionResult: - Left margin controlled by -Indent (default 1) - Right margin equals left margin for symmetry - Suffix right-aligned to (OrionMaxWidth - RightMargin) THEME CONSISTENCY: All colors are pulled from the current theme: - Accent: MenuNumber and SuffixNumber (eye-catching for numbers) - Muted: Period separator (subtle, non-distracting) - Text: Text and Suffix (primary readable content) See Get-OrionTheme and Set-OrionTheme for theme customization. .LINK Write-Menu .LINK Write-Action .LINK Write-ActionResult .LINK Set-OrionTheme #> function Write-MenuLine { [CmdletBinding(DefaultParameterSetName = 'Default')] param( [Parameter(Mandatory, ParameterSetName = 'Default', Position = 0)][string]$MenuNumber, [Parameter(Mandatory, ParameterSetName = 'Default', Position = 1)][string]$Text, [string]$SuffixNumber = "", [string]$Suffix = "", [int]$Indent = 1, [switch]$Muted, [string]$MenuNumberColor = "", [string]$TextColor = "", [string]$SuffixColor = "", [Parameter(Mandatory, ParameterSetName = 'Demo')] [switch]$Demo ) if ($Demo) { $renderCodeBlock = { param([string[]]$Lines) $innerWidth = ($Lines | Measure-Object -Property Length -Maximum).Maximum + 4 $bar = '─' * $innerWidth Write-Host ' # Code' -ForegroundColor DarkGray Write-Host " ┌$bar┐" -ForegroundColor DarkGray foreach ($line in $Lines) { $padded = (" $line").PadRight($innerWidth) Write-Host " │" -ForegroundColor DarkGray -NoNewline Write-Host $padded -ForegroundColor Green -NoNewline Write-Host '│' -ForegroundColor DarkGray } Write-Host " └$bar┘" -ForegroundColor DarkGray Write-Host '' } Write-Host '' Write-Host ' Write-MenuLine Demo' -ForegroundColor Cyan Write-Host ' ===================' -ForegroundColor DarkGray Write-Host '' Write-Host ' [With right-aligned suffix]' -ForegroundColor Yellow Write-Host '' & $renderCodeBlock @("Write-MenuLine -MenuNumber '1' -Text 'Active Deployments' -SuffixNumber '12' -Suffix 'running'") Write-MenuLine -MenuNumber '1' -Text 'Active Deployments' -SuffixNumber '12' -Suffix 'running' & $renderCodeBlock @("Write-MenuLine -MenuNumber '2' -Text 'Pending Approvals' -SuffixNumber '3' -Suffix 'waiting'") Write-MenuLine -MenuNumber '2' -Text 'Pending Approvals' -SuffixNumber '3' -Suffix 'waiting' Write-Host '' Write-Host ' [Without suffix]' -ForegroundColor Yellow Write-Host '' & $renderCodeBlock @("Write-MenuLine -MenuNumber '3' -Text 'Settings'") Write-MenuLine -MenuNumber '3' -Text 'Settings' Write-Host '' Write-Host ' [Muted style]' -ForegroundColor Yellow Write-Host '' & $renderCodeBlock @("Write-MenuLine -MenuNumber 'X' -Text 'Exit' -Muted") Write-MenuLine -MenuNumber 'X' -Text 'Exit' -Muted Write-Host '' return } # Initialize theme if not set if (-not $script:Theme) { $script:Theme = @{ Accent = 'Cyan' Success = 'Green' Warning = 'Yellow' Error = 'Red' Text = 'White' Muted = 'DarkGray' Action = 'White' Result = 'Cyan' UseAnsi = $true } if ($psISE) { $script:Theme.UseAnsi = $false } } # Use global max width if not set if (-not $script:OrionMaxWidth) { $script:OrionMaxWidth = 100 } # Determine colors from theme or parameters # If -Muted is enabled, override all colors with Muted if ($Muted) { $numColor = $script:Theme.Muted $textColor = $script:Theme.Muted $suffixNumColor = $script:Theme.Muted $suffixTxtColor = $script:Theme.Muted } else { $numColor = if ($MenuNumberColor) { $MenuNumberColor } else { $script:Theme.Accent } $textColor = if ($TextColor) { $TextColor } else { $script:Theme.Text } # SuffixNumber shares color with MenuNumber (Accent) # Suffix shares color with Text $suffixNumColor = if ($SuffixColor) { $SuffixColor } else { $script:Theme.Accent } $suffixTxtColor = if ($SuffixColor) { $SuffixColor } else { $script:Theme.Text } } # Build indentation string $indentString = if ($Indent -gt 0) { ' ' * $Indent } else { '' } # Build left side: " 1. Menu Text" $leftText = "$MenuNumber. $Text" $leftLength = $indentString.Length + $leftText.Length # Calculate effective width (respecting margins like Write-ActionResult) $rightMargin = $Indent $effectiveWidth = $script:OrionMaxWidth - $rightMargin # Check if we have suffix to display $hasSuffix = $false if ($SuffixNumber -and $SuffixNumber -ne "0" -and $SuffixNumber -ne "") { $hasSuffix = $true } # Output the line Write-Host $indentString -NoNewline Write-Host "$MenuNumber. " -ForegroundColor $numColor -NoNewline Write-Host $Text -ForegroundColor $textColor -NoNewline if ($hasSuffix) { # Build suffix text for length calculation $suffixText = if ($Suffix) { "$SuffixNumber $Suffix" } else { "$SuffixNumber" } # Calculate padding for right-alignment $padding = $effectiveWidth - $leftLength - $suffixText.Length if ($padding -gt 0) { Write-Host (" " * $padding) -NoNewline } # Output SuffixNumber in Accent color (or Muted), Suffix in Text color (or Muted) Write-Host $SuffixNumber -ForegroundColor $suffixNumColor -NoNewline if ($Suffix) { Write-Host " $Suffix" -ForegroundColor $suffixTxtColor } else { Write-Host } } else { # No suffix, just end the line Write-Host } } |