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 <noreply@anthropic.com>
182 lines
5.9 KiB
Go
182 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/a-h/templ"
|
|
|
|
"git.dev.alexdunmow.com/block/core/blocks"
|
|
"git.dev.alexdunmow.com/block/core/plugin"
|
|
"git.dev.alexdunmow.com/block/core/templates"
|
|
)
|
|
|
|
// wrap adapts a templ-returning render function to templates.TemplateFunc.
|
|
// templ.Component already implements templates.HTMLComponent via Render.
|
|
func wrap(f func(ctx context.Context, doc map[string]any) templ.Component) templates.TemplateFunc {
|
|
return func(ctx context.Context, doc map[string]any) templates.HTMLComponent {
|
|
return f(ctx, doc)
|
|
}
|
|
}
|
|
|
|
// Register is the plugin entry point that wires up the Terminal system
|
|
// template, its four page templates, all theme blocks, the four built-in
|
|
// overrides, and the email wrapper.
|
|
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
|
// 1) System template
|
|
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
|
|
Key: "terminal",
|
|
Title: "Terminal",
|
|
Description: "Phosphor green on black terminal aesthetic with ASCII art and monospace type.",
|
|
})
|
|
|
|
// 2) Page templates (exact keys + slots per spec §6 / UAT §3)
|
|
if err := tr.RegisterPageTemplate("terminal", templates.PageTemplateMeta{
|
|
Key: "default",
|
|
Title: "Default",
|
|
Description: "Standard 80-col centered TTY layout",
|
|
Slots: []string{"header", "main", "footer"},
|
|
}, wrap(RenderTerminal)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("terminal", templates.PageTemplateMeta{
|
|
Key: "landing",
|
|
Title: "Landing",
|
|
Description: "ASCII hero + feature grid for project README sites",
|
|
Slots: []string{"hero", "main", "cta", "footer"},
|
|
}, wrap(RenderTerminalLanding)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("terminal", templates.PageTemplateMeta{
|
|
Key: "article",
|
|
Title: "Article (man-page)",
|
|
Description: "Man-page two-column with section nav, ideal for writeups",
|
|
Slots: []string{"header", "toc", "main", "footer"},
|
|
}, wrap(RenderTerminalArticle)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("terminal", templates.PageTemplateMeta{
|
|
Key: "full-width",
|
|
Title: "Full Width",
|
|
Description: "Edge-to-edge for tool dashboards & status pages",
|
|
Slots: []string{"header", "main", "footer"},
|
|
}, wrap(RenderTerminalFullWidth)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 3) Schemas BEFORE block registration (per CLAUDE.md).
|
|
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 4) Theme blocks. Keys are unqualified at registration; address as
|
|
// terminal:<key> from master pages and page block lists.
|
|
br.Register(AsciiHeaderBlockMeta, AsciiHeaderBlock)
|
|
br.Register(ManpageHeaderBlockMeta, ManpageHeaderBlock)
|
|
br.Register(TocBlockMeta, TocBlock)
|
|
br.Register(CodeConsoleBlockMeta, CodeConsoleBlock)
|
|
br.Register(KeybindTableBlockMeta, KeybindTableBlock)
|
|
br.Register(BootLogBlockMeta, BootLogBlock)
|
|
br.Register(FooterBlockMeta, FooterBlock)
|
|
|
|
// 5) Built-in block overrides — only applied while the Terminal theme
|
|
// is active.
|
|
br.RegisterTemplateOverride("terminal", "heading", TerminalHeadingBlock)
|
|
br.RegisterTemplateOverride("terminal", "text", TerminalTextBlock)
|
|
br.RegisterTemplateOverride("terminal", "button", TerminalButtonBlock)
|
|
br.RegisterTemplateOverride("terminal", "image", TerminalImageBlock)
|
|
|
|
// 6) Email wrapper (plain text first, then HTML — handled by wrapper).
|
|
tr.RegisterEmailWrapper("terminal", TerminalEmailWrapper)
|
|
|
|
return nil
|
|
}
|
|
|
|
// DefaultMasterPages returns the two master pages Terminal seeds on first
|
|
// load (per UAT §9): one default master covering default/landing/full-width,
|
|
// and one article master that swaps in the man-page header and adds the
|
|
// TOC block.
|
|
func DefaultMasterPages() []plugin.MasterPageDefinition {
|
|
return []plugin.MasterPageDefinition{
|
|
{
|
|
Key: "terminal:default-master",
|
|
Title: "Terminal Default Master",
|
|
PageTemplates: []string{"default", "landing", "full-width"},
|
|
Blocks: []plugin.MasterPageBlock{
|
|
{
|
|
BlockKey: "terminal:ascii_header",
|
|
Title: "TTY Header",
|
|
Content: map[string]any{"title": "~/projects", "prompt": "$ "},
|
|
Slot: "header",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "navbar",
|
|
Title: "Main Nav",
|
|
Content: map[string]any{"menuName": "main", "style": "bracketed"},
|
|
Slot: "header",
|
|
SortOrder: 1,
|
|
},
|
|
{
|
|
BlockKey: "slot",
|
|
Title: "Main Content",
|
|
Content: map[string]any{"slotName": "main", "placeholder": "// content here"},
|
|
Slot: "main",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "terminal:footer",
|
|
Title: "TTY Footer",
|
|
Content: map[string]any{"motd": "connection closed.", "showSignup": true},
|
|
Slot: "footer",
|
|
SortOrder: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Key: "terminal:article-master",
|
|
Title: "Terminal Article Master",
|
|
PageTemplates: []string{"article"},
|
|
Blocks: []plugin.MasterPageBlock{
|
|
{
|
|
BlockKey: "terminal:manpage_header",
|
|
Title: "Man-page Header",
|
|
Content: map[string]any{"name": "WRITEUP", "section": 1, "version": "terminal v0.1.0"},
|
|
Slot: "header",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "navbar",
|
|
Title: "Main Nav",
|
|
Content: map[string]any{"menuName": "main", "style": "bracketed"},
|
|
Slot: "header",
|
|
SortOrder: 1,
|
|
},
|
|
{
|
|
BlockKey: "terminal:toc",
|
|
Title: "Section TOC",
|
|
Content: map[string]any{"heading": "Sections", "items": []any{}},
|
|
Slot: "toc",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "slot",
|
|
Title: "Article Body",
|
|
Content: map[string]any{"slotName": "main", "placeholder": "// article body"},
|
|
Slot: "main",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "terminal:footer",
|
|
Title: "TTY Footer",
|
|
Content: map[string]any{"motd": "connection closed.", "showSignup": false},
|
|
Slot: "footer",
|
|
SortOrder: 0,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|