Functions/Public/Write-Panel.ps1

<#
================================================================================
ORION DESIGN - POWERSHELL UI FRAMEWORK | Write-Panel Function
================================================================================
Author: Sune Alexandersen Narud
Date: August 22, 2025
Module: OrionDesign v1.6.0
Category: Layout & Formatting
Dependencies: OrionDesign Theme System
 
FUNCTION PURPOSE:
Creates bordered content panels with titles and multiple styling options.
Versatile layout component providing organized content display with various
border styles and automatic content wrapping for information organization.
 
HLD INTEGRATION:
┌─ LAYOUT FORMAT ─┐ ┌─ PANEL STYLES ─┐ ┌─ OUTPUT ─┐
│ Write-Panel │◄──►│ Box/Left/Top │───►│ Bordered │
│ • Title/Content │ │ Card/Minimal │ │ Content │
│ • Border Styles │ │ Custom Widths │ │ Wrapped │
│ • Auto Wrap │ │ Icon Support │ │ Styled │
└─────────────────┘ └────────────────┘ └──────────┘
================================================================================
#>


<#
.SYNOPSIS
Creates styled information panels with borders and icons.
 
.DESCRIPTION
The Write-Panel function displays information in styled panels with various border styles, icons, and color themes.
 
.PARAMETER Content
The content to display in the panel (supports array of strings).
 
.PARAMETER Title
Optional title for the panel.
 
.PARAMETER Style
The visual style of the panel. Available styles:
• Box: Complete panel with full borders on all sides and corner decorations
• Left: Minimal panel with accent left border and clean, unobtrusive design
• Top: Panel with prominent top border accent and subtitle-style formatting
• Card: Modern card-style panel with subtle shadow effects and rounded appearance
• Minimal: Ultra-clean panel with minimal styling and maximum content focus
 
Valid values: Box, Left, Top, Card, Minimal
 
.PARAMETER Type
The type of panel for color theming. Valid values:
- 'Info' - Information (Cyan)
- 'Success' - Success (Green)
- 'Warning' - Warning (Yellow)
- 'Error' - Error (Red)
- 'Default' - Default theme
 
.PARAMETER Icon
Custom icon to display (uses type-based icons by default).
 
.PARAMETER Width
Width of the panel.
 
.PARAMETER Padding
Internal padding for content.
 
.EXAMPLE
Write-Panel -Content "This is an information message" -Type Info -Style Box
 
Displays an information panel with box styling.
 
.EXAMPLE
Write-Panel -Content @("Multiple lines", "of content", "in panel") -Title "Status Report" -Type Success -Style Card
 
Displays a success panel with multiple lines and a title.
#>

function Write-Panel {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param(
        [Parameter(Mandatory, ParameterSetName = 'Default', Position = 0)][array]$Content,
        [string]$Title = "",
        [ValidateSet('Box', 'Left', 'Top', 'Card', 'Minimal')] [string]$Style = 'Box',
        [ValidateSet('Info', 'Success', 'Warning', 'Error', 'Default')] [string]$Type = 'Info',
        [string]$Icon = "",
        [int]$Width = 0,
        [int]$Padding = 1,

        [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-Panel Demo' -ForegroundColor Cyan
        Write-Host ' ================' -ForegroundColor DarkGray
        Write-Host ''

        $types = @('Info', 'Success', 'Warning', 'Error')
        foreach ($type in $types) {
            Write-Host " [Type: $type | Style: Box]" -ForegroundColor Yellow
            Write-Host ''
            & $renderCodeBlock @("Write-Panel -Content 'Server SQL-01 status update.' -Type $type -Style Box")
            Write-Panel -Content 'Server SQL-01 status update.' -Type $type -Style Box
            Write-Host ''
        }

        Write-Host ' [Multi-line with Title | Style: Card]' -ForegroundColor Yellow
        Write-Host ''
        & $renderCodeBlock @(
            "Write-Panel -Content @('Deployment complete', '3 services restarted', 'Health check: OK') -Title 'Deploy Result' -Type Success -Style Card"
        )
        Write-Panel -Content @('Deployment complete', '3 services restarted', 'Health check: OK') -Title 'Deploy Result' -Type Success -Style Card

        return
    }

    # Default theme
    if (-not $script:Theme) {
        $script:Theme = @{
            Accent   = 'Cyan'
            Success  = 'Green'
            Warning  = 'Yellow'
            Error    = 'Red'
            Text     = 'White'
            Muted    = 'DarkGray'
            Divider  = '─'
            UseAnsi  = $true
        }
        if ($psISE) { $script:Theme.UseAnsi = $false }
    }

    # Set colors and icons based on type
    switch ($Type) {
        'Info' { 
            $color = $script:Theme.Accent
            if (-not $Icon) { $Icon = "ℹ" }
        }
        'Success' { 
            $color = $script:Theme.Success
            if (-not $Icon) { $Icon = "✓" }
        }
        'Warning' { 
            $color = $script:Theme.Warning
            if (-not $Icon) { $Icon = "⚠" }
        }
        'Error' { 
            $color = $script:Theme.Error
            if (-not $Icon) { $Icon = "✗" }
        }
        'Default' { 
            $color = $script:Theme.Text
            if (-not $Icon) { $Icon = "●" }
        }
    }

    # Convert content to array of strings
    $lines = @()
    foreach ($item in $Content) {
        $lines += $item.ToString()
    }

    # Calculate width if not specified
    if ($Width -eq 0) {
        $maxLength = 0
        if ($Title) { $maxLength = $Title.Length }
        foreach ($line in $lines) {
            if ($line.Length -gt $maxLength) { $maxLength = $line.Length }
        }
        $Width = $maxLength + ($Padding * 2) + 6  # Space for borders, icons, and spacing
        if ($Width -lt 30) { $Width = 30 }
        
        # Apply global max width if set
        if ($script:OrionMaxWidth -and $Width -gt $script:OrionMaxWidth) {
            $Width = $script:OrionMaxWidth
        }
    }

    Write-Host

    switch ($Style) {
        'Box' {
            # Top border
            Write-Host "┌" -ForegroundColor $color -NoNewline
            Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
            Write-Host "┐" -ForegroundColor $color

            # Title
            if ($Title) {
                $usedSpace = 4 + $Icon.Length + $Title.Length  # "│ " + icon + title + " │"
                $titlePadding = [Math]::Max(0, $Width - $usedSpace)
                $leftPad = [Math]::Floor($titlePadding / 2)
                $rightPad = $titlePadding - $leftPad

                Write-Host "│ " -ForegroundColor $color -NoNewline
                Write-Host $Icon -ForegroundColor $color -NoNewline
                Write-Host (" " * $leftPad) -NoNewline
                Write-Host $Title -ForegroundColor $color -NoNewline
                Write-Host (" " * $rightPad) -NoNewline
                Write-Host " │" -ForegroundColor $color

                # Separator
                Write-Host "├" -ForegroundColor $color -NoNewline
                Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
                Write-Host "┤" -ForegroundColor $color
            }

            # Content
            foreach ($line in $lines) {
                Write-Host "│" -ForegroundColor $color -NoNewline
                Write-Host (" " * $Padding) -NoNewline

                if (-not $Title) {
                    Write-Host $Icon -ForegroundColor $color -NoNewline
                    Write-Host " " -NoNewline
                }

                Write-Host $line -ForegroundColor $script:Theme.Text -NoNewline
                
                # Calculate exact remaining space to match border width
                $contentWidth = $Padding + $line.Length
                if (-not $Title) { $contentWidth += $Icon.Length + 1 }
                $remainingSpace = $Width - 2 - $contentWidth - $Padding  # Width - borders - content - right padding
                $remainingSpace = [Math]::Max(0, $remainingSpace)
                
                Write-Host (" " * $Padding) -NoNewline  # Right padding
                Write-Host (" " * $remainingSpace) -NoNewline  # Fill to border
                Write-Host "│" -ForegroundColor $color
            }

            # Bottom border
            Write-Host "└" -ForegroundColor $color -NoNewline
            Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
            Write-Host "┘" -ForegroundColor $color
        }

        'Left' {
            if ($Title) {
                Write-Host "▌ " -ForegroundColor $color -NoNewline
                Write-Host $Icon -ForegroundColor $color -NoNewline
                Write-Host " $Title" -ForegroundColor $color
                Write-Host "▌" -ForegroundColor $color
            }

            foreach ($line in $lines) {
                Write-Host "▌ " -ForegroundColor $color -NoNewline
                if (-not $Title) {
                    Write-Host $Icon -ForegroundColor $color -NoNewline
                    Write-Host " " -NoNewline
                }
                Write-Host $line -ForegroundColor $script:Theme.Text
            }
        }

        'Top' {
            # Top border
            Write-Host ("▀" * $Width) -ForegroundColor $color

            if ($Title) {
                Write-Host $Icon -ForegroundColor $color -NoNewline
                Write-Host " $Title" -ForegroundColor $color
                Write-Host
            }

            foreach ($line in $lines) {
                if (-not $Title) {
                    Write-Host $Icon -ForegroundColor $color -NoNewline
                    Write-Host " " -NoNewline
                }
                Write-Host $line -ForegroundColor $script:Theme.Text
            }
        }

        'Card' {
            # Shadow effect
            Write-Host (" " * 2) -NoNewline
            Write-Host ("▄" * ($Width - 1)) -ForegroundColor $script:Theme.Muted

            # Top border
            Write-Host "┌" -ForegroundColor $color -NoNewline
            Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
            Write-Host "┐" -ForegroundColor $color -NoNewline
            Write-Host "▌" -ForegroundColor $script:Theme.Muted

            # Title
            if ($Title) {
                $usedSpace = 4 + $Icon.Length + $Title.Length  # "│ " + icon + " " + title + "│"
                $remaining = [Math]::Max(0, $Width - $usedSpace)
                
                Write-Host "│ " -ForegroundColor $color -NoNewline
                Write-Host $Icon -ForegroundColor $color -NoNewline
                Write-Host " $Title" -ForegroundColor $color -NoNewline
                Write-Host (" " * $remaining) -NoNewline
                Write-Host "│" -ForegroundColor $color -NoNewline
                Write-Host "▌" -ForegroundColor $script:Theme.Muted

                # Separator
                Write-Host "├" -ForegroundColor $color -NoNewline
                Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
                Write-Host "┤" -ForegroundColor $color -NoNewline
                Write-Host "▌" -ForegroundColor $script:Theme.Muted
            }

            # Content
            foreach ($line in $lines) {
                $iconSpace = if (-not $Title) { $Icon.Length + 1 } else { 0 }
                $usedSpace = 2 + 1 + $line.Length + $iconSpace  # "│" + " " + content + icon + "│"
                $remaining = [Math]::Max(0, $Width - $usedSpace)
                
                Write-Host "│" -ForegroundColor $color -NoNewline
                Write-Host " " -NoNewline

                if (-not $Title) {
                    Write-Host $Icon -ForegroundColor $color -NoNewline
                    Write-Host " " -NoNewline
                }

                Write-Host $line -ForegroundColor $script:Theme.Text -NoNewline
                Write-Host (" " * $remaining) -NoNewline
                Write-Host "│" -ForegroundColor $color -NoNewline
                Write-Host "▌" -ForegroundColor $script:Theme.Muted
            }

            # Bottom border
            Write-Host "└" -ForegroundColor $color -NoNewline
            Write-Host ("─" * ($Width - 2)) -ForegroundColor $color -NoNewline
            Write-Host "┘" -ForegroundColor $color -NoNewline
            Write-Host "▌" -ForegroundColor $script:Theme.Muted

            # Shadow bottom
            Write-Host (" " * 2) -NoNewline
            Write-Host ("▀" * ($Width - 1)) -ForegroundColor $script:Theme.Muted
        }

        'Minimal' {
            if ($Title) {
                Write-Host $Icon -ForegroundColor $color -NoNewline
                Write-Host " $Title" -ForegroundColor $color
            }

            foreach ($line in $lines) {
                Write-Host " " -NoNewline
                if (-not $Title) {
                    Write-Host $Icon -ForegroundColor $color -NoNewline
                    Write-Host " " -NoNewline
                }
                Write-Host $line -ForegroundColor $script:Theme.Text
            }
        }
    }

    Write-Host
}