From 1bebbea5ad84818810cd1534f3aae55ab72c304f Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sat, 6 Jun 2026 14:11:40 +0800 Subject: [PATCH] initial: theme plugin noir Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/noir. Co-Authored-By: Claude Opus 4.7 --- .gitignore | 5 + BUILD_REPORT.md | 143 +++++++ Makefile | 31 ++ RECOMMENDED_FONTS.md | 46 +++ assets/.gitkeep | 0 assets/style.css | 234 +++++++++++ caption_strip.go | 36 ++ caption_strip.templ | 9 + caption_strip_templ.go | 67 ++++ case_study.go | 48 +++ case_study.templ | 53 +++ case_study_templ.go | 182 +++++++++ contact_sheet.go | 55 +++ contact_sheet.templ | 39 ++ contact_sheet_templ.go | 152 +++++++ email_wrapper.templ | 136 +++++++ email_wrapper_templ.go | 401 +++++++++++++++++++ embed.go | 64 +++ fonts.json | 1 + footer.go | 48 +++ footer.templ | 33 ++ footer_templ.go | 98 +++++ go.mod | 20 + go.sum | 42 ++ helpers.go | 75 ++++ image_pair.go | 38 ++ image_pair.templ | 30 ++ image_pair_templ.go | 142 +++++++ lightbox_gallery.go | 45 +++ lightbox_gallery.templ | 87 ++++ lightbox_gallery_templ.go | 229 +++++++++++ overrides.go | 99 +++++ overrides.templ | 87 ++++ overrides_templ.go | 577 +++++++++++++++++++++++++++ plugin.mod | 12 + presets.json | 110 +++++ register.go | 176 ++++++++ registration.go | 25 ++ schemas/caption_strip.schema.json | 20 + schemas/case_study.schema.json | 48 +++ schemas/contact_sheet.schema.json | 39 ++ schemas/footer.schema.json | 40 ++ schemas/image_pair.schema.json | 26 ++ schemas/lightbox_gallery.schema.json | 41 ++ template.templ | 288 +++++++++++++ template_templ.go | 548 +++++++++++++++++++++++++ 46 files changed, 4725 insertions(+) create mode 100644 .gitignore create mode 100644 BUILD_REPORT.md create mode 100644 Makefile create mode 100644 RECOMMENDED_FONTS.md create mode 100644 assets/.gitkeep create mode 100644 assets/style.css create mode 100644 caption_strip.go create mode 100644 caption_strip.templ create mode 100644 caption_strip_templ.go create mode 100644 case_study.go create mode 100644 case_study.templ create mode 100644 case_study_templ.go create mode 100644 contact_sheet.go create mode 100644 contact_sheet.templ create mode 100644 contact_sheet_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 helpers.go create mode 100644 image_pair.go create mode 100644 image_pair.templ create mode 100644 image_pair_templ.go create mode 100644 lightbox_gallery.go create mode 100644 lightbox_gallery.templ create mode 100644 lightbox_gallery_templ.go create mode 100644 overrides.go create mode 100644 overrides.templ create mode 100644 overrides_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/caption_strip.schema.json create mode 100644 schemas/case_study.schema.json create mode 100644 schemas/contact_sheet.schema.json create mode 100644 schemas/footer.schema.json create mode 100644 schemas/image_pair.schema.json create mode 100644 schemas/lightbox_gallery.schema.json create mode 100644 template.templ create mode 100644 template_templ.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f780e6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.so +*.test +tmp/ +.idea/ +.vscode/ diff --git a/BUILD_REPORT.md b/BUILD_REPORT.md new file mode 100644 index 0000000..829fd5a --- /dev/null +++ b/BUILD_REPORT.md @@ -0,0 +1,143 @@ +# Noir — Build Report + +Implementation pass: wave-1 scaffold of the `noir` theme plugin. + +Plugin slug: `noir` +Module path: `git.dev.alexdunmow.com/block/themes/noir` +SDK pinned to: `git.dev.alexdunmow.com/block/core v0.11.1` +Go directive: `go 1.26.4` +Tech style: templ (per spec §11) + +## What landed + +### Metadata & build glue +- `plugin.mod` — name, display_name, scope `@themes`, kind `theme`, version `0.1.0`, categories `["templates", "media"]`, tags array (8 entries, includes the four spec-required minimums), `[compatibility] block_core = ">=0.11.0 <0.12.0"`. +- `go.mod` — pins `block/core v0.11.1` and `templ v0.3.1020`, mirrors gotham's indirect set, no `replace` directives. +- `Makefile` — local-only targets (`all`, `templ`, `clean`). No `rebuild` target. Default builds `noir.so` via `CGO_ENABLED=1 go build -buildmode=plugin`. +- `embed.go` — five canonical `//go:embed` directives plus a `ThemeCSSManifest()` that surfaces `assets/style.css` through `CSSManifest.InputCSSAppend` so the custom utilities (`.tracked-mono`, `.bleed`, `.hairline`, sprocket motif, lightbox overlay) survive Tailwind's content scanner. +- `registration.go` — exports `var Registration plugin.PluginRegistration` with all functions wired. + +### System & page templates +- `tr.RegisterSystemTemplate({Key: "noir", …})` — exactly once. +- Four `tr.RegisterPageTemplate("noir", …)` calls with the spec's slot sets: + - `default` — `["header", "main", "footer"]` + - `landing` — `["hero", "main", "cta", "footer"]` + - `article` — `["header", "main", "aside", "footer"]` + - `full-width` — `["header", "main", "footer"]` +- Each page renderer lives in `template.templ` and consumes the shared `bn.Head` / `bn.AdminBypassBanner` / `bn.BodyEnd` helpers, mirroring gotham. + +### Blocks (6 theme-specific) +- `noir:lightbox_gallery` — grid + vanilla keyboard-aware lightbox overlay (Esc + Enter/Space, click-outside dismiss, ARIA-modal). +- `noir:contact_sheet` — sprocket-framed numbered grid; `data-frame-number` attribute on each frame for UAT §13.9. +- `noir:case_study` — sticky meta rail (client / year / credits) + image stack. +- `noir:caption_strip` — 10px mono full-width strip. +- `noir:image_pair` — 50/50 diptych with shared caption. +- `noir:footer` — dissolved-rail footer with optional social links. + +All registered with `Source: "noir"` and the appropriate `blocks.Category*` constant. + +### Schemas (6, draft-07) +- Property names exactly match the Go `content["…"]` reads in each block. +- Every `x-editor` value comes from the allowed set: + `text`, `media`, `select`, `number`, `array`, `link`. +- `lightbox_gallery.columns` uses `x-editor: select` with `enum: [2, 3, 4]` (spec §8). +- `case_study.year` uses `x-editor: number` (spec §8). +- `case_study.credits` is `array`; `case_study.images` is `array` per spec §8. +- `footer.social` is `array` with `text`/`url` fields per spec §8. + +### Template overrides (5) +- `RegisterTemplateOverride("noir", …)` for `heading`, `text`, `image`, `button`, `card` — exactly five calls, per UAT §3. +- Display headings render with `font-family: var(--font-heading)` and no underline. +- Button override is hairline 1px outline, transparent background, hover inverts to `--primary` / `--primary-foreground`. +- Card override is transparent with hairline border only. +- Image override emits the `.bleed` utility for full-bleed and a `figcaption.tracked-mono` for the mono caption. + +### Email wrapper +- `tr.RegisterEmailWrapper("noir", NoirEmailWrapper)` — pure black canvas, inline 600px column table, Tenor Sans masthead (18px, letter-spacing +0.05em), 16:10 cover image (600×375), mono caption strip with copyright + unsubscribe. +- All inline styles; no `