From 6dbd76f2e87fc3657030fc233303fdcbccfcd260 Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sat, 4 Jul 2026 15:00:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20convert=20to=20codeless=20.bnp=20?= =?UTF-8?q?=E2=80=94=20templates=20+=20manifest,=20Go/templ=20deleted=20(W?= =?UTF-8?q?O-WZ-021)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- Makefile | 40 +- blocks.go | 53 -- blocks/blocks.yaml | 28 ++ .../lcars_header.ninjatpl | 6 +- {schemas => blocks}/lcars_header.schema.json | 0 .../panel.html => blocks/lcars_panel.ninjatpl | 0 {schemas => blocks}/lcars_panel.schema.json | 0 blocks/lcars_sidebar.ninjatpl | 23 + {schemas => blocks}/lcars_sidebar.schema.json | 0 embed.go | 60 --- go.mod | 19 - go.sum | 56 --- main.go | 17 - manifest.yaml | 458 ++++++++++++++++++ master_pages.go | 57 --- master_pages.json | 21 + plugin.mod | 5 +- register.go | 50 -- registration.go | 24 - templates/blocks/sidebar.html | 11 - .../lcars.ninjatpl} | 0 .../{default.html => lcars/default.ninjatpl} | 0 .../full-display.ninjatpl} | 0 .../lcars/heading.ninjatpl} | 0 .../lcars/text.ninjatpl} | 0 25 files changed, 552 insertions(+), 376 deletions(-) delete mode 100644 blocks.go create mode 100644 blocks/blocks.yaml rename templates/blocks/header.html => blocks/lcars_header.ninjatpl (72%) rename {schemas => blocks}/lcars_header.schema.json (100%) rename templates/blocks/panel.html => blocks/lcars_panel.ninjatpl (100%) rename {schemas => blocks}/lcars_panel.schema.json (100%) create mode 100644 blocks/lcars_sidebar.ninjatpl rename {schemas => blocks}/lcars_sidebar.schema.json (100%) delete mode 100644 embed.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 main.go create mode 100644 manifest.yaml delete mode 100644 master_pages.go create mode 100644 master_pages.json delete mode 100644 register.go delete mode 100644 registration.go delete mode 100644 templates/blocks/sidebar.html rename templates/{email_wrapper.html => email/lcars.ninjatpl} (100%) rename templates/{default.html => lcars/default.ninjatpl} (100%) rename templates/{full_display.html => lcars/full-display.ninjatpl} (100%) rename templates/{blocks/heading_override.html => overrides/lcars/heading.ninjatpl} (100%) rename templates/{blocks/text_override.html => overrides/lcars/text.ninjatpl} (100%) diff --git a/Makefile b/Makefile index 8122243..aeafdb4 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,27 @@ -# lcars — build & publish helpers (wasm .bnp workflow) +# lcars — build & publish helpers (CODELESS .bnp workflow, WO-WZ-021) # -# The theme compiles to a wasip1 reactor-mode wasm module packed into a .bnp -# artifact (`ninja plugin build`). The legacy .so path is retired (WO-WZ-015): -# the CMS is wasm-native and can no longer load .so plugins. Distribution is -# publish-to-registry -> InstallFromRegistry (hot-load, no restart). +# This theme is a CODELESS .bnp: pure declaration the host runs — blocks +# (blocks/blocks.yaml + .ninjatpl), page/system templates, template overrides, +# an email wrapper, master pages, presets, fonts and CSS in manifest.yaml. No +# Go, no templ, no plugin.wasm, no block/core dependency. `ninja plugin build` +# classifies the repo as codeless (no Go at the root) and packs the artifact +# with manifest.pb (codeless: true) and NO plugin.wasm. # # Usage: -# make build # compile wasm + pack lcars-.bnp -# make verify # validate the built .bnp (layout/abi/name/size) -# make archive-check # prove a clean `git archive HEAD` compiles to wasm +# make build # pack lcars-.bnp (codeless — no wasm) +# make verify # validate the built .bnp (loader-identical checks) +# make archive-check # prove a clean `git archive HEAD` still builds codeless # make publish # ninja plugin publish --bnp (to the active registry) -# make templ # regenerate templ Go files # make clean # remove build artefacts -.PHONY: build verify archive-check publish templ clean help +.PHONY: build verify archive-check publish clean help PLUGIN_NAME := lcars NINJA := ninja BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp -# Compile to wasm and pack the .bnp (GOOS=wasip1 GOARCH=wasm, DESCRIBE probe, -# tar.zst of plugin.wasm + plugin.mod + manifest.pb + schemas/ + assets/). +# Pack the codeless .bnp (manifest.pb synthesized from plugin.mod + manifest.yaml +# + blocks/ + templates/; no wasm compile, no DESCRIBE probe). build: $(NINJA) plugin build --dir . @@ -28,12 +29,12 @@ build: verify: $(NINJA) plugin verify $(BNP) -# Prove a clean `git archive HEAD` (what publish ships) compiles to wasm. +# Prove a clean `git archive HEAD` (what publish ships) still packs codeless. archive-check: @T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \ trap 'rm -rf "$$T"' EXIT && \ git archive HEAD | tar -x -C "$$T" && \ - cd "$$T" && GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o "$$T/check.wasm" . && \ + cd "$$T" && $(NINJA) plugin build --dir . && \ echo "archive-check OK" # Publish the prebuilt .bnp to the active registry. @@ -41,19 +42,14 @@ archive-check: publish: build $(NINJA) plugin publish --bnp $(BNP) -# Regenerate templ Go files locally. -templ: - templ generate - # Remove build artefacts. clean: - rm -f $(PLUGIN_NAME)-*.bnp $(PLUGIN_NAME).so plugin.wasm + rm -f $(PLUGIN_NAME)-*.bnp plugin.wasm help: @echo "Targets:" - @echo " build Compile wasm + pack the .bnp" + @echo " build Pack the codeless .bnp (no wasm)" @echo " verify Validate the built .bnp (loader-identical checks)" - @echo " archive-check Prove a clean git archive HEAD compiles to wasm" + @echo " archive-check Prove a clean git archive HEAD packs codeless" @echo " publish Publish the .bnp to the active registry" - @echo " templ Regenerate templ Go files" @echo " clean Remove build artefacts" diff --git a/blocks.go b/blocks.go deleted file mode 100644 index 9bb2043..0000000 --- a/blocks.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "git.dev.alexdunmow.com/block/core/blocks" -) - -// --- LCARS Header Block --- - -var LCARSHeaderMeta = blocks.BlockMeta{ - Key: "lcars_header", - Title: "LCARS Header", - Description: "Top bar with elbow bracket, status indicators, and stardate", - Category: blocks.CategoryNavigation, - Source: "lcars", -} - -var headerDefaults = map[string]any{ - "title": "LCARS", - "subtitle": "Library Computer Access/Retrieval System", - "stardate": "", - "status": "online", - "menu_name": "main", -} - -// --- LCARS Sidebar Block --- - -var LCARSSidebarMeta = blocks.BlockMeta{ - Key: "lcars_sidebar", - Title: "LCARS Sidebar", - Description: "Left panel with rounded-rectangle navigation buttons", - Category: blocks.CategoryNavigation, - Source: "lcars", -} - -var sidebarDefaults = map[string]any{ - "items": []any{ - map[string]any{"label": "Personnel", "url": "#", "color": "primary"}, - map[string]any{"label": "Operations", "url": "#", "color": "secondary"}, - map[string]any{"label": "Sciences", "url": "#", "color": "accent"}, - map[string]any{"label": "Engineering", "url": "#", "color": "primary"}, - map[string]any{"label": "Medical", "url": "#", "color": "secondary"}, - }, -} - -// --- LCARS Panel Block --- - -var LCARSPanelMeta = blocks.BlockMeta{ - Key: "lcars_panel", - Title: "LCARS Panel", - Description: "Framed content area with LCARS border treatment", - Category: blocks.CategoryLayout, - Source: "lcars", -} diff --git a/blocks/blocks.yaml b/blocks/blocks.yaml new file mode 100644 index 0000000..8ed7faf --- /dev/null +++ b/blocks/blocks.yaml @@ -0,0 +1,28 @@ +# LCARS theme block definitions (codeless .bnp, WO-WZ-021). +# Keys are fully qualified (lcars:) because the codeless loader registers +# definitions verbatim — there is no PluginBlockRegistry prefixing in the +# codeless path (unlike the retired wasm/pongo-guest path). The qualified keys +# match the master_pages.json block references. +# +# header and sidebar previously used MustBlockTemplateWithDefaults; the codeless +# path has no defaults-merge, so their defaults are baked into the templates via +# |default filters (title/subtitle) and the {% empty %} branch (sidebar items). +blocks: + - key: lcars:lcars_header + title: LCARS Header + description: Top bar with elbow bracket, status indicators, and stardate + category: navigation + schema: lcars_header.schema.json + template: lcars_header.ninjatpl + - key: lcars:lcars_sidebar + title: LCARS Sidebar + description: Left panel with rounded-rectangle navigation buttons + category: navigation + schema: lcars_sidebar.schema.json + template: lcars_sidebar.ninjatpl + - key: lcars:lcars_panel + title: LCARS Panel + description: Framed content area with LCARS border treatment + category: layout + schema: lcars_panel.schema.json + template: lcars_panel.ninjatpl diff --git a/templates/blocks/header.html b/blocks/lcars_header.ninjatpl similarity index 72% rename from templates/blocks/header.html rename to blocks/lcars_header.ninjatpl index a5bb160..ff66914 100644 --- a/templates/blocks/header.html +++ b/blocks/lcars_header.ninjatpl @@ -2,9 +2,9 @@
-

{{ title }}

- {% if subtitle %} - {{ subtitle }} +

{{ title|default:"LCARS" }}

+ {% if subtitle|default:"Library Computer Access/Retrieval System" %} + {{ subtitle|default:"Library Computer Access/Retrieval System" }} {% endif %}
diff --git a/schemas/lcars_header.schema.json b/blocks/lcars_header.schema.json similarity index 100% rename from schemas/lcars_header.schema.json rename to blocks/lcars_header.schema.json diff --git a/templates/blocks/panel.html b/blocks/lcars_panel.ninjatpl similarity index 100% rename from templates/blocks/panel.html rename to blocks/lcars_panel.ninjatpl diff --git a/schemas/lcars_panel.schema.json b/blocks/lcars_panel.schema.json similarity index 100% rename from schemas/lcars_panel.schema.json rename to blocks/lcars_panel.schema.json diff --git a/blocks/lcars_sidebar.ninjatpl b/blocks/lcars_sidebar.ninjatpl new file mode 100644 index 0000000..8634fe4 --- /dev/null +++ b/blocks/lcars_sidebar.ninjatpl @@ -0,0 +1,23 @@ + diff --git a/schemas/lcars_sidebar.schema.json b/blocks/lcars_sidebar.schema.json similarity index 100% rename from schemas/lcars_sidebar.schema.json rename to blocks/lcars_sidebar.schema.json diff --git a/embed.go b/embed.go deleted file mode 100644 index 0a6316f..0000000 --- a/embed.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "embed" - "io/fs" - "net/http" - - "git.dev.alexdunmow.com/block/core/plugin" -) - -//go:embed assets/* -var assetsFS embed.FS - -//go:embed schemas/* -var schemasFS embed.FS - -//go:embed templates/* -var templateFS embed.FS - -//go:embed presets.json -var presetsData []byte - -//go:embed fonts.json -var fontsData []byte - -//go:embed plugin.mod -var pluginModBytes []byte - -func Assets() fs.FS { - sub, _ := fs.Sub(assetsFS, "assets") - return sub -} - -func SchemasFS() fs.FS { - sub, _ := fs.Sub(schemasFS, "schemas") - return sub -} - -func TemplatesFS() fs.FS { - sub, _ := fs.Sub(templateFS, "templates") - return sub -} - -func AssetsHandler() http.Handler { - return http.FileServer(http.FS(Assets())) -} - -func ThemePresets() []byte { return presetsData } - -func BundledFonts() []byte { return fontsData } - -func ThemeCSSManifest() *plugin.CSSManifest { - css, err := assetsFS.ReadFile("assets/style.css") - if err != nil { - return &plugin.CSSManifest{} - } - return &plugin.CSSManifest{ - InputCSSAppend: string(css), - } -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 0e4bb91..0000000 --- a/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module git.dev.alexdunmow.com/block/lcars - -go 1.26.4 - -require git.dev.alexdunmow.com/block/core v0.15.2 - -require ( - connectrpc.com/connect v1.20.0 // indirect - github.com/BurntSushi/toml v1.6.0 // indirect - github.com/a-h/templ v0.3.1020 // indirect - github.com/flosch/pongo2/v6 v6.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.9.2 // indirect - golang.org/x/mod v0.34.0 // indirect - golang.org/x/text v0.36.0 // indirect - google.golang.org/protobuf v1.36.11 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index da21199..0000000 --- a/go.sum +++ /dev/null @@ -1,56 +0,0 @@ -connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ= -connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4= -git.dev.alexdunmow.com/block/core v0.15.2 h1:qTjJxa1pClxwehkdTxXiJDpHQLr5DoXBUCa40QRO0L8= -git.dev.alexdunmow.com/block/core v0.15.2/go.mod h1:A+mgA9oeWoPhXruv4Mjpywwl2A9B5I3cKzlJjalBdlE= -github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= -github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw= -github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/flosch/pongo2/v6 v6.1.0 h1:A/NJbrQJJD2B2mbpw3DRFwBYG0xpCr3vwFlEr46y1HQ= -github.com/flosch/pongo2/v6 v6.1.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= -github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= -github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU= -github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go deleted file mode 100644 index 7364ea6..0000000 --- a/main.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build wasip1 - -// Package main compiles the lcars theme to a wasip1 reactor-mode wasm guest -// (WO-WZ-015). The .so build path is retired; `ninja plugin build` produces the -// .bnp artifact the registry serves. -// -// Reactor mode: the host runs `_initialize` once per pooled instance, which -// runs this init func (hence wasmguest.Serve) before any bn_invoke. Serve is -// non-blocking; all theme work then arrives over the ABI hook calls. main is -// never called. -package main - -import "git.dev.alexdunmow.com/block/core/plugin/wasmguest" - -func init() { wasmguest.Serve(Registration) } - -func main() {} // never called — reactor mode diff --git a/manifest.yaml b/manifest.yaml new file mode 100644 index 0000000..ed6414a --- /dev/null +++ b/manifest.yaml @@ -0,0 +1,458 @@ +# LCARS theme — codeless .bnp manifest (WO-WZ-021 Phase B1). +# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm). +# This theme was previously a pongo2 wasm guest (it shipped the pongo engine +# inside the guest); the codeless path renders the SAME .ninjatpl sources +# host-side via cms/backend/plugin/pongoengine, so no engine ships here. +theme_presets: presets.json +bundled_fonts: fonts.json +master_pages: master_pages.json + +system_templates: + - key: lcars + title: LCARS + description: "Star Trek LCARS computer interface theme" + +page_templates: + - system: lcars + key: default + title: Standard Display + description: "Classic LCARS layout with sidebar and header frame" + slots: [header, sidebar, main, footer] + - system: lcars + key: full-display + title: Full Display + description: "Full-width LCARS display without sidebar" + slots: [header, main, footer] + +template_overrides: + - { template: lcars, block: heading } + - { template: lcars, block: text } + +email_wrappers: + - lcars + +css: + input_css_append: | + /* ============================================================ + LCARS Theme — Star Trek Computer Interface + ============================================================ */ + + /* --- Typography --- */ + + .lcars-page { + font-family: 'Antonio', sans-serif; + letter-spacing: 0.05em; + } + + /* --- Color Utilities --- */ + + .lcars-bg-primary { background-color: hsl(var(--primary)); } + .lcars-bg-secondary { background-color: hsl(var(--secondary)); } + .lcars-bg-accent { background-color: hsl(var(--accent)); } + .lcars-bg-muted { background-color: hsl(var(--muted)); } + .lcars-text-primary { color: hsl(var(--primary)); } + .lcars-text-secondary { color: hsl(var(--secondary)); } + .lcars-text-accent { color: hsl(var(--accent)); } + + /* --- Frame Layout --- */ + + .lcars-frame { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0.5rem; + gap: 0.25rem; + } + + .lcars-body { + display: grid; + grid-template-columns: 1fr; + grid-template-rows: auto 1fr auto; + flex: 1; + gap: 0.25rem; + } + + .lcars-content-area { + display: grid; + grid-template-columns: 12rem 0.25rem 1fr; + gap: 0; + flex: 1; + } + + .lcars-frame-full .lcars-body-full { + display: flex; + flex-direction: column; + flex: 1; + gap: 0.25rem; + } + + /* --- Elbow Brackets --- */ + + .lcars-elbow-top, + .lcars-elbow-bottom { + display: flex; + align-items: stretch; + height: 2rem; + } + + .lcars-elbow-corner { + width: 12rem; + min-width: 12rem; + background-color: hsl(var(--primary)); + } + + .lcars-elbow-tl { + border-bottom-left-radius: 0; + border-bottom-right-radius: 2rem; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + .lcars-elbow-bl { + border-top-left-radius: 0; + border-top-right-radius: 2rem; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + + .lcars-bar { + flex: 1; + margin-left: 0.25rem; + } + + .lcars-bar-top { + background-color: hsl(var(--secondary)); + border-radius: 0 0 1rem 0; + } + + .lcars-bar-bottom { + background-color: hsl(var(--secondary)); + border-radius: 0 1rem 0 0; + } + + .lcars-bar-accent { + height: 0.5rem; + background: linear-gradient( + to right, + hsl(var(--primary)) 0%, + hsl(var(--primary)) 30%, + hsl(var(--secondary)) 30%, + hsl(var(--secondary)) 60%, + hsl(var(--accent)) 60%, + hsl(var(--accent)) 100% + ); + border-radius: 0.25rem; + } + + /* --- Divider (between sidebar and main) --- */ + + .lcars-divider { + background-color: hsl(var(--primary)); + width: 0.25rem; + } + + /* --- Sidebar --- */ + + .lcars-sidebar-area { + display: flex; + flex-direction: column; + overflow: hidden; + } + + .lcars-sidebar { + display: flex; + flex-direction: column; + gap: 0.25rem; + padding: 0.25rem 0; + } + + .lcars-sidebar-btn { + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0.5rem 1rem; + border-radius: 0 1.5rem 1.5rem 0; + text-decoration: none; + color: hsl(var(--background)); + font-weight: 700; + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.1em; + transition: filter 0.15s ease; + min-height: 2.5rem; + } + + .lcars-sidebar-btn:hover { + filter: brightness(1.2); + } + + .lcars-sidebar-btn-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + /* --- Main Content --- */ + + .lcars-main-area { + padding: 1.5rem 2rem; + } + + .lcars-main-full { + flex: 1; + padding: 2rem; + } + + .lcars-empty-state { + display: flex; + align-items: center; + justify-content: center; + min-height: 20rem; + } + + /* --- Header Block --- */ + + .lcars-header-bar { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0; + } + + .lcars-header-pill { + width: 6rem; + height: 2.5rem; + border-radius: 1.25rem; + flex-shrink: 0; + } + + .lcars-header-title-area { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + } + + .lcars-title { + font-size: 2rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + color: hsl(var(--primary)); + line-height: 1; + margin: 0; + } + + .lcars-subtitle { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.2em; + color: hsl(var(--secondary)); + } + + .lcars-header-indicators { + display: flex; + align-items: center; + gap: 1rem; + flex-shrink: 0; + } + + .lcars-stardate { + font-size: 0.875rem; + font-weight: 600; + color: hsl(var(--accent)); + text-transform: uppercase; + letter-spacing: 0.1em; + } + + .lcars-status { + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + padding: 0.25rem 0.75rem; + border-radius: 0.75rem; + } + + .lcars-status-online { + background-color: hsl(var(--primary)); + color: hsl(var(--background)); + animation: lcars-pulse 3s ease-in-out infinite; + } + + .lcars-status-standby { + background-color: hsl(var(--secondary)); + color: hsl(var(--background)); + } + + .lcars-status-alert { + background-color: hsl(var(--destructive)); + color: hsl(var(--destructive-foreground)); + animation: lcars-blink 1s step-end infinite; + } + + .lcars-status-offline { + background-color: hsl(var(--muted)); + color: hsl(var(--muted-foreground)); + } + + .lcars-editor-badge { + position: absolute; + top: 0.25rem; + right: 0.5rem; + font-size: 0.625rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.2em; + color: hsl(var(--accent)); + opacity: 0.7; + } + + /* --- Panel Block --- */ + + .lcars-panel { + border-left: 0.25rem solid hsl(var(--primary)); + margin: 1rem 0; + } + + .lcars-panel-secondary { border-left-color: hsl(var(--secondary)); } + .lcars-panel-accent { border-left-color: hsl(var(--accent)); } + + .lcars-panel-header { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; + } + + .lcars-panel-header-pill { + width: 3rem; + height: 1.25rem; + background-color: inherit; + border-radius: 0.625rem; + background-color: hsl(var(--primary)); + } + + .lcars-panel-secondary .lcars-panel-header-pill { background-color: hsl(var(--secondary)); } + .lcars-panel-accent .lcars-panel-header-pill { background-color: hsl(var(--accent)); } + + .lcars-panel-title { + font-size: 0.875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + color: hsl(var(--foreground)); + white-space: nowrap; + } + + .lcars-panel-header-bar { + flex: 1; + height: 0.125rem; + background-color: hsl(var(--border)); + } + + .lcars-panel-body { + padding: 0.75rem 1rem 0.75rem 1.25rem; + } + + /* --- Heading Override --- */ + + .lcars-heading { + font-family: 'Antonio', sans-serif; + text-transform: uppercase; + letter-spacing: 0.12em; + color: hsl(var(--primary)); + border-bottom: 0.125rem solid hsl(var(--primary)); + padding-bottom: 0.25rem; + margin-bottom: 1rem; + } + + .lcars-heading-1 { font-size: 2.25rem; } + .lcars-heading-2 { font-size: 1.75rem; } + .lcars-heading-3 { font-size: 1.375rem; } + .lcars-heading-4 { font-size: 1.125rem; } + + /* --- Text Override --- */ + + .lcars-prose { + color: hsl(var(--foreground)); + line-height: 1.7; + font-size: 1rem; + } + + .lcars-prose a { + color: hsl(var(--secondary)); + text-decoration: underline; + text-underline-offset: 0.2em; + } + + .lcars-prose a:hover { + color: hsl(var(--primary)); + } + + .lcars-prose strong { + color: hsl(var(--primary)); + } + + .lcars-prose code { + background-color: hsl(var(--muted)); + padding: 0.125rem 0.375rem; + border-radius: 0.25rem; + font-size: 0.875em; + } + + /* --- Footer --- */ + + .lcars-footer-area { + padding: 0.5rem 0; + } + + /* --- Animations --- */ + + @keyframes lcars-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } + } + + @keyframes lcars-blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } + } + + /* --- Responsive --- */ + + @media (max-width: 768px) { + .lcars-content-area { + grid-template-columns: 1fr; + } + + .lcars-sidebar-area { + display: none; + } + + .lcars-divider { + display: none; + } + + .lcars-elbow-corner { + width: 4rem; + min-width: 4rem; + } + + .lcars-sidebar-btn { + border-radius: 1.5rem; + justify-content: center; + } + + .lcars-header-pill { + width: 3rem; + } + + .lcars-title { + font-size: 1.5rem; + } + + .lcars-main-area { + padding: 1rem; + } + } diff --git a/master_pages.go b/master_pages.go deleted file mode 100644 index 15451c5..0000000 --- a/master_pages.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import "git.dev.alexdunmow.com/block/core/plugin" - -func DefaultMasterPages() []plugin.MasterPageDefinition { - return []plugin.MasterPageDefinition{ - { - Key: "lcars:standard-display", - Title: "LCARS Standard Display", - PageTemplates: []string{"default"}, - Blocks: []plugin.MasterPageBlock{ - { - BlockKey: "lcars:lcars_header", - Title: "LCARS Header", - Content: map[string]any{"title": "LCARS", "subtitle": "Library Computer Access/Retrieval System"}, - Slot: "header", - SortOrder: 0, - }, - { - BlockKey: "lcars:lcars_sidebar", - Title: "LCARS Sidebar", - Content: map[string]any{}, - Slot: "sidebar", - SortOrder: 0, - }, - { - BlockKey: "slot", - Title: "Main Content Slot", - Content: map[string]any{"slotName": "main", "placeholder": "Enter display data…"}, - Slot: "main", - SortOrder: 0, - }, - }, - }, - { - Key: "lcars:full-display", - Title: "LCARS Full Display", - PageTemplates: []string{"full-display"}, - Blocks: []plugin.MasterPageBlock{ - { - BlockKey: "lcars:lcars_header", - Title: "LCARS Header", - Content: map[string]any{"title": "LCARS", "subtitle": "Main Viewer"}, - Slot: "header", - SortOrder: 0, - }, - { - BlockKey: "slot", - Title: "Main Content Slot", - Content: map[string]any{"slotName": "main", "placeholder": "Enter display data…"}, - Slot: "main", - SortOrder: 0, - }, - }, - }, - } -} diff --git a/master_pages.json b/master_pages.json new file mode 100644 index 0000000..413ca04 --- /dev/null +++ b/master_pages.json @@ -0,0 +1,21 @@ +[ + { + "key": "lcars:standard-display", + "title": "LCARS Standard Display", + "page_templates": ["default"], + "blocks": [ + { "block_key": "lcars:lcars_header", "title": "LCARS Header", "content": { "title": "LCARS", "subtitle": "Library Computer Access/Retrieval System" }, "slot": "header", "sort_order": 0 }, + { "block_key": "lcars:lcars_sidebar", "title": "LCARS Sidebar", "content": {}, "slot": "sidebar", "sort_order": 0 }, + { "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main", "placeholder": "Enter display data…" }, "slot": "main", "sort_order": 0 } + ] + }, + { + "key": "lcars:full-display", + "title": "LCARS Full Display", + "page_templates": ["full-display"], + "blocks": [ + { "block_key": "lcars:lcars_header", "title": "LCARS Header", "content": { "title": "LCARS", "subtitle": "Main Viewer" }, "slot": "header", "sort_order": 0 }, + { "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main", "placeholder": "Enter display data…" }, "slot": "main", "sort_order": 0 } + ] + } +] diff --git a/plugin.mod b/plugin.mod index abdd2b8..c66eb4e 100644 --- a/plugin.mod +++ b/plugin.mod @@ -2,11 +2,8 @@ name = "lcars" display_name = "LCARS" scope = "@themes" -version = "0.2.9" +version = "0.3.0" description = "Star Trek-inspired LCARS interface theme for BlockNinja — angular panels, bold accent colors, and the distinctive curved frame layout of the 24th-century starship computer." kind = "theme" categories = ["templates"] tags = ["retro-futurist", "scifi", "lcars", "demo", "showcase", "angular", "amber"] - -[compatibility] -block_core = ">=0.15.0 <0.16.0" diff --git a/register.go b/register.go deleted file mode 100644 index 372cd8f..0000000 --- a/register.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "git.dev.alexdunmow.com/block/core/blocks" - "git.dev.alexdunmow.com/block/core/templates" - "git.dev.alexdunmow.com/block/core/templates/pongo" -) - -var engine = pongo.NewEngine(TemplatesFS(), "/templates/lcars/style.css") - -func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error { - tr.RegisterSystemTemplate(templates.SystemTemplateMeta{ - Key: "lcars", - Title: "LCARS", - Description: "Star Trek LCARS computer interface theme", - }) - - if err := tr.RegisterPageTemplate("lcars", templates.PageTemplateMeta{ - Key: "default", - Title: "Standard Display", - Description: "Classic LCARS layout with sidebar and header frame", - Slots: []string{"header", "sidebar", "main", "footer"}, - }, engine.MustPageTemplate("default.html")); err != nil { - return err - } - - if err := tr.RegisterPageTemplate("lcars", templates.PageTemplateMeta{ - Key: "full-display", - Title: "Full Display", - Description: "Full-width LCARS display without sidebar", - Slots: []string{"header", "main", "footer"}, - }, engine.MustPageTemplate("full_display.html")); err != nil { - return err - } - - if err := br.LoadSchemasFromFS(SchemasFS()); err != nil { - return err - } - - br.Register(LCARSHeaderMeta, engine.MustBlockTemplateWithDefaults("blocks/header.html", headerDefaults)) - br.Register(LCARSSidebarMeta, engine.MustBlockTemplateWithDefaults("blocks/sidebar.html", sidebarDefaults)) - br.Register(LCARSPanelMeta, engine.MustBlockTemplate("blocks/panel.html")) - - br.RegisterTemplateOverride("lcars", "heading", engine.MustTemplateOverride("blocks/heading_override.html")) - br.RegisterTemplateOverride("lcars", "text", engine.MustTemplateOverride("blocks/text_override.html")) - - tr.RegisterEmailWrapper("lcars", engine.MustEmailWrapper("email_wrapper.html")) - - return nil -} diff --git a/registration.go b/registration.go deleted file mode 100644 index 127bf8b..0000000 --- a/registration.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "io/fs" - "net/http" - - "git.dev.alexdunmow.com/block/core/blocks" - "git.dev.alexdunmow.com/block/core/plugin" - "git.dev.alexdunmow.com/block/core/templates" -) - -var Registration = plugin.PluginRegistration{ - Name: "lcars", - Version: plugin.ParseModVersion(pluginModBytes), - Register: func(tr templates.TemplateRegistry, br blocks.BlockRegistry) error { - return Register(tr, br) - }, - Assets: func() http.Handler { return AssetsHandler() }, - Schemas: func() fs.FS { return SchemasFS() }, - ThemePresets: func() []byte { return ThemePresets() }, - BundledFonts: func() []byte { return BundledFonts() }, - MasterPages: func() []plugin.MasterPageDefinition { return DefaultMasterPages() }, - CSSManifest: func() *plugin.CSSManifest { return ThemeCSSManifest() }, -} diff --git a/templates/blocks/sidebar.html b/templates/blocks/sidebar.html deleted file mode 100644 index 7e72262..0000000 --- a/templates/blocks/sidebar.html +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/templates/email_wrapper.html b/templates/email/lcars.ninjatpl similarity index 100% rename from templates/email_wrapper.html rename to templates/email/lcars.ninjatpl diff --git a/templates/default.html b/templates/lcars/default.ninjatpl similarity index 100% rename from templates/default.html rename to templates/lcars/default.ninjatpl diff --git a/templates/full_display.html b/templates/lcars/full-display.ninjatpl similarity index 100% rename from templates/full_display.html rename to templates/lcars/full-display.ninjatpl diff --git a/templates/blocks/heading_override.html b/templates/overrides/lcars/heading.ninjatpl similarity index 100% rename from templates/blocks/heading_override.html rename to templates/overrides/lcars/heading.ninjatpl diff --git a/templates/blocks/text_override.html b/templates/overrides/lcars/text.ninjatpl similarity index 100% rename from templates/blocks/text_override.html rename to templates/overrides/lcars/text.ninjatpl