From 0a9b177f7c0a948aff9dd300bd491f46da2531d9 Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sat, 6 Jun 2026 14:11:44 +0800 Subject: [PATCH] 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 --- .gitignore | 1 + BUILD_REPORT.md | 247 +++++++++++++ Makefile | 60 ++++ RECOMMENDED_FONTS.md | 31 ++ ascii_header.go | 46 +++ ascii_header.templ | 40 +++ ascii_header_templ.go | 140 ++++++++ assets/.gitkeep | 0 assets/style.css | 430 +++++++++++++++++++++++ boot_log.go | 55 +++ boot_log.templ | 25 ++ boot_log_templ.go | 119 +++++++ button_override.go | 24 ++ button_override.templ | 20 ++ button_override_templ.go | 106 ++++++ code_console.go | 44 +++ code_console.templ | 15 + code_console_templ.go | 108 ++++++ email_wrapper.templ | 141 ++++++++ email_wrapper_templ.go | 434 +++++++++++++++++++++++ embed.go | 59 ++++ fonts.json | 1 + footer.go | 59 ++++ footer.templ | 33 ++ footer_templ.go | 179 ++++++++++ go.mod | 20 ++ go.sum | 42 +++ heading_override.go | 44 +++ heading_override.templ | 52 +++ heading_override_templ.go | 322 +++++++++++++++++ helpers.go | 75 ++++ image_override.go | 30 ++ image_override.templ | 22 ++ image_override_templ.go | 117 +++++++ keybind_table.go | 56 +++ keybind_table.templ | 24 ++ keybind_table_templ.go | 86 +++++ manpage_header.go | 46 +++ manpage_header.templ | 12 + manpage_header_templ.go | 94 +++++ plugin.mod | 12 + presets.json | 89 +++++ register.go | 181 ++++++++++ registration.go | 25 ++ schemas/ascii_header.schema.json | 29 ++ schemas/boot_log.schema.json | 27 ++ schemas/code_console.schema.json | 37 ++ schemas/footer.schema.json | 46 +++ schemas/keybind_table.schema.json | 33 ++ schemas/manpage_header.schema.json | 31 ++ schemas/toc.schema.json | 39 +++ template.templ | 257 ++++++++++++++ template_templ.go | 541 +++++++++++++++++++++++++++++ text_override.go | 17 + text_override.templ | 7 + text_override_templ.go | 66 ++++ toc.go | 50 +++ toc.templ | 27 ++ toc_templ.go | 124 +++++++ 59 files changed, 5097 insertions(+) create mode 100644 .gitignore create mode 100644 BUILD_REPORT.md create mode 100644 Makefile create mode 100644 RECOMMENDED_FONTS.md create mode 100644 ascii_header.go create mode 100644 ascii_header.templ create mode 100644 ascii_header_templ.go create mode 100644 assets/.gitkeep create mode 100644 assets/style.css create mode 100644 boot_log.go create mode 100644 boot_log.templ create mode 100644 boot_log_templ.go create mode 100644 button_override.go create mode 100644 button_override.templ create mode 100644 button_override_templ.go create mode 100644 code_console.go create mode 100644 code_console.templ create mode 100644 code_console_templ.go create mode 100644 email_wrapper.templ create mode 100644 email_wrapper_templ.go create mode 100644 embed.go create mode 100644 fonts.json create mode 100644 footer.go create mode 100644 footer.templ create mode 100644 footer_templ.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 heading_override.go create mode 100644 heading_override.templ create mode 100644 heading_override_templ.go create mode 100644 helpers.go create mode 100644 image_override.go create mode 100644 image_override.templ create mode 100644 image_override_templ.go create mode 100644 keybind_table.go create mode 100644 keybind_table.templ create mode 100644 keybind_table_templ.go create mode 100644 manpage_header.go create mode 100644 manpage_header.templ create mode 100644 manpage_header_templ.go create mode 100644 plugin.mod create mode 100644 presets.json create mode 100644 register.go create mode 100644 registration.go create mode 100644 schemas/ascii_header.schema.json create mode 100644 schemas/boot_log.schema.json create mode 100644 schemas/code_console.schema.json create mode 100644 schemas/footer.schema.json create mode 100644 schemas/keybind_table.schema.json create mode 100644 schemas/manpage_header.schema.json create mode 100644 schemas/toc.schema.json create mode 100644 template.templ create mode 100644 template_templ.go create mode 100644 text_override.go create mode 100644 text_override.templ create mode 100644 text_override_templ.go create mode 100644 toc.go create mode 100644 toc.templ create mode 100644 toc_templ.go 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 `