Private/Show-TitleSlide.ps1
|
function Show-TitleSlide { <# .SYNOPSIS Renders a title slide with large figlet text. .DESCRIPTION Displays a full-screen title slide containing a # heading rendered as large figlet text. Title slides are the opening slides of a presentation, designed to make a strong visual impact with large, centered text. The rendering process: 1. Extracts # heading text from slide content 2. Detects inline color tags for color override 3. Loads font file from h1 setting (default: Spectre's built-in font) 4. Creates centered figlet text with specified color 5. Calculates padding to vertically center content 6. Renders in bordered panel filling terminal height Title slides use the h1 font setting (also accepts aliases: titleFont, h1Font). Font files must be in .flf (FIGlet) format and located in the Fonts directory. Title slides should contain ONLY a # heading with no other content. Additional content will not be displayed. .PARAMETER Slide The slide object containing a # heading. Must match pattern: ^#\s+(.+)$ .PARAMETER Settings The presentation settings hashtable containing: - foreground: Default text color - background: Slide background color - border: Border color - borderStyle: Border style - h1: Font name for # headings (default: built-in Spectre font) - h1Color: Optional color override for # headings .PARAMETER IsFirstSlide Switch indicating this is the first slide in the presentation. Reserved for potential future features (e.g., logo display). .PARAMETER CurrentSlide The current slide number for pagination display. .PARAMETER TotalSlides The total number of slides in the presentation for pagination. .EXAMPLE Show-TitleSlide -Slide $slideObject -Settings $settings Renders a title slide with large centered figlet text. .EXAMPLE $slide = [PSCustomObject]@{ Number = 1 Content = '# Welcome to Deck' } $settings = @{ h1 = 'default'; foreground = 'Cyan1'; border = 'Blue' } Show-TitleSlide -Slide $slide -Settings $settings -IsFirstSlide Renders the first slide of a presentation with default font and cyan text. .EXAMPLE $slide = [PSCustomObject]@{ Number = 1 Content = '# <magenta>PowerShell Rocks!</magenta>' } Show-TitleSlide -Slide $slide -Settings $settings Renders a title slide with inline color override (magenta text). .EXAMPLE $settings = @{ h1 = 'small'; h1Color = 'Yellow'; border = 'Green' } Show-TitleSlide -Slide $slide -Settings $settings Renders a title slide using the 'small' font file and yellow color from settings. .OUTPUTS None. Renders directly to the terminal console using PwshSpectreConsole. .NOTES Font Configuration: - h1 setting specifies font name without .flf extension - Fonts loaded from ../Fonts/ directory relative to script - 'default' uses Spectre.Console's built-in font - Custom fonts must be valid FIGlet (.flf) format Font Aliases: - h1, titleFont, h1Font all map to the same setting - Normalized by ConvertFrom-DeckMarkdown during parsing Color Priority: - Inline tags: <color>text</color> or <span style="color:name">text</span> - h1Color setting in frontmatter - foreground setting as fallback Content Rules: - MUST contain exactly one # heading - NO additional content after heading - Use ## for section slides instead - Use ### for content slides with headers Visual Design: - Content vertically centered in panel - Figlet text horizontally centered - Panel fills entire terminal height - Border color from settings #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSCustomObject]$Slide, [Parameter(Mandatory = $true)] [hashtable]$Settings, [Parameter()] [switch]$IsFirstSlide, [Parameter(Mandatory = $false)] [int]$CurrentSlide = 1, [Parameter(Mandatory = $false)] [int]$TotalSlides = 1 ) process { try { # Extract the # heading text if ($Slide.Content -match '^#\s+(.+)$') { $titleText = $Matches[1].Trim() Write-Verbose " Title: $titleText" } else { throw "Title slide does not contain a valid # heading" } # Check for color tags in heading text and extract color $headingColor = $null if ($titleText -match '<(\w+)>.*?</\1>') { $headingColor = $Matches[1] Write-Verbose " Extracted color from tag: $headingColor" } elseif ($titleText -match "<span\s+style=['""]color:(\w+)['""]>.*?</span>") { $headingColor = $Matches[1] Write-Verbose " Extracted color from span: $headingColor" } # Strip HTML tags from title text $titleText = $titleText -replace "<span\s+style=['""]color:\w+['""]>(.*?)</span>", '$1' $titleText = $titleText -replace '<(\w+)>(.*?)</\1>', '$2' # Get colors and styles from settings $colorName = if ($headingColor) { $headingColor } elseif ($Settings.h1Color) { $Settings.h1Color } else { $Settings.foreground } $figletColor = Get-SpectreColorFromSettings -ColorName $colorName -SettingName 'Figlet' $borderInfo = Get-BorderStyleFromSettings -Settings $Settings # Create figlet text object with optional font from settings $figletParams = @{ Text = $titleText Color = $figletColor Justification = 'Center' } if ($Settings.h1 -and $Settings.h1 -ne 'default') { $fontPath = if (Test-Path $Settings.h1) { $Settings.h1 } else { Join-Path $PSScriptRoot "../Fonts/$($Settings.h1).flf" } Write-Verbose " h1 font setting: $($Settings.h1)" Write-Verbose " Constructed font path: $fontPath" Write-Verbose " Font file exists: $(Test-Path $fontPath)" if (Test-Path $fontPath) { $figletParams['FontPath'] = $fontPath Write-Verbose " Using h1 font: $($Settings.h1)" } else { Write-Warning "Font file not found: $fontPath" } } $figlet = New-FigletText @figletParams # Create panel with internal padding calculated to fill terminal height # Account for rendering behavior to prevent scrolling $dimensions = Get-TerminalDimensions $windowHeight = $dimensions.Height $windowWidth = $dimensions.Width # Set panel to expand and measure what we need to fill $panel = [Spectre.Console.Panel]::new($figlet) $panel.Expand = $true # Add border style first if ($borderInfo.Style) { $panel.Border = [Spectre.Console.BoxBorder]::$($borderInfo.Style) } # Measure figlet with horizontal padding already applied # Horizontal padding is 4 on each side = 8 total $contentWidth = $windowWidth - 8 $figletSize = Get-SpectreRenderableSize -Renderable $figlet -ContainerWidth $contentWidth $actualFigletHeight = $figletSize.Height # Calculate vertical padding needed # Total height = border (2) + top padding + content + bottom padding $borderHeight = 2 $remainingSpace = $windowHeight - $actualFigletHeight - $borderHeight $topPadding = [math]::Max(0, [math]::Ceiling($remainingSpace / 2.0)) $bottomPadding = [math]::Max(0, $remainingSpace - $topPadding) $panel.Padding = [Spectre.Console.Padding]::new(4, $topPadding, 4, $bottomPadding) # Border style already added above if ($borderInfo.Style) { $panel.Border = [Spectre.Console.BoxBorder]::$($borderInfo.Style) } # Add border color if ($borderInfo.Color) { $panel.BorderStyle = [Spectre.Console.Style]::new($borderInfo.Color) } # Add help text header for first slide, otherwise pagination if ($IsFirstSlide) { $panel.Header = [Spectre.Console.PanelHeader]::new("[grey39]press ? for help[/]") } elseif ($Settings.pagination -eq $true) { $paginationParams = @{ CurrentSlide = $CurrentSlide TotalSlides = $TotalSlides Style = $Settings.paginationStyle } if ($borderInfo.Color) { $paginationParams['Color'] = $borderInfo.Color } $paginationText = Get-PaginationText @paginationParams $panel.Header = [Spectre.Console.PanelHeader]::new($paginationText) $panel.Header.Justification = [Spectre.Console.Justify]::Right } # Render panel Out-SpectreHost $panel } catch { $errorRecord = [System.Management.Automation.ErrorRecord]::new( $_.Exception, 'TitleSlideRenderFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $Slide ) $PSCmdlet.ThrowTerminatingError($errorRecord) } } end { Write-Verbose "Title slide rendered" } } |