Veto
Components

Terminal box

A terminal window for the 'here is the command to run' block on a landing page or an installation guide. It is presentation, not an emulator - nothing is executed, and the typing animation plays over text that is already on the page.

One command

The common shape is one line long, so Command is a shorthand for a single child line. The copy button takes the command without the prompt - a prompt is decoration, and pasting one into a shell is an error.

Terminal

dotnet add package Veto
razor
<VetoTerminalBox Command="dotnet add package Veto" />

Typing

Typed reveals the command a character at a time. It is a width animation stepped once per character, over text that is already in the DOM - nothing is inserted as it plays, so the text stays selectable and a screen reader is given the whole command at once rather than watching it arrive. Looping suits a landing page, a page the reader is working through wants it to settle, which is what Loop=false does.

Looping

npx create-veto-app@latest

Types once, then stays

dotnet new blazorwasm -o MyApp

Wide characters

echo こんにちは 🚀
razor
@* Types in, holds, clears, repeats. *@
<VetoTerminalBox Command="npx create-veto-app@latest" Typed="true" />

@* Types once and stays put. *@
<VetoTerminalBox Command="dotnet new blazorwasm -o MyApp"
                 Typed="true" Loop="false" TypingDuration="3s" />

A long session

MaxHeight caps the window's body; the lines scroll inside it rather than stretching the page.

build

[01/12] Compiling Veto.Component1...
[02/12] Compiling Veto.Component2...
[03/12] Compiling Veto.Component3...
[04/12] Compiling Veto.Component4...
[05/12] Compiling Veto.Component5...
[06/12] Compiling Veto.Component6...
[07/12] Compiling Veto.Component7...
[08/12] Compiling Veto.Component8...
[09/12] Compiling Veto.Component9...
[10/12] Compiling Veto.Component10...
[11/12] Compiling Veto.Component11...
[12/12] Compiling Veto.Component12...
razor
<VetoTerminalBox Title="build" MaxHeight="10rem">
    @foreach (var line in _log)
    {
        <VetoTerminalLine Prompt="@null" Output="@line" />
    }
</VetoTerminalBox>

A session

Child lines for anything longer than one command. Output is drawn muted and is deliberately left out of what the copy button collects, nobody wants a program's own chatter pasted back into their shell. A line that is only output belongs to the program, so give it no prompt.

bash

dotnet add package Veto
info : Adding PackageReference for 'Veto' into project.
dotnet run
Now listening on: http://localhost:5000
razor
<VetoTerminalBox Title="bash">
    <VetoTerminalLine Command="dotnet add package Veto" />
    <VetoTerminalLine Prompt="@null" Output="info : Adding PackageReference for 'Veto' into project." />
    <VetoTerminalLine Command="dotnet run" />
    <VetoTerminalLine Prompt="@null" Output="Now listening on: http://localhost:5000" />
</VetoTerminalBox>

The window itself

Title and Icon name the window - a shell, a container, a remote host. ShowHeader=false takes the bar away entirely, for a page that has already said what it is, and the body then carries the rounding.

deploy@veto-prod

systemctl restart veto
git clone https://github.com/G-HK/Veto.git
razor
<VetoTerminalBox Title="deploy@veto-prod" Icon="@VetoIcons.Server"
                 Command="systemctl restart veto" />

<VetoTerminalBox ShowHeader="false"
                 Command="git clone https://github.com/G-HK/Veto.git" />

The prompt sign

Prompt is any string, so the sign is whatever the shell you are showing actually uses. PromptContent replaces it with content - an icon, a coloured host name - and unlike a bare $, content put there deliberately is read out rather than hidden, because it is presumably saying something. PromptEditable lets the reader type over it, which is what makes @bind-Prompt worth having: the prompt becomes a small input of its own.

zsh

veto build

pwsh

dotnet test

With an icon

git push origin main

Type over the prompt

whoami
Bound prompt: $
razor
@* Any sign the shell you are showing actually uses. *@
<VetoTerminalBox Prompt="&#8250;" Command="veto build" />
<VetoTerminalBox Prompt="PS>" Command="dotnet test" />

@* Content instead of a sign. *@
<VetoTerminalLine Command="git push origin main">
    <PromptContent>
        <VetoIcon Icon="@VetoIcons.GitHub" Size="VetoIconSize.Small" />
    </PromptContent>
</VetoTerminalLine>

@* Editable, and bound back to the page. *@
<VetoTerminalBox PromptEditable="true" @bind-Prompt="_prompt" Command="whoami" />

What copy takes

By default the commands in the window, one per line, gathered from what is actually rendered. CopyText overrides that outright - for a window showing an abbreviated command where the real one is longer, or where the thing worth copying was never on screen.

Copies more than it shows

docker compose up

No copy button

rm -rf ./bin ./obj
Not copied yet
razor
@* Copies the full command, not the short one on screen. *@
<VetoTerminalBox Command="docker compose up"
                 CopyText="docker compose --profile full --env-file .env.production up --build --detach" />

<VetoTerminalBox Command="rm -rf ./bin ./obj" Copyable="false" />
Something went wrong. Reload 🗙