Examples/Invoke-QuizDemo.ps1

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

# ---------------------------------------------------------------------------
# Quiz demo
# Five PowerShell/Elm-Architecture multiple-choice questions.
# Demonstrates: multi-phase views (Quiz -> Results), answer tracking,
# conditional rendering based on model state
# ---------------------------------------------------------------------------

$questions = @(
    [PSCustomObject]@{
        Text    = 'What does TEA stand for?'
        Options = @(
            'Terminal Elm Architecture'
            'The Elm Architecture'
            'Typed Event Abstraction'
            'Terminal Event Adapter'
        )
        Answer  = 1
    }
    [PSCustomObject]@{
        Text    = 'Which PowerShell version introduced classes?'
        Options = @(
            'PowerShell 3.0'
            'PowerShell 4.0'
            'PowerShell 5.0'
            'PowerShell 6.0'
        )
        Answer  = 2
    }
    [PSCustomObject]@{
        Text    = 'In the Elm Architecture, which function handles messages?'
        Options = @(
            'InitFn'
            'UpdateFn'
            'ViewFn'
            'DispatchFn'
        )
        Answer  = 1
    }
    [PSCustomObject]@{
        Text    = 'What ANSI escape sequence hides the terminal cursor?'
        Options = @(
            'ESC[0m'
            'ESC[2J'
            'ESC[?25l'
            'ESC[?25h'
        )
        Answer  = 2
    }
    [PSCustomObject]@{
        Text    = 'What does Compare-ElmViewTree return on the very first render?'
        Options = @(
            'Empty list'
            'Clear patch'
            'Replace patch'
            'FullRedraw patch'
        )
        Answer  = 3
    }
)

$init = {
    [PSCustomObject]@{
        Model = [PSCustomObject]@{
            Questions     = $questions
            QuestionIndex = 0
            Selected      = 0
            Answers       = @()
            Phase         = 'Quiz'
        }
        Cmd = $null
    }
}

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

    if ($msg.Key -eq 'Q') {
        return [PSCustomObject]@{
            Model = $model
            Cmd   = [PSCustomObject]@{ Type = 'Quit' }
        }
    }

    if ($model.Phase -eq 'Results') {
        if ($msg.Key -eq 'R') {
            return [PSCustomObject]@{
                Model = [PSCustomObject]@{
                    Questions     = $model.Questions
                    QuestionIndex = 0
                    Selected      = 0
                    Answers       = @()
                    Phase         = 'Quiz'
                }
                Cmd = $null
            }
        }
        return [PSCustomObject]@{ Model = $model; Cmd = $null }
    }

    $q        = $model.Questions[$model.QuestionIndex]
    $optCount = @($q.Options).Count

    switch ($msg.Key) {
        'UpArrow' {
            $newSel = if ($model.Selected -gt 0) { $model.Selected - 1 } else { $optCount - 1 }
            return [PSCustomObject]@{
                Model = [PSCustomObject]@{
                    Questions     = $model.Questions
                    QuestionIndex = $model.QuestionIndex
                    Selected      = $newSel
                    Answers       = $model.Answers
                    Phase         = 'Quiz'
                }
                Cmd = $null
            }
        }
        'DownArrow' {
            $newSel = if ($model.Selected -lt $optCount - 1) { $model.Selected + 1 } else { 0 }
            return [PSCustomObject]@{
                Model = [PSCustomObject]@{
                    Questions     = $model.Questions
                    QuestionIndex = $model.QuestionIndex
                    Selected      = $newSel
                    Answers       = $model.Answers
                    Phase         = 'Quiz'
                }
                Cmd = $null
            }
        }
        'Enter' {
            $correct    = ($model.Selected -eq $q.Answer)
            $newAnswers = @($model.Answers) + @($correct)
            $nextIndex  = $model.QuestionIndex + 1
            $nextPhase  = if ($nextIndex -ge @($model.Questions).Count) { 'Results' } else { 'Quiz' }
            return [PSCustomObject]@{
                Model = [PSCustomObject]@{
                    Questions     = $model.Questions
                    QuestionIndex = $nextIndex
                    Selected      = 0
                    Answers       = $newAnswers
                    Phase         = $nextPhase
                }
                Cmd = $null
            }
        }
    }

    [PSCustomObject]@{ Model = $model; Cmd = $null }
}

$view = {
    param($model)

    $titleStyle    = New-ElmStyle -Foreground 'BrightCyan' -Bold
    $questionStyle = New-ElmStyle -Foreground 'BrightWhite'
    $selectedStyle = New-ElmStyle -Foreground 'BrightYellow' -Bold
    $normalStyle   = New-ElmStyle -Foreground 'White'
    $correctStyle  = New-ElmStyle -Foreground 'BrightGreen'
    $wrongStyle    = New-ElmStyle -Foreground 'BrightRed'
    $hintStyle     = New-ElmStyle -Foreground 'BrightBlack'
    $boxStyle      = New-ElmStyle -Border 'Rounded' -Padding @(0, 2) -Width 56

    if ($model.Phase -eq 'Results') {
        $answers = @($model.Answers)
        $score   = ($answers | Where-Object { $_ }).Count
        $total   = $answers.Count

        $children = @(
            New-ElmText -Content 'Quiz Results' -Style $titleStyle
            New-ElmText -Content ''
            New-ElmText -Content "Score: $score / $total" -Style $questionStyle
            New-ElmText -Content ''
        )

        $qs = @($model.Questions)
        for ($i = 0; $i -lt $qs.Count; $i++) {
            $marker = if ($answers[$i]) { '[+]' } else { '[x]' }
            $style  = if ($answers[$i]) { $correctStyle } else { $wrongStyle }
            $children += New-ElmText -Content "$marker $($qs[$i].Text)" -Style $style
        }

        $children += New-ElmText -Content ''
        $children += New-ElmText -Content '[R] try again [Q] quit' -Style $hintStyle

        return New-ElmBox -Style $boxStyle -Children $children
    }

    # Quiz phase
    $q      = $model.Questions[$model.QuestionIndex]
    $qNum   = $model.QuestionIndex + 1
    $qTotal = @($model.Questions).Count
    $opts   = @($q.Options)

    $children = @(
        New-ElmText -Content "Question $qNum of $qTotal" -Style $hintStyle
        New-ElmText -Content ''
        New-ElmText -Content $q.Text -Style $questionStyle
        New-ElmText -Content ''
    )

    for ($i = 0; $i -lt $opts.Count; $i++) {
        $marker = if ($i -eq $model.Selected) { '(*) ' } else { '( ) ' }
        $style  = if ($i -eq $model.Selected) { $selectedStyle } else { $normalStyle }
        $children += New-ElmText -Content "$marker$($opts[$i])" -Style $style
    }

    $children += New-ElmText -Content ''
    $children += New-ElmText -Content '[Up/Down] select [Enter] confirm [Q] quit' -Style $hintStyle

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

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