Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/guest-portfolio.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Terminal.js is the central orchestrator of the portfolio. It renders the full command history, wires up keyboard input through TerminalInput, parses every typed command via a switch dispatch, and outputs richly styled React nodes for each result. It also mounts a desktop-only CommandPalette sidebar so visitors can click commands rather than type them.
TerminalContext
All shared runtime state lives inTerminalContext. The useTerminal() hook provides the following shape to any consumer:
addHistory is shaped as:
setExecuteCommand is called inside Terminal with () => processCommand
so that the CommandPalette sidebar can invoke executeCommand(cmd) to
programmatically trigger any command — the same code path as typing it at the
prompt. Without this indirection, CommandPalette would have no access to
processCommand, since it lives in a sibling subtree.Layout Structure
CommandPalette is rendered as a sibling in the parent layout:
Prompt Format
Every history entry renders the prompt in the pattern:guest@portfolio.dev:— rendered in green (text-terminal-green)<cwd>— rendered in amber (text-terminal-amber), e.g.~or~/projects$and the command text — rendered in white (text-terminal-white)
TerminalInput at the bottom renders an identical prompt prefix so the active line matches the history lines visually.
Auto-scroll
AuseRef anchor <div> is placed after the last history entry and after TerminalInput. Whenever history changes, a useEffect fires scrollIntoView({ behavior: 'smooth' }) to keep the newest output visible:
Command Dispatch
Commands are parsed by splitting the raw input string on whitespace, lower-casing the first token, then switching on it. The full set of recognised commands:| Command | Output component / behaviour |
|---|---|
help | Inline two-column command reference grid |
clear | Calls clearHistory(), returns immediately |
whoami | <AboutOutput /> |
cat about.md | <AboutOutput /> |
./skills.sh | <SkillsOutput /> |
git log | <GitLogOutput /> |
git <other> | Inline error: git: '<token>' is not a git command |
mail [subject] | <MailOutput subject={...} /> |
man <page> | <ManOutput page={...} /> |
man (no arg) | Inline: What manual page do you want? |
ls [-la] [dir] | Directory listing from virtual filesystem |
cd [dir] | Updates cwd via setCwd |
cat <file> | File content from virtual filesystem |
theme green|amber | Calls setTheme, confirms inline |
sudo make me a sandwich | Easter egg 🥪 |
sudo <other> | ”not in the sudoers file” error |
matrix | Shows <MatrixRain /> for 5 seconds |
cowsay [text] | ASCII cow <pre> block |
vim / emacs / nano | Redirects to mail |
<unknown> | Red div: command not found: <token> |
Filesystem Commands
ls and cd resolve paths using the resolveNode(cwd, target) utility from utils/fileSystem.js. Errors (e.g. path not found, not a directory) render in text-terminal-red. Directory listings colour entries based on node.type: "dir" → amber bold, "exec" → green bold, regular files → unstyled white.
Initial Render
When the history array is empty (first load or afterclear), a useEffect fires once and calls addHistory("", <AsciiBanner />) to render the welcome banner with no prompt prefix.
CommandPalette Integration
CommandPalette reads executeCommand from context and calls it when a quick-command button is clicked. It is hidden on small/medium screens (hidden lg:block) and sits in a fixed-width w-64 sidebar with two sections:
- QUICK COMMANDS — 8 pre-wired commands:
help,whoami,ls projects/,./skills.sh,git log --career,ls -la blog/,mail,clear - SYSTEM —
theme amber/theme greentoggle buttons
TerminalInput Behaviour
TerminalInput renders the active prompt line. Key behaviours:
- Enter — submits the current value, calls
onCommand(value), resets input - ↑ / ↓ — navigates command history (filtered to non-empty commands)
- Tab — tab-completion for command names and filesystem paths
- Click anywhere — auto-focuses the input so typing always works
- The visible cursor is a
<span className="typewriter-cursor bg-terminal-primary">block overlay; the real<input>usescaret-transparent