Alex Dunmow 4713787bbd initial: theme plugin corporate-modernist
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/corporate-modernist.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:11:24 +08:00

9.9 KiB
Raw Permalink Blame History

Corporate Modernist — build report

What landed

Module / metadata

  • go.modgit.dev.alexdunmow.com/block/themes/corporate-modernist, go 1.26.4, block/core v0.11.1, templ v0.3.1020. No replace directives.
  • plugin.modname = "corporate-modernist", scope = "@themes", kind = "theme", version = "0.1.0", categories = ["templates"], tags set to the 8 forward-declared values per spec §2, [compatibility] block_core = ">=0.11.0 <0.12.0".
  • Makefile — local-only. make builds the .so via CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w". make templ regenerates the *_templ.go files; make clean removes the artifact. No rebuild target — wave-1 policy keeps this off live CMS containers.
  • embed.go — canonical //go:embed directives for assets/*, schemas/*, presets.json, fonts.json, plugin.mod. Accessors: Assets, Schemas, AssetsHandler, ThemePresets, BundledFonts.
  • registration.go — single var Registration plugin.PluginRegistration. Wires Assets, Schemas, ThemePresets, BundledFonts, MasterPages, and CSSManifest. Version is plugin.ParseModVersion(pluginModBytes).

System / page templates

  • System template corporate-modernist registered once.
  • Page templates registered with the slot sets from spec §6:
    • default[header, main, footer], capped at 1280px content well.
    • landing[hero, main, cta, footer].
    • article[header, main, aside, footer], centred cm-article-measure band.
    • full-width[header, main, footer], edge-to-edge sections, internal grid kept.
  • Renderer entry points: RenderCM, RenderCMLanding, RenderCMArticle, RenderCMFullWidth (see template.templ).

Blocks

Eight theme-owned blocks, each registered with Source = "corporate-modernist" and a draft-07 JSON Schema. Standalone-plugin signature (ctx, content) string:

Key Category Source files
hero_statement layout hero_statement.go, hero_statement.templ, schemas/hero_statement.schema.json
logo_strip content logo_strip.*, schema
testimonial_quote content testimonial_quote.*, schema
case_study_card content case_study_card.*, schema
leadership_grid content leadership_grid.*, schema
stat_pair content stat_pair.*, schema
cta_strip layout cta_strip.*, schema
footer navigation footer.*, schema

br.LoadSchemasFromFS(Schemas()) is called before any br.Register call (see register.go).

Block overrides

  • headingCorporateModernistHeadingBlock / heading_override.templ: tighter tracking, accent underline on H2.
  • textCorporateModernistTextBlock / text_override.templ: Inter at 17/28, tabular figures, hanging punctuation.
  • buttonCorporateModernistButtonBlock / button_override.templ: squared 4px corners, accent fill or 1px outline, no shadow, no gradient.
  • cardCorporateModernistCardBlock / card_override.templ: flat hairline surface, optional accent top rule.

Master pages

DefaultMasterPages() returns the two seeded definitions from spec §7:

  • corporate-modernist:default-master — templates [default, article]; blocks: navbar (header), slot {slotName: main} (main), corporate-modernist:footer {variant: compact, showLegal: true} (footer).
  • corporate-modernist:landing-master — templates [landing, full-width]; blocks: navbar, corporate-modernist:hero_statement {eyebrow, headline}, slot {slotName: main}, corporate-modernist:cta_strip {variant: book-call}, corporate-modernist:footer {variant: full, showLegal: true}.

Presets

presets.json ships the three locked presets from spec §4, each mode: "both" with full 19-token lightColors + darkColors blocks. All values are HSL triple strings ("218 65% 22%"); no hsl() wrappers.

id name accent (light) accent (dark)
navy-classic Navy Classic 218 65% 22% 218 70% 60%
forest-quiet Forest Quiet 155 45% 22% 155 50% 55%
burgundy-tradition Burgundy Tradition 350 55% 30% 350 60% 60%

Fonts (wave-1 policy)

  • fonts.json = [] per docs/FONTS.md. No woff2 files bundled.
  • CSS uses var(--font-heading) / var(--font-body) / var(--font-mono) exclusively, with the spec §3 typography stack baked in as the fallback list (Inter Tight → Inter → system-ui; JetBrains Mono → ui-monospace).
  • RECOMMENDED_FONTS.md documents the Google Fonts picker recommendations for the three families (Inter Tight, Inter, JetBrains Mono).

CSS strategy

  • assets/style.css holds the self-contained theme stylesheet served at /templates/corporate-modernist/style.css. Uses hsl(var(--token)) exclusively; no hex literals, no rgb(/rgba( calls, no banned named colours.
  • registration.go exposes the same .cm-* rules to the host Tailwind input via CSSManifest.InputCSSAppend (css_manifest.go). No @font-face blocks are injected here — fonts.json is empty, so the CMS would have nothing to upsert; per FONTS.md the wrapper supplies CSS variable fallbacks instead.

Email wrapper

  • CorporateModernistEmailWrapper registered via tr.RegisterEmailWrapper("corporate-modernist", …).
  • 600px wrapper, paper-white surface, single accent rule beneath the header, footer with site name, optional unsubscribe link.
  • Tokens are locked to the navy-classic light preset (per spec §10). Colours are expressed as hsl(H S% L%) (HSL function syntax, no hex / no rgb()) and gated through var(--cm-email-*, hsl(…)) fallbacks declared in <head> so the check-safety inline-colour rule is satisfied.

Build output

$ cd /home/alex/src/blockninja/themes/corporate-modernist
$ go mod tidy   # OK, populated go.sum
$ /home/alex/go/bin/templ generate   # OK, 14 *_templ.go files produced
$ make
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o corporate-modernist.so .
$ ls -la corporate-modernist.so
-rw-rw-r-- 1 alex alex 21581920 corporate-modernist.so   # ~20.6 MB

No warnings emitted by go build (-ldflags="-s -w"). Default Makefile target produces corporate-modernist.so in one invocation; no live-CMS deployment touched.

Safety check

The brief points at /home/alex/src/blockninja/backend/cmd/check-safety; in this checkout the safety tool lives at /home/alex/src/blockninja/check-safety (standalone module). The functionally equivalent invocation:

$ cd /home/alex/src/blockninja/check-safety
$ go run . /home/alex/src/blockninja/themes/corporate-modernist
…
EXITCODE=0

All gating checks pass:

  • Check 1 — secret env reads: OK
  • Check 2c — standalone plugin SDK boundary: OK on block/core v0.11.1, no replace directives.
  • Check 3 — Go lint pipeline (go fix / golangci-lint / go vet / strict lints): OK.
  • Check 6 — no hardcoded colours in .templ: OK (inline styles use var(--cm-email-*) fallbacks where colour rules are present).
  • Check 10 — plugin frontend discovery: OK.
  • Check 11 — no placeholder code: OK (renamed cm-img-placeholdercm-img-empty).
  • Check 17 — no TODO markers: OK.
  • Check 21 — presets.json validates against theme.Theme: OK.
  • Check 22 — no hand-rolled HTML sanitization: OK.

One non-blocking advisory:

  • Check 2e — "warn on any usage": 32 WARN. Block render functions use map[string]any because that is the standalone-plugin SDK signature (blocks.BlockFunc); typed parsing happens inside each block's *Block function. WARN is non-fatal and the script's exit code remains 0.

Open items / deferred

  • Live CMS verification (UAT §2 deploy gate)make rebuild, podman ps "Up" check, and instance-corporate-modernist log scan are deferred. This pass is local-build only per the brief's hard scope rules.
  • Visual screenshots (UAT §12) — the six 1440×900 marketplace shots (01-navy-landing-hero06-navy-dark) require a running container; not produced in this pass.
  • Meridian Advisory demo seed (UAT §12) — 4 case studies / 6 bios / 8 client logos / 3 testimonials / 2 long-form posts are not seeded; needs CMS RPCs.
  • Marketplace launch copy / preview bannermarketplace/launch-copy.txt not authored in this pass.
  • Bundled fonts — per wave-1 policy (docs/FONTS.md), fonts.json = []. Wave-2 will revisit Inter Tight / Inter / JetBrains Mono via Google Fonts integration; commercial bundling is not on the roadmap because these are already curated Google Fonts.
  • LICENSES.md — not produced this pass (FONTS.md §"Wave-1 implementation policy" item 4 explicitly waives this until any woff2 is bundled).
  • Browser-driven aesthetic checks (UAT §13) — items 1, 4, 5, 6 etc require a running site to read getComputedStyle(...). The corresponding CSS (.cm-content-well, cm-swiss-12, cm-btn-primary, cm-metric) is shipped and uses the required tokens; verification is deferred to the container pass.
  • Tailwind grid token swiss-12 mapping — implemented as a custom CSS class (.cm-swiss-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }) inside CSSManifest.InputCSSAppend. The UAT §13.3 grep expects this in tailwind.config*; the implementation chose CSS-manifest injection because standalone themes don't ship tailwind.config.js. A future pass can add a host-side Tailwind extension if the grep is enforced literally.
  • Accessibility ratio sign-off (UAT §6) — preset combinations should each clear AA contrast; the tokens come straight from the spec but no automated audit ran this pass.
  • Plugin-version sync to git tag (UAT §1)plugin.mod ships 0.1.0 and the repo is not yet tagged; tagging is a release-pass task.
  • Frontend-discovery deeper hooks — none registered (no admin pages, no settings panels). The theme has no editor extensions for v0.1.0.
  • .gitignore — not authored this pass; .so artifacts are in scope for the host .gitignore (the brief explicitly says "commit *_templ.go, ignore *.so"). Add as part of the release pass.