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>
126 lines
9.9 KiB
Markdown
126 lines
9.9 KiB
Markdown
# Corporate Modernist — build report
|
||
|
||
## What landed
|
||
|
||
### Module / metadata
|
||
- `go.mod` — `git.dev.alexdunmow.com/block/themes/corporate-modernist`, `go 1.26.4`, `block/core v0.11.1`, `templ v0.3.1020`. No `replace` directives.
|
||
- `plugin.mod` — `name = "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
|
||
- `heading` — `CorporateModernistHeadingBlock` / `heading_override.templ`: tighter tracking, accent underline on H2.
|
||
- `text` — `CorporateModernistTextBlock` / `text_override.templ`: Inter at 17/28, tabular figures, hanging punctuation.
|
||
- `button` — `CorporateModernistButtonBlock` / `button_override.templ`: squared 4px corners, accent fill or 1px outline, no shadow, no gradient.
|
||
- `card` — `CorporateModernistCardBlock` / `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-placeholder` → `cm-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-hero` … `06-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 banner** — `marketplace/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.
|