layout.ps1

<#
.SYNOPSIS
    `layout.ps1`
.DESCRIPTION
    `layout.ps1` lays out a page.

    This is a simple and helpful scripting convention for web development.

    Just pipe to `./layout.ps1`

    A layout gives pages in a site a consistent way to render content

    `./layout.ps1` can layout content any way we want.

    This `./layout.ps1` places content within a standard frame.

    Feel free to copy and paste this code.
    
    Please document your parameters, and add NOTES.
.NOTES
    This layout makes use of a few includes and a custom CSS function.

    Includes are commands that directly output content, often in `html` or `svg`.

    * `/_includes/CopyCode' includes a copy code link
    * `/_includes/FeatherIcon` includes a feather icon
    * `/_includes/Palette` includes a color palette selector

    
    These should be initialized prior to use.
#>

param(
[uri]
$RepositoryUrl = $(
    if ($env:GITHUB_REPOSITORY) {
        "https://github.com/$env:GITHUB_REPOSITORY"
    } else {
        "https://github.com/PoshWeb/Matrix"
    }
),

[string]
$AnalyticsId,

[string]
$PaletteName = 'cyberpunk',

# The Google Font name
[Alias('FontName')]
[string]
$Font = 'Roboto',

# The Google Code Font name
[string]
$CodeFont = 'CodeFont',

# If set, will not include highlight js
[switch]
$NoHighlight,

[psobject]
$SiteMenu = $(
    [PSCustomObject]@{
        Matrix = [PSCustomObject]@{
            CSS = [PSCustomObject]@{
                "CSS Matrix" = '/matrix/css/'
                Compatibility = '/matrix/css/compatible/'
                Transforms = '/matrix/css/transform/'
            }
            HTML = [PSCustomObject]@{
                "HTML Matrix" = '/matrix/html/'
                "MathML Matrix" = '/matrix/mathml/'
                "SVG Matrix" = '/matrix/svg/'
            }            
            PowerShell = [PSCustomObject]@{
                DotNet = '/matrix/dotnet/'
                PowerShell = '/matrix/powershell/'
            }            
        }
    }
),

[string]
$SiteName = $(
    if ($env:GITHUB_REPOSITORY) {
        @($env:GITHUB_REPOSITORY -split '/', 2)[-1]
    } else {
        'Matrix'
    }
),

# The locale for the page.
# By default, the Current UI Culture.
[Alias('Locale')]
[cultureinfo]
$Culture = [CultureInfo]::CurrentUICulture,

[uri]
$PageUrl
)

# Gather all input using `$input` for maximum efficiency.
$allInput = @($input)

# Declare a filter to turn things into HTML.
filter toHtml {
    $in = $_

    # XML lives rent-free in HTML
    if ($in.OuterXml) {return $in.OuterXml}

    # Any object with an .html property
    $inHtml = $in.Html            
    if ($inHtml) {
        # should render that property
        return $inHtml
    }
    
    "$in"            
}


# Know thyself
$mySelf = $MyInvocation.MyCommand

# Any environment variables
foreach ($env in Get-ChildItem env:) {
    # See if any environment variables map to parameter
    # (after we remove any punctuation from the name)
    $envName = $env.Name -replace '\p{P}'
    if (        
        # If they map
        $mySelf.Parameters[$envName] -and 
        # and are not already bound
        (-not $PSBoundParameters.ContainsKey($envName))
    ) {
        # set them
        $ExecutionContext.SessionState.PSVariable.Set(
            $envName,
            $(
                # If the value looks like json
                if ($env.Value -match '^\s{0,}[\[\{]') {
                    # convert it before we set the value.
                    ConvertFrom-Json -InputObject $env.Value
                }
                # If the value is a boolean string
                elseif ($env.Value -match '^true|false$') {
                    # convert it to a boolean
                    $evn.Value -match 'true'
                } 
                # Otherwise, directly map it.
                else {
                    $env.Value
                }
            )
        )
        # After we set the variable, map it into `$psBoundParameters`
        $PSBoundParameters[$envName] = 
            $ExecutionContext.SessionState.PSVariable.Get(
                $envName
            ).Value
    }
}


$head = @(
    # Analytics first (per recommendations)
    if ($AnalyticsId) {
        "<!-- Google tag (gtag.js) -->
        <script async src='https://www.googletagmanager.com/gtag/js?id=$($AnalyticsID)'></script>
        <script>
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '$($AnalyticsID)');
        </script>"

    }
    # Basic viewport
    "<meta charset='utf-8' />"
    "<meta name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1.0' />"

    # If a title was set
    if ($title) {
        # use it
        "<title>$(
            [Web.HttpUtility]::HtmlEncode($title)
        )</title>"

    }

    if ($description) {
        "<meta name='description' content='$(
            [Web.HttpUtility]::HtmlAttributeEncode($description)
        )' />"

    }

    # If a palette name was provided
    if ($PaletteName) { 
        # link to the stylesheet
        "<link rel='stylesheet' href='https://cdn.jsdelivr.net/gh/2bitdesigns/4bitcss@latest/css/$PaletteName.css' id='palette' />"
    }

    if (-not $NoHighlight) {
        "<link rel='stylesheet' href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/styles/default.min.css' id='highlight' />"
        '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/highlight.min.js"></script>'
        foreach ($language in 'css', 'svg', 'html','powershell') {
            "<script src='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/languages/$language.min.js'></script>"
        }
    }        

    if ($ExecutionContext.SessionState.InvokeCommand.GetCommand("/$SiteName.css", 'Alias,Function')) {
        if ($PageUrl) {
            "<link rel='stylesheet' href='/$SiteName.css' />"
        } else {
            "<style>"
            . "/$SiteName.css"
            "</style>"
        }
    }        
)

$body = @(
    "<section class='foreground'>"
        "<header>"
            "<details class='main-menu'>"
                "<summary>$(
                    /_includes/FeatherIcon -Icon menu
                )</summary>"

                "<article>"
                    "<li><a href='/' aria-label='Home'>$(
                        /_includes/FeatherIcon -Icon home
                    )</a></li>"

                    "<li><a href='$RepositoryUrl' aria-label='GitHub'>$(
                        /_includes/FeatherIcon -Icon github
                    )</a></li>"

                    /_includes/Menu $SiteMenu
                "</article>"
            "</details>"
            "<section class='title'>"
                if ($ExecutionContext.SessionState.InvokeCommand.GetCommand("/$siteName.svg", 'Alias,Function')) {
                    "<div class='grid'>"
                        "<div class='logo'>"
                            . "/$SiteName.svg"
                        "</div>"                    
                    "</div>"                    
                }
                "<h1 class='logo-text'>$siteName</h1>"
            "</section>"
            "<details class='options-menu'>"
                "<summary>$(/_includes/FeatherIcon settings)</summary>"
                "<fieldset><legend>Palette</legend>$(
                    /_includes/Palette -DefaultPalette $PaletteName
                )</fieldset>"
                
            "</details>"        
            
        "</header>"
        "<section class='main'>"            
            @($allInput | toHtml) -join [Environment]::NewLine                
        "</section>"
        "<footer><section class='scroll-progress'></section></footer>"
    "</section>"
    /_includes/CopyCode
)


"<!DOCTYPE html>"
"<html lang='$($Culture)'>"
    "<head>$(
        $head -join [Environment]::NewLine
    )</head>"

    "<body>$(
        $body -join [Environment]::NewLine
    )</body>"

"</html>"