commit 0a9b177f7c0a948aff9dd300bd491f46da2531d9 Author: Alex Dunmow Date: Sat Jun 6 14:11:44 2026 +0800 initial: theme plugin terminal Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/terminal. Co-Authored-By: Claude Opus 4.7 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ae1cff --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +terminal.so diff --git a/BUILD_REPORT.md b/BUILD_REPORT.md new file mode 100644 index 0000000..5876849 --- /dev/null +++ b/BUILD_REPORT.md @@ -0,0 +1,247 @@ +# 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 `