Examples/Invoke-TodoList.ps1

Import-Module "$PSScriptRoot/../Elm.psd1" -Force

# ---------------------------------------------------------------------------
# Model
# ---------------------------------------------------------------------------
# items : list of @{ Text = '...'; Done = $false }
# cursor : index of the selected item
# ---------------------------------------------------------------------------

$init = {
    $items = @(
        @{ Text = 'Buy groceries';         Done = $false }
        @{ Text = 'Write unit tests';       Done = $false }
        @{ Text = 'Ship it';                Done = $false }
        @{ Text = 'Touch grass';            Done = $false }
        @{ Text = 'Feed the cat';           Done = $false }
    )
    [PSCustomObject]@{
        Model = [PSCustomObject]@{ Items = $items; Cursor = 0 }
        Cmd   = $null
    }
}

# ---------------------------------------------------------------------------
# Update
# ---------------------------------------------------------------------------

$update = {
    param($msg, $model)

    $items  = $model.Items
    $cursor = $model.Cursor
    $count  = $items.Count

    switch ($msg.Key) {
        'UpArrow' {
            $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $count - 1 }
        }
        'DownArrow' {
            $cursor = if ($cursor -lt $count - 1) { $cursor + 1 } else { 0 }
        }
        'Spacebar' {
            # Toggle done on selected item — clone the array so the model is immutable-ish
            $newItems = @()
            for ($i = 0; $i -lt $count; $i++) {
                if ($i -eq $cursor) {
                    $newItems += @{ Text = $items[$i].Text; Done = -not $items[$i].Done }
                } else {
                    $newItems += $items[$i]
                }
            }
            $items = $newItems
        }
        'Q' {
            return [PSCustomObject]@{
                Model = $model
                Cmd   = [PSCustomObject]@{ Type = 'Quit' }
            }
        }
    }

    [PSCustomObject]@{
        Model = [PSCustomObject]@{ Items = $items; Cursor = $cursor }
        Cmd   = $null
    }
}

# ---------------------------------------------------------------------------
# View
# ---------------------------------------------------------------------------

$view = {
    param($model)

    $titleStyle    = New-ElmStyle -Bold -Foreground 'BrightCyan'
    $hintStyle     = New-ElmStyle -Foreground 'BrightBlack'
    $selectedStyle = New-ElmStyle -Background 'Blue' -Foreground 'BrightWhite' -Bold
    $doneStyle     = New-ElmStyle -Foreground 'BrightBlack' -Strikethrough
    $normalStyle   = New-ElmStyle -Foreground 'White'
    $boxStyle      = New-ElmStyle -Border 'Rounded' -Padding @(0, 1) -Width 42

    $rows = @(
        New-ElmText -Content ' todo list' -Style $titleStyle
        New-ElmText -Content ''
    )

    for ($i = 0; $i -lt $model.Items.Count; $i++) {
        $item   = $model.Items[$i]
        $prefix = if ($item.Done) { '[x] ' } else { '[ ] ' }
        $label  = $prefix + $item.Text

        if ($i -eq $model.Cursor) {
            $rows += New-ElmText -Content "> $label" -Style $selectedStyle
        } elseif ($item.Done) {
            $rows += New-ElmText -Content " $label" -Style $doneStyle
        } else {
            $rows += New-ElmText -Content " $label" -Style $normalStyle
        }
    }

    $rows += New-ElmText -Content ''
    $rows += New-ElmText -Content ' [up/down] move [space] toggle [q] quit' -Style $hintStyle

    New-ElmBox -Style $boxStyle -Children $rows
}

# ---------------------------------------------------------------------------
# Run
# ---------------------------------------------------------------------------

Start-ElmProgram -InitFn $init -UpdateFn $update -ViewFn $view