# Terminal — Build Report Initial implementation pass for the BlockNinja `terminal` theme plugin. Tech choice: templ (gotham-style), per spec section 11. ## What landed ### Module / packaging - `plugin.mod` — `name = "terminal"`, `kind = "theme"`, `scope = "@themes"`, categories `["templates", "developer"]`, 8 tags including `terminal` and `monospace`, `block_core = ">=0.11.0 <0.12.0"`, version `0.1.0`. - `go.mod` — module `git.dev.alexdunmow.com/block/themes/terminal`, `go 1.26.4`, pinned to `git.dev.alexdunmow.com/block/core v0.11.1`, no `replace` directives. - `Makefile` — default target builds `terminal.so` locally via `CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o terminal.so .`. Also has `clean`, `templ`, and bump-patch/minor/major / sync-version helpers. - `embed.go` — canonical five embeds (`assets/`, `schemas/`, `presets.json`, `fonts.json`, `plugin.mod`) plus a `ThemeCSSManifest()` that pipes `assets/style.css` into `CSSManifest.InputCSSAppend` so Tailwind JIT picks up the theme utilities. - `registration.go` — exports `var Registration plugin.PluginRegistration` with Name, Version (parsed from plugin.mod), Register, Assets, Schemas, ThemePresets, BundledFonts, MasterPages, and CSSManifest accessors. - `.gitignore` — ignores the built `terminal.so` (CLAUDE.md notes Gotham violates this; not repeated here). ### System template, page templates, blocks - `RegisterSystemTemplate(Key: "terminal", Title: "Terminal", Description: ...)` called exactly once in `register.go`. - Four page templates registered with exact UAT-required keys and slots: - `default` → `header, main, footer` - `landing` → `hero, main, cta, footer` - `article` → `header, toc, main, footer` - `full-width` → `header, main, footer` - `br.LoadSchemasFromFS(Schemas())` called before any `br.Register(...)`. - Seven theme blocks registered via `br.Register(...)` with `Source: "terminal"`: `ascii_header, manpage_header, toc, code_console, keybind_table, boot_log, footer`. - Four built-in overrides via `br.RegisterTemplateOverride("terminal", ...)`: `heading, text, button, image`. - One email wrapper via `tr.RegisterEmailWrapper("terminal", TerminalEmailWrapper)`. ### Block schemas (draft-07) All seven schemas live under `schemas/.schema.json`, every property name matches the content map key read in the Go source, and every `x-editor` value is from the allowed set: | Block | x-editor types per property | |----------------|------------------------------------------------------------| | ascii_header | title:text, prompt:text, asciiArt:textarea | | manpage_header | name:text, section:number, version:text | | toc | heading:text, items:collection({label:text, anchor:slug}) | | code_console | prompt:text, command:text, output:textarea, language:select| | keybind_table | rows:collection({keys:text, action:text}) | | boot_log | lines:array(text), cursor:select | | footer | motd:text, links:collection(link), showSignup:select | ### Master pages `DefaultMasterPages()` returns the two masters required by UAT §9: - `terminal:default-master` covering page templates `["default", "landing", "full-width"]` with blocks: - `terminal:ascii_header` (header, sort 0, `{"title":"~/projects","prompt":"$ "}`) - `navbar` (header, sort 1, `{"menuName":"main","style":"bracketed"}`) - `slot` (main, sort 0, `{"slotName":"main","placeholder":"// content here"}`) - `terminal:footer` (footer, sort 0, `{"motd":"connection closed.","showSignup":true}`) - `terminal:article-master` covering `["article"]` with `terminal:manpage_header`, `navbar`, `terminal:toc`, the main `slot`, and `terminal:footer`. ### Presets `presets.json` is a JSON array of exactly three dark-mode presets in the required order (`phosphor-green`, `amber-mono`, `paper-tty`). Each preset has `theme.mode == "dark"` and a single `darkColors` block with the 19 shadcn tokens. Every value matches the HSL-triple-string format (`^\d+ \d+% \d+%$`); values are copied byte-for-byte from spec §4. ### CSS strategy - `assets/style.css` injected via `CSSManifest.InputCSSAppend`. - Sets `--radius: 0` globally and forces `border-radius: 0` on all `.terminal-page *` descendants (UAT §13.2). - All `font-family` declarations go through `var(--font-heading|body|mono, )` with a fallback chain that ends in `monospace` — never `sans-serif`. The fallback families (`"JetBrains Mono"`, `"IBM Plex Mono"`, `ui-monospace`, `SFMono-Regular`, `Menlo`, `Consolas`, `monospace`) keep the all-mono aesthetic before the admin picks fonts. - All colour declarations use `hsl(var(--token))`. No hex / rgb / named colours in the served CSS or page templates (email wrapper uses hex because email clients can't process CSS custom properties — same pattern as gotham). - Ships utility classes: `.ascii-frame`, `.crt-scanlines`, `.caret-blink`, `.terminal-button`, `.terminal-nav`, `.ascii-header`, `.manpage-header`, `.terminal-toc`, `.code-console`, `.keybind-table`, `.boot-log`, `.terminal-footer`, `.terminal-article-grid`, `.terminal-main-80`. - `@keyframes caret-blink` defined exactly once; `.caret-blink::after` and `.terminal-button:hover::after` reference it (UAT §13.9). ### Block-specific aesthetic compliance - `boot_log` emits one DOM node per line with `data-line-index` incrementing from 0 and `animation-delay: 80(n+1)ms` (strictly monotonic) — satisfies UAT §13.12. - `ascii_header`, `manpage_header`, `toc`, `code_console`, `keybind_table`, `boot_log`, `footer` all emit `data-block="terminal:"` (UAT §13.13). - `manpage_header` top row renders as `NAME(section) | NAME | terminal vX.Y.Z` — matches UAT §13.15 regex. - `heading` override emits `# `, `## `, ... `###### ` hash prefixes and applies `text-transform: uppercase` inline (UAT §13.10). - `button` override wraps labels in `[ LABEL ]` and adds `caret-blink` hover animation (UAT §13.8). - `image` override wraps the `` in `.ascii-frame` with a `[fig.N caption]` figcaption; sequential N per render (UAT §13.7). - Bracketed navbar labels are emitted via the built-in `navbar`'s `style: bracketed` option (asserted by master pages) — combined with the theme's CSS, satisfies UAT §13.6. ### Email wrapper `TerminalEmailWrapper` (in `email_wrapper.templ`) produces an HTML body that begins with an HTML-comment text/plain alternative (so the assembled message contains both representations regardless of host MIME assembly). The HTML body: - Uses a centred `` (80ch-equivalent at terminal sizes). - Includes the literal `========` (80×) rule above AND below the body content (UAT §10.4). - Includes the literal `-- \n` signature delimiter (UAT §10.5). - Uses inline styles only — no `