From 2c0428dce9c2c68f04ebb7318cfb20293c581b65 Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sat, 4 Jul 2026 15:22:57 +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 --- Makefile | 40 +- blocks/blocks.yaml | 42 ++ blocks/caption_strip.ninjatpl | 1 + {schemas => blocks}/caption_strip.schema.json | 0 blocks/case_study.ninjatpl | 1 + {schemas => blocks}/case_study.schema.json | 0 blocks/contact_sheet.ninjatpl | 1 + {schemas => blocks}/contact_sheet.schema.json | 0 blocks/footer.ninjatpl | 1 + {schemas => blocks}/footer.schema.json | 0 blocks/image_pair.ninjatpl | 1 + {schemas => blocks}/image_pair.schema.json | 0 blocks/lightbox_gallery.ninjatpl | 1 + .../lightbox_gallery.schema.json | 0 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 -- footer.go | 48 -- footer.templ | 33 - footer_templ.go | 98 --- go.mod | 20 - go.sum | 46 -- 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 ------- main.go | 17 - manifest.yaml | 279 +++++++++ master_pages.json | 24 + overrides.go | 99 --- overrides.templ | 87 --- overrides_templ.go | 577 ------------------ plugin.mod | 5 +- register.go | 176 ------ registration.go | 25 - template.templ | 288 --------- template_templ.go | 548 ----------------- templates/email/noir.ninjatpl | 52 ++ templates/noir/article.ninjatpl | 68 +++ templates/noir/default.ninjatpl | 65 ++ templates/noir/full-width.ninjatpl | 65 ++ templates/noir/landing.ninjatpl | 64 ++ templates/overrides/noir/button.ninjatpl | 1 + templates/overrides/noir/card.ninjatpl | 1 + templates/overrides/noir/heading.ninjatpl | 1 + templates/overrides/noir/image.ninjatpl | 1 + templates/overrides/noir/text.ninjatpl | 1 + 59 files changed, 689 insertions(+), 3976 deletions(-) create mode 100644 blocks/blocks.yaml create mode 100644 blocks/caption_strip.ninjatpl rename {schemas => blocks}/caption_strip.schema.json (100%) create mode 100644 blocks/case_study.ninjatpl rename {schemas => blocks}/case_study.schema.json (100%) create mode 100644 blocks/contact_sheet.ninjatpl rename {schemas => blocks}/contact_sheet.schema.json (100%) create mode 100644 blocks/footer.ninjatpl rename {schemas => blocks}/footer.schema.json (100%) create mode 100644 blocks/image_pair.ninjatpl rename {schemas => blocks}/image_pair.schema.json (100%) create mode 100644 blocks/lightbox_gallery.ninjatpl rename {schemas => blocks}/lightbox_gallery.schema.json (100%) delete mode 100644 caption_strip.go delete mode 100644 caption_strip.templ delete mode 100644 caption_strip_templ.go delete mode 100644 case_study.go delete mode 100644 case_study.templ delete mode 100644 case_study_templ.go delete mode 100644 contact_sheet.go delete mode 100644 contact_sheet.templ delete mode 100644 contact_sheet_templ.go delete mode 100644 email_wrapper.templ delete mode 100644 email_wrapper_templ.go delete mode 100644 embed.go delete mode 100644 footer.go delete mode 100644 footer.templ delete mode 100644 footer_templ.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 helpers.go delete mode 100644 image_pair.go delete mode 100644 image_pair.templ delete mode 100644 image_pair_templ.go delete mode 100644 lightbox_gallery.go delete mode 100644 lightbox_gallery.templ delete mode 100644 lightbox_gallery_templ.go delete mode 100644 main.go create mode 100644 manifest.yaml create mode 100644 master_pages.json delete mode 100644 overrides.go delete mode 100644 overrides.templ delete mode 100644 overrides_templ.go delete mode 100644 register.go delete mode 100644 registration.go delete mode 100644 template.templ delete mode 100644 template_templ.go create mode 100644 templates/email/noir.ninjatpl create mode 100644 templates/noir/article.ninjatpl create mode 100644 templates/noir/default.ninjatpl create mode 100644 templates/noir/full-width.ninjatpl create mode 100644 templates/noir/landing.ninjatpl create mode 100644 templates/overrides/noir/button.ninjatpl create mode 100644 templates/overrides/noir/card.ninjatpl create mode 100644 templates/overrides/noir/heading.ninjatpl create mode 100644 templates/overrides/noir/image.ninjatpl create mode 100644 templates/overrides/noir/text.ninjatpl diff --git a/Makefile b/Makefile index 60ee2d1..78d592a 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,27 @@ -# noir — build & publish helpers (wasm .bnp workflow) +# noir — 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 noir-.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 noir-.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 := noir 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/blocks.yaml b/blocks/blocks.yaml new file mode 100644 index 0000000..6bae64c --- /dev/null +++ b/blocks/blocks.yaml @@ -0,0 +1,42 @@ +# Noir theme block definitions (codeless .bnp, WO-WZ-021). +# Keys are fully qualified (noir:) because the codeless loader registers +# definitions verbatim — there is no PluginBlockRegistry prefixing in the +# codeless path (unlike the wasm/templ path). The qualified keys match the +# hardcoded data-block attributes and the master_pages.json references. +blocks: + - key: noir:lightbox_gallery + title: Lightbox Gallery + description: Grid of photographs that expand into a full-viewport lightbox overlay on click. + category: content + schema: lightbox_gallery.schema.json + template: lightbox_gallery.ninjatpl + - key: noir:contact_sheet + title: Contact Sheet + description: Numbered photograph frames with sprocket motif evoking a darkroom contact sheet. + category: content + schema: contact_sheet.schema.json + template: contact_sheet.ninjatpl + - key: noir:case_study + title: Project Case Study + description: Long-form project spread with sticky meta rail and image-led prose. + category: layout + schema: case_study.schema.json + template: case_study.ninjatpl + - key: noir:caption_strip + title: Caption Strip + description: Full-width 10px mono caption strip with a label on the left and supporting text on the right. + category: navigation + schema: caption_strip.schema.json + template: caption_strip.ninjatpl + - key: noir:image_pair + title: Image Pair + description: 50/50 photograph diptych with a shared caption beneath both images. + category: content + schema: image_pair.schema.json + template: image_pair.ninjatpl + - key: noir:footer + title: Noir Footer + description: Dissolved bottom rail with optional colophon and social links. + category: layout + schema: footer.schema.json + template: footer.ninjatpl diff --git a/blocks/caption_strip.ninjatpl b/blocks/caption_strip.ninjatpl new file mode 100644 index 0000000..3b0eb98 --- /dev/null +++ b/blocks/caption_strip.ninjatpl @@ -0,0 +1 @@ +
{{ label }}{{ right }}
diff --git a/schemas/caption_strip.schema.json b/blocks/caption_strip.schema.json similarity index 100% rename from schemas/caption_strip.schema.json rename to blocks/caption_strip.schema.json diff --git a/blocks/case_study.ninjatpl b/blocks/case_study.ninjatpl new file mode 100644 index 0000000..5cf74d9 --- /dev/null +++ b/blocks/case_study.ninjatpl @@ -0,0 +1 @@ +
{% if title %}

{{ title }}

{% endif %}{% if images %}
{% for img in images %}{% if img %}
{{ title }}
{% endif %}{% endfor %}
{% else %}
Add photographs to the case study spread.
{% endif %}
diff --git a/schemas/case_study.schema.json b/blocks/case_study.schema.json similarity index 100% rename from schemas/case_study.schema.json rename to blocks/case_study.schema.json diff --git a/blocks/contact_sheet.ninjatpl b/blocks/contact_sheet.ninjatpl new file mode 100644 index 0000000..57132e7 --- /dev/null +++ b/blocks/contact_sheet.ninjatpl @@ -0,0 +1 @@ +
{% if not items %}
Add frames to populate the contact sheet.
{% else %}
{% for item in items %}
{% if item.frame %}{{ item.frame }}{% else %}{% if forloop.Counter < 10 %}0{% endif %}{{ forloop.Counter }}{% endif %}{% if item.image %}{{ item.label }}{% else %}
{% endif %}{% if item.label %}
{{ item.label }}
{% endif %}
{% endfor %}
{% endif %}
diff --git a/schemas/contact_sheet.schema.json b/blocks/contact_sheet.schema.json similarity index 100% rename from schemas/contact_sheet.schema.json rename to blocks/contact_sheet.schema.json diff --git a/blocks/footer.ninjatpl b/blocks/footer.ninjatpl new file mode 100644 index 0000000..d5a64fd --- /dev/null +++ b/blocks/footer.ninjatpl @@ -0,0 +1 @@ +
{% if showColophon != "false" and showColophon != false %}

Designed and printed in the darkroom.

{% else %}{% endif %}{% if social %}{% endif %}
diff --git a/schemas/footer.schema.json b/blocks/footer.schema.json similarity index 100% rename from schemas/footer.schema.json rename to blocks/footer.schema.json diff --git a/blocks/image_pair.ninjatpl b/blocks/image_pair.ninjatpl new file mode 100644 index 0000000..33a9bc3 --- /dev/null +++ b/blocks/image_pair.ninjatpl @@ -0,0 +1 @@ +
{% if left %}
{{ caption }}
{% else %}
{% endif %}{% if right %}
{{ caption }}
{% else %}
{% endif %}
{% if caption %}

{{ caption }}

{% endif %}
diff --git a/schemas/image_pair.schema.json b/blocks/image_pair.schema.json similarity index 100% rename from schemas/image_pair.schema.json rename to blocks/image_pair.schema.json diff --git a/blocks/lightbox_gallery.ninjatpl b/blocks/lightbox_gallery.ninjatpl new file mode 100644 index 0000000..eecb986 --- /dev/null +++ b/blocks/lightbox_gallery.ninjatpl @@ -0,0 +1 @@ +
{% if not items %}
Add photographs to populate the gallery.
{% else %}
{% for item in items %}
{% if item.caption %}
{{ item.caption }}
{% endif %}
{% endfor %}
{% endif %}
diff --git a/schemas/lightbox_gallery.schema.json b/blocks/lightbox_gallery.schema.json similarity index 100% rename from schemas/lightbox_gallery.schema.json rename to blocks/lightbox_gallery.schema.json diff --git a/caption_strip.go b/caption_strip.go deleted file mode 100644 index 80a5dcb..0000000 --- a/caption_strip.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// CaptionStripBlockMeta defines the Noir caption strip block. -var CaptionStripBlockMeta = blocks.BlockMeta{ - Key: "caption_strip", - Title: "Caption Strip", - Description: "Full-width 10px mono caption strip with a label on the left and supporting text on the right.", - Source: "noir", - Category: blocks.CategoryNavigation, -} - -// CaptionStripBlock renders a thin caption strip. -// Content shape: {"label":"INDEX","right":"© Studio"} -func CaptionStripBlock(ctx context.Context, content map[string]any) string { - data := CaptionStripData{ - Label: getString(content, "label"), - Right: getString(content, "right"), - } - - var buf bytes.Buffer - _ = captionStripComponent(data).Render(ctx, &buf) - return buf.String() -} - -// CaptionStripData holds the parsed view-model. -type CaptionStripData struct { - Label string - Right string -} diff --git a/caption_strip.templ b/caption_strip.templ deleted file mode 100644 index a9d4478..0000000 --- a/caption_strip.templ +++ /dev/null @@ -1,9 +0,0 @@ -package main - -// captionStripComponent renders the 10px mono caption strip. -templ captionStripComponent(data CaptionStripData) { -
- { data.Label } - { data.Right } -
-} diff --git a/caption_strip_templ.go b/caption_strip_templ.go deleted file mode 100644 index a1f353a..0000000 --- a/caption_strip_templ.go +++ /dev/null @@ -1,67 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// captionStripComponent renders the 10px mono caption strip. -func captionStripComponent(data CaptionStripData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var2 string - templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Label) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `caption_strip.templ`, Line: 6, Col: 41} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var3 string - templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Right) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `caption_strip.templ`, Line: 7, Col: 41} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/case_study.go b/case_study.go deleted file mode 100644 index 4c651b8..0000000 --- a/case_study.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// CaseStudyBlockMeta defines the Noir long-form project case study block. -var CaseStudyBlockMeta = blocks.BlockMeta{ - Key: "case_study", - Title: "Project Case Study", - Description: "Long-form project spread with sticky meta rail and image-led prose.", - Source: "noir", - Category: blocks.CategoryLayout, -} - -// CaseStudyBlock renders a project case study. -// Content shape: {"title":"...","client":"...","year":2025,"credits":["...","..."],"images":["...","..."]} -func CaseStudyBlock(ctx context.Context, content map[string]any) string { - data := CaseStudyData{ - Title: getString(content, "title"), - Client: getString(content, "client"), - Year: getInt(content, "year", 0), - Credits: getStringSlice(content, "credits"), - } - - for _, img := range getStringSlice(content, "images") { - if img == "" { - continue - } - data.Images = append(data.Images, blocks.ResolveMediaPath(img)) - } - - var buf bytes.Buffer - _ = caseStudyComponent(data).Render(ctx, &buf) - return buf.String() -} - -// CaseStudyData holds the parsed view-model for the case study block. -type CaseStudyData struct { - Title string - Client string - Year int - Credits []string - Images []string -} diff --git a/case_study.templ b/case_study.templ deleted file mode 100644 index 392da96..0000000 --- a/case_study.templ +++ /dev/null @@ -1,53 +0,0 @@ -package main - -// caseStudyComponent renders a project case-study spread with a sticky meta rail. -templ caseStudyComponent(data CaseStudyData) { -
-
- -
- if data.Title != "" { -

- { data.Title } -

- } - if len(data.Images) > 0 { -
- for _, img := range data.Images { -
- { -
- } -
- } else { -
- Add photographs to the case study spread. -
- } -
-
-
-} diff --git a/case_study_templ.go b/case_study_templ.go deleted file mode 100644 index 888d8ef..0000000 --- a/case_study_templ.go +++ /dev/null @@ -1,182 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// caseStudyComponent renders a project case-study spread with a sticky meta rail. -func caseStudyComponent(data CaseStudyData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.Title != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var5 string - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study.templ`, Line: 34, Col: 18} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if len(data.Images) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, img := range data.Images { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
\"")
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
Add photographs to the case study spread.
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/contact_sheet.go b/contact_sheet.go deleted file mode 100644 index 9fcf930..0000000 --- a/contact_sheet.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// ContactSheetBlockMeta defines the Noir contact sheet block. -var ContactSheetBlockMeta = blocks.BlockMeta{ - Key: "contact_sheet", - Title: "Contact Sheet", - Description: "Numbered photograph frames with sprocket motif evoking a darkroom contact sheet.", - Source: "noir", - Category: blocks.CategoryContent, -} - -// ContactSheetBlock renders a contact-sheet grid. -// Content shape: {"items":[{"image":"...","frame":"01","label":"..."}, ...]} -func ContactSheetBlock(ctx context.Context, content map[string]any) string { - items := getSlice(content, "items") - - var frames []ContactFrame - for i, item := range items { - frame := getString(item, "frame") - if frame == "" { - frame = padFrame(i + 1) - } - frames = append(frames, ContactFrame{ - Image: blocks.ResolveMediaPath(getString(item, "image")), - Frame: frame, - Label: getString(item, "label"), - }) - } - - var buf bytes.Buffer - _ = contactSheetComponent(frames).Render(ctx, &buf) - return buf.String() -} - -// ContactFrame represents a single numbered frame in the contact sheet. -type ContactFrame struct { - Image string - Frame string - Label string -} - -// padFrame zero-pads a frame number to two digits ("01", "02", ..., "10"). -func padFrame(n int) string { - if n < 10 { - return "0" + intToString(n) - } - return intToString(n) -} diff --git a/contact_sheet.templ b/contact_sheet.templ deleted file mode 100644 index 1ae785b..0000000 --- a/contact_sheet.templ +++ /dev/null @@ -1,39 +0,0 @@ -package main - -// contactSheetComponent renders the contact sheet grid with sprocket frames. -templ contactSheetComponent(frames []ContactFrame) { -
-
- if len(frames) == 0 { -
- Add frames to populate the contact sheet. -
- } else { -
- for _, frame := range frames { -
- - { frame.Frame } - - if frame.Image != "" { - { - } else { -
- } - if frame.Label != "" { -
- { frame.Label } -
- } -
- } -
- } -
-
-} diff --git a/contact_sheet_templ.go b/contact_sheet_templ.go deleted file mode 100644 index 7a55856..0000000 --- a/contact_sheet_templ.go +++ /dev/null @@ -1,152 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// contactSheetComponent renders the contact sheet grid with sprocket frames. -func contactSheetComponent(frames []ContactFrame) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(frames) == 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Add frames to populate the contact sheet.
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, frame := range frames { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var3 string - templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(frame.Frame) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `contact_sheet.templ`, Line: 16, Col: 21} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if frame.Image != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\"") ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if frame.Label != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(frame.Label) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `contact_sheet.templ`, Line: 30, Col: 22} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/email_wrapper.templ b/email_wrapper.templ deleted file mode 100644 index f223161..0000000 --- a/email_wrapper.templ +++ /dev/null @@ -1,136 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - - "git.dev.alexdunmow.com/block/core/templates" -) - -// NoirEmailWrapper wraps body content in a pure black 600px canvas with a -// Tenor Sans masthead and a mono caption strip above the footer. -func NoirEmailWrapper(body string, emailCtx templates.EmailContext) string { - var buf bytes.Buffer - _ = noirEmailTemplate(emailCtx, body).Render(context.Background(), &buf) - return buf.String() -} - -// noirEmailTemplate renders the inline-styled HTML email wrapper. -templ noirEmailTemplate(emailCtx templates.EmailContext, body string) { - - - - - - - - { emailCtx.SiteSettings.SiteName } - - - if emailCtx.PreviewText != "" { -
{ emailCtx.PreviewText }
- } - - - - -
- - - - - - - if emailCtx.SiteSettings.LogoURL != "" { - - - - } - - - - - - - - - - - - -
- if emailCtx.SiteSettings.SiteName != "" { -
- { emailCtx.SiteSettings.SiteName } -
- } -
- { -
- @templ.Raw(body) -
- - - - - -
- if emailCtx.SiteSettings.SiteName != "" { - { "© " + emailCtx.SiteSettings.SiteName } - } - - if emailCtx.UnsubscribeURL != "" { - - Unsubscribe - - } -
-
- if emailCtx.SiteSettings.SiteURL != "" { - - { emailCtx.SiteSettings.SiteURL } - - } -
-
- - -} - -// noirEmailBg returns the canvas colour (pure black per spec) with a fallback -// derived from the EmailContext. -func noirEmailBg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Background != "" { - return emailCtx.Colors.Background - } - return "#000000" -} - -func noirEmailCard(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Card != "" { - return emailCtx.Colors.Card - } - return "#0a0a0a" -} - -func noirEmailFg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Foreground != "" { - return emailCtx.Colors.Foreground - } - return "#f5f5f5" -} - -func noirEmailMutedFg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.MutedForeground != "" { - return emailCtx.Colors.MutedForeground - } - return "#8c8c8c" -} - -func noirEmailBorder(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Border != "" { - return emailCtx.Colors.Border - } - return "#1f1f1f" -} diff --git a/email_wrapper_templ.go b/email_wrapper_templ.go deleted file mode 100644 index ab16edc..0000000 --- a/email_wrapper_templ.go +++ /dev/null @@ -1,401 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -import ( - "bytes" - "context" - "fmt" - - "git.dev.alexdunmow.com/block/core/templates" -) - -// NoirEmailWrapper wraps body content in a pure black 600px canvas with a -// Tenor Sans masthead and a mono caption strip above the footer. -func NoirEmailWrapper(body string, emailCtx templates.EmailContext) string { - var buf bytes.Buffer - _ = noirEmailTemplate(emailCtx, body).Render(context.Background(), &buf) - return buf.String() -} - -// noirEmailTemplate renders the inline-styled HTML email wrapper. -func noirEmailTemplate(emailCtx templates.EmailContext, body string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var2 string - templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteName) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 28, Col: 41} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.PreviewText != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.PreviewText) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 32, Col: 101} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.SiteSettings.LogoURL != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.SiteSettings.SiteName != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteName) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 43, Col: 42} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
\"")
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(body).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.SiteSettings.SiteName != "" { - var templ_7745c5c3_Var14 string - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs("© " + emailCtx.SiteSettings.SiteName) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 69, Col: 52} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.UnsubscribeURL != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "Unsubscribe") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if emailCtx.SiteSettings.SiteURL != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var20 string - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteURL) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 88, Col: 41} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// noirEmailBg returns the canvas colour (pure black per spec) with a fallback -// derived from the EmailContext. -func noirEmailBg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Background != "" { - return emailCtx.Colors.Background - } - return "#000000" -} - -func noirEmailCard(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Card != "" { - return emailCtx.Colors.Card - } - return "#0a0a0a" -} - -func noirEmailFg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Foreground != "" { - return emailCtx.Colors.Foreground - } - return "#f5f5f5" -} - -func noirEmailMutedFg(emailCtx templates.EmailContext) string { - if emailCtx.Colors.MutedForeground != "" { - return emailCtx.Colors.MutedForeground - } - return "#8c8c8c" -} - -func noirEmailBorder(emailCtx templates.EmailContext) string { - if emailCtx.Colors.Border != "" { - return emailCtx.Colors.Border - } - return "#1f1f1f" -} - -var _ = templruntime.GeneratedTemplate diff --git a/embed.go b/embed.go deleted file mode 100644 index e63ef1f..0000000 --- a/embed.go +++ /dev/null @@ -1,64 +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 presets.json -var presetsData []byte - -//go:embed fonts.json -var fontsData []byte - -//go:embed plugin.mod -var pluginModBytes []byte - -// Assets returns the embedded assets filesystem. -func Assets() fs.FS { - sub, _ := fs.Sub(assetsFS, "assets") - return sub -} - -// Schemas returns the embedded schemas filesystem. -func Schemas() fs.FS { - sub, _ := fs.Sub(schemasFS, "schemas") - return sub -} - -// AssetsHandler returns an http.Handler that serves the embedded assets. -func AssetsHandler() http.Handler { - return http.FileServer(http.FS(Assets())) -} - -// ThemePresets returns the embedded theme presets JSON. -func ThemePresets() []byte { - return presetsData -} - -// BundledFonts returns the embedded fonts manifest JSON. -func BundledFonts() []byte { - return fontsData -} - -// ThemeCSSManifest exposes Noir's custom utility CSS (.bleed, .tracked-mono, -// .hairline, lightbox keyframes) to the host Tailwind input so the classes -// survive the content scanner. -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/footer.go b/footer.go deleted file mode 100644 index 260f690..0000000 --- a/footer.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// FooterBlockMeta defines the Noir dissolved-rail footer block. -var FooterBlockMeta = blocks.BlockMeta{ - Key: "footer", - Title: "Noir Footer", - Description: "Dissolved bottom rail with optional colophon and social links.", - Source: "noir", - Category: blocks.CategoryLayout, -} - -// FooterBlock renders the Noir footer. -// Content shape: {"showColophon":"true","social":[{"text":"Instagram","url":"..."}, ...]} -func FooterBlock(ctx context.Context, content map[string]any) string { - data := FooterData{ - ShowColophon: getBoolish(content, "showColophon", true), - } - - for _, item := range getSlice(content, "social") { - data.Social = append(data.Social, FooterLink{ - Text: getString(item, "text"), - URL: getString(item, "url"), - }) - } - - var buf bytes.Buffer - _ = footerComponent(data).Render(ctx, &buf) - return buf.String() -} - -// FooterData holds the parsed view-model for the Noir footer. -type FooterData struct { - ShowColophon bool - Social []FooterLink -} - -// FooterLink is a single social-link entry. -type FooterLink struct { - Text string - URL string -} diff --git a/footer.templ b/footer.templ deleted file mode 100644 index bf664d2..0000000 --- a/footer.templ +++ /dev/null @@ -1,33 +0,0 @@ -package main - -// footerComponent renders the Noir footer rail. -templ footerComponent(data FooterData) { -
-
- if data.ShowColophon { -

- Designed and printed in the darkroom. -

- } else { - - } - if len(data.Social) > 0 { - - } -
-
-} diff --git a/footer_templ.go b/footer_templ.go deleted file mode 100644 index 826025a..0000000 --- a/footer_templ.go +++ /dev/null @@ -1,98 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// footerComponent renders the Noir footer rail. -func footerComponent(data FooterData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.ShowColophon { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

Designed and printed in the darkroom.

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if len(data.Social) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/go.mod b/go.mod deleted file mode 100644 index 710ca49..0000000 --- a/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module git.dev.alexdunmow.com/block/themes/noir - -go 1.26.4 - -require ( - git.dev.alexdunmow.com/block/core v0.15.2 - github.com/a-h/templ v0.3.1020 -) - -require ( - connectrpc.com/connect v1.20.0 // indirect - github.com/BurntSushi/toml v1.6.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 ebd3d11..0000000 --- a/go.sum +++ /dev/null @@ -1,46 +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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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/helpers.go b/helpers.go deleted file mode 100644 index b047d78..0000000 --- a/helpers.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import "strconv" - -// getString extracts a string value from content map. Returns "" if missing or wrong type. -func getString(content map[string]any, key string) string { - if v, ok := content[key].(string); ok { - return v - } - return "" -} - -// getInt extracts an int value from content map (handles float64 from JSON). -func getInt(content map[string]any, key string, defaultVal int) int { - if v, ok := content[key].(float64); ok { - return int(v) - } - if v, ok := content[key].(int); ok { - return v - } - if v, ok := content[key].(string); ok { - if n, err := strconv.Atoi(v); err == nil { - return n - } - } - return defaultVal -} - -// getSlice extracts a slice of maps from content. Returns nil if missing. -func getSlice(content map[string]any, key string) []map[string]any { - if v, ok := content[key].([]any); ok { - result := make([]map[string]any, 0, len(v)) - for _, item := range v { - if m, ok := item.(map[string]any); ok { - result = append(result, m) - } - } - return result - } - return nil -} - -// getStringSlice extracts a slice of strings from content. Non-string entries are coerced via fmt.Sprintf. -// Returns nil if missing. -func getStringSlice(content map[string]any, key string) []string { - if v, ok := content[key].([]any); ok { - result := make([]string, 0, len(v)) - for _, item := range v { - if s, ok := item.(string); ok { - result = append(result, s) - } - } - return result - } - if v, ok := content[key].([]string); ok { - return v - } - return nil -} - -// getBoolish accepts "true"/"false" strings and booleans. Returns defaultVal otherwise. -func getBoolish(content map[string]any, key string, defaultVal bool) bool { - if v, ok := content[key].(bool); ok { - return v - } - if v, ok := content[key].(string); ok { - switch v { - case "true": - return true - case "false": - return false - } - } - return defaultVal -} diff --git a/image_pair.go b/image_pair.go deleted file mode 100644 index f6812eb..0000000 --- a/image_pair.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// ImagePairBlockMeta defines the Noir diptych block. -var ImagePairBlockMeta = blocks.BlockMeta{ - Key: "image_pair", - Title: "Image Pair", - Description: "50/50 photograph diptych with a shared caption beneath both images.", - Source: "noir", - Category: blocks.CategoryContent, -} - -// ImagePairBlock renders a two-photograph diptych. -// Content shape: {"left":"...","right":"...","caption":"..."} -func ImagePairBlock(ctx context.Context, content map[string]any) string { - data := ImagePairData{ - Left: blocks.ResolveMediaPath(getString(content, "left")), - Right: blocks.ResolveMediaPath(getString(content, "right")), - Caption: getString(content, "caption"), - } - - var buf bytes.Buffer - _ = imagePairComponent(data).Render(ctx, &buf) - return buf.String() -} - -// ImagePairData holds the parsed view-model for the diptych. -type ImagePairData struct { - Left string - Right string - Caption string -} diff --git a/image_pair.templ b/image_pair.templ deleted file mode 100644 index 0f06cce..0000000 --- a/image_pair.templ +++ /dev/null @@ -1,30 +0,0 @@ -package main - -// imagePairComponent renders a 50/50 photograph diptych with a shared caption. -templ imagePairComponent(data ImagePairData) { -
-
-
- if data.Left != "" { -
- { -
- } else { -
- } - if data.Right != "" { -
- { -
- } else { -
- } -
- if data.Caption != "" { -

- { data.Caption } -

- } -
-
-} diff --git a/image_pair_templ.go b/image_pair_templ.go deleted file mode 100644 index 8b9f456..0000000 --- a/image_pair_templ.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// imagePairComponent renders a 50/50 photograph diptych with a shared caption. -func imagePairComponent(data ImagePairData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.Left != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
\"")
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.Right != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
\"")
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.Caption != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Caption) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_pair.templ`, Line: 25, Col: 19} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/lightbox_gallery.go b/lightbox_gallery.go deleted file mode 100644 index a8a0671..0000000 --- a/lightbox_gallery.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "bytes" - "context" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// LightboxGalleryBlockMeta defines the Noir lightbox gallery block. -var LightboxGalleryBlockMeta = blocks.BlockMeta{ - Key: "lightbox_gallery", - Title: "Lightbox Gallery", - Description: "Grid of photographs that expand into a full-viewport lightbox overlay on click.", - Source: "noir", - Category: blocks.CategoryContent, -} - -// LightboxGalleryBlock renders the gallery from content.items + content.columns. -// Content shape: {"items":[{"image":"...","caption":"..."}, ...], "columns": 2|3|4} -func LightboxGalleryBlock(ctx context.Context, content map[string]any) string { - items := getSlice(content, "items") - cols := getInt(content, "columns", 3) - if cols != 2 && cols != 3 && cols != 4 { - cols = 3 - } - - var entries []LightboxItem - for _, item := range items { - entries = append(entries, LightboxItem{ - Image: blocks.ResolveMediaPath(getString(item, "image")), - Caption: getString(item, "caption"), - }) - } - - var buf bytes.Buffer - _ = lightboxGalleryComponent(entries, cols).Render(ctx, &buf) - return buf.String() -} - -// LightboxItem represents one photograph in the gallery. -type LightboxItem struct { - Image string - Caption string -} diff --git a/lightbox_gallery.templ b/lightbox_gallery.templ deleted file mode 100644 index 03488a0..0000000 --- a/lightbox_gallery.templ +++ /dev/null @@ -1,87 +0,0 @@ -package main - -// lightboxGalleryComponent renders the gallery grid with lightbox triggers. -templ lightboxGalleryComponent(items []LightboxItem, cols int) { -
-
- if len(items) == 0 { -
- Add photographs to populate the gallery. -
- } else { -
- for i, item := range items { -
- - if item.Caption != "" { -
- { item.Caption } -
- } -
- } -
- } -
-
-} - -// lightboxGridCols returns Tailwind grid-template-columns utility for the requested columns. -func lightboxGridCols(cols int) string { - switch cols { - case 2: - return "grid-cols-1 md:grid-cols-2" - case 4: - return "grid-cols-1 md:grid-cols-2 lg:grid-cols-4" - default: // 3 - return "grid-cols-1 md:grid-cols-2 lg:grid-cols-3" - } -} - -// lightboxAriaLabel builds an accessible button label for each gallery entry. -func lightboxAriaLabel(index int, caption string) string { - if caption != "" { - return "Open photograph: " + caption - } - return "Open photograph " + intToString(index+1) -} - -// intToString avoids importing strconv into a templ-generated file. -func intToString(n int) string { - if n == 0 { - return "0" - } - neg := false - if n < 0 { - neg = true - n = -n - } - var b [20]byte - i := len(b) - for n > 0 { - i-- - b[i] = byte('0' + n%10) - n /= 10 - } - if neg { - i-- - b[i] = '-' - } - return string(b[i:]) -} diff --git a/lightbox_gallery_templ.go b/lightbox_gallery_templ.go deleted file mode 100644 index 59ac84d..0000000 --- a/lightbox_gallery_templ.go +++ /dev/null @@ -1,229 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// lightboxGalleryComponent renders the gallery grid with lightbox triggers. -func lightboxGalleryComponent(items []LightboxItem, cols int) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(items) == 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Add photographs to populate the gallery.
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - var templ_7745c5c3_Var2 = []any{"grid gap-4", lightboxGridCols(cols)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for i, item := range items { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if item.Caption != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(item.Caption) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `lightbox_gallery.templ`, Line: 34, Col: 23} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// lightboxGridCols returns Tailwind grid-template-columns utility for the requested columns. -func lightboxGridCols(cols int) string { - switch cols { - case 2: - return "grid-cols-1 md:grid-cols-2" - case 4: - return "grid-cols-1 md:grid-cols-2 lg:grid-cols-4" - default: // 3 - return "grid-cols-1 md:grid-cols-2 lg:grid-cols-3" - } -} - -// lightboxAriaLabel builds an accessible button label for each gallery entry. -func lightboxAriaLabel(index int, caption string) string { - if caption != "" { - return "Open photograph: " + caption - } - return "Open photograph " + intToString(index+1) -} - -// intToString avoids importing strconv into a templ-generated file. -func intToString(n int) string { - if n == 0 { - return "0" - } - neg := false - if n < 0 { - neg = true - n = -n - } - var b [20]byte - i := len(b) - for n > 0 { - i-- - b[i] = byte('0' + n%10) - n /= 10 - } - if neg { - i-- - b[i] = '-' - } - return string(b[i:]) -} - -var _ = templruntime.GeneratedTemplate diff --git a/main.go b/main.go deleted file mode 100644 index 1780cd5..0000000 --- a/main.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build wasip1 - -// Package main compiles the noir 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..04d569e --- /dev/null +++ b/manifest.yaml @@ -0,0 +1,279 @@ +# Noir theme — codeless .bnp manifest (WO-WZ-021 Phase B1). +# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm). +theme_presets: presets.json +bundled_fonts: fonts.json +master_pages: master_pages.json + +system_templates: + - key: noir + title: Noir + description: "Silver-on-black photography theme with full-bleed imagery, micro mono labels, lightbox galleries and contact-sheet layouts." + +page_templates: + - system: noir + key: default + title: Default + description: "Centred gallery page with a thin masthead and dissolved footer." + slots: [header, main, footer] + - system: noir + key: landing + title: Landing + description: "Edge-to-edge hero image, micro caption strip, minimal CTA." + slots: [hero, main, cta, footer] + - system: noir + key: article + title: Article / Project + description: "Long-form case study with sticky caption rail and image-led prose." + slots: [header, main, aside, footer] + - system: noir + key: full-width + title: Full Width + description: "Contact-sheet or lightbox grid, no horizontal padding." + slots: [header, main, footer] + +template_overrides: + - { template: noir, block: heading } + - { template: noir, block: text } + - { template: noir, block: image } + - { template: noir, block: button } + - { template: noir, block: card } + +email_wrappers: + - noir + +css: + input_css_append: | + /* ============================================================ + Noir Theme — Silver-on-black photography + Custom utility CSS injected via CSSManifest.InputCSSAppend. + ============================================================ */ + + /* --- Typography slots ---------------------------------------- */ + /* Body & page typography flow through the theme font variables. + Fallback stacks reflect the spec's intended faces (Tenor Sans, + Inter, JetBrains Mono) without hardcoding the family name. */ + + .noir-page { + font-family: var(--font-body, "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif); + -webkit-font-smoothing: antialiased; + } + + .noir-display { + font-family: var(--font-heading, "Tenor Sans", Georgia, serif); + letter-spacing: 0.01em; + text-decoration: none; + } + + /* --- .tracked-mono ------------------------------------------- */ + /* 10px JetBrains Mono, +60 tracking equivalent (0.18em), uppercase. + Used for captions, frame numbers, and the caption strip. */ + + .tracked-mono { + font-family: var(--font-mono, "JetBrains Mono", "Consolas", "SFMono-Regular", monospace); + font-size: 10px; + letter-spacing: 0.18em; + text-transform: uppercase; + line-height: 1.4; + } + + .tracked-mono-sm { + font-family: var(--font-mono, "JetBrains Mono", "Consolas", "SFMono-Regular", monospace); + font-size: 11px; + letter-spacing: 0.18em; + text-transform: uppercase; + line-height: 1.4; + } + + /* --- .bleed -------------------------------------------------- */ + /* Edge-to-edge utility — breaks out of a max-width container. */ + + .bleed { + width: 100vw; + margin-left: calc((100vw - 100%) / 2 * -1); + margin-right: calc((100vw - 100%) / 2 * -1); + } + + /* --- .hairline ----------------------------------------------- */ + /* 1px almost-invisible border using the border token at 40% alpha. */ + + .hairline { + border: 1px solid hsl(var(--border) / 0.4); + } + + .hairline-t { border-top: 1px solid hsl(var(--border) / 0.4); } + .hairline-b { border-bottom: 1px solid hsl(var(--border) / 0.4); } + + /* --- Surface tokens used by overrides ------------------------ */ + + .noir-surface { + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + } + + .noir-card { + background-color: transparent; + border: 1px solid hsl(var(--border) / 0.4); + } + + /* Buttons render as hairline outlines that invert on hover. + Override block uses these classes directly. */ + + .noir-btn { + display: inline-block; + background-color: transparent; + color: hsl(var(--foreground)); + border: 1px solid hsl(var(--foreground)); + padding: 0.75rem 1.5rem; + font-family: var(--font-mono, "JetBrains Mono", "Consolas", "SFMono-Regular", monospace); + font-size: 11px; + letter-spacing: 0.18em; + text-transform: uppercase; + text-decoration: none; + transition: background-color 0.18s ease, color 0.18s ease; + cursor: pointer; + } + + .noir-btn:hover, + .noir-btn:focus-visible { + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + } + + .noir-btn:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } + + /* --- Caption strip ------------------------------------------- */ + + .noir-caption-strip { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.625rem 1.5rem; + border-top: 1px solid hsl(var(--border) / 0.4); + border-bottom: 1px solid hsl(var(--border) / 0.4); + background-color: hsl(var(--background)); + color: hsl(var(--mutedForeground)); + } + + /* --- Contact sheet sprocket motif ---------------------------- */ + + .noir-sprocket { + position: relative; + background-color: hsl(var(--card)); + border: 1px solid hsl(var(--border) / 0.4); + padding: 1.25rem 0.75rem 0.75rem; + } + + .noir-sprocket::before, + .noir-sprocket::after { + content: ""; + position: absolute; + left: 0; + right: 0; + height: 0.5rem; + /* Sprocket holes drawn as repeating radial-gradient circles + using the muted foreground token at low alpha. */ + background-image: radial-gradient( + circle, + hsl(var(--mutedForeground) / 0.85) 0, + hsl(var(--mutedForeground) / 0.85) 25%, + transparent 27%, + transparent 100% + ); + background-size: 1rem 0.5rem; + background-repeat: repeat-x; + background-position: 0 50%; + opacity: 0.35; + } + + .noir-sprocket::before { top: 0; } + .noir-sprocket::after { bottom: 0; } + + .noir-frame-number { + position: absolute; + top: 0.4rem; + left: 0.75rem; + } + + /* --- Lightbox overlay ---------------------------------------- */ + + [data-noir-lightbox] { + position: fixed; + inset: 0; + width: 100vw; + height: 100vh; + display: none; + z-index: 9999; + background-color: hsl(var(--background)); + align-items: center; + justify-content: center; + flex-direction: column; + padding: 1.5rem; + animation: noirFadeIn 180ms ease forwards; + } + + [data-noir-lightbox][aria-hidden="false"] { + display: flex; + } + + [data-noir-lightbox] img { + max-width: 100%; + max-height: 80vh; + object-fit: contain; + } + + [data-noir-lightbox] .noir-lightbox-caption { + margin-top: 1rem; + color: hsl(var(--mutedForeground)); + } + + [data-noir-lightbox] .noir-lightbox-close { + position: absolute; + top: 1rem; + right: 1rem; + background: transparent; + border: 1px solid hsl(var(--border)); + color: hsl(var(--foreground)); + padding: 0.4rem 0.8rem; + cursor: pointer; + } + + @keyframes noirFadeIn { + from { opacity: 0; } + to { opacity: 1; } + } + + /* --- Sticky case-study meta rail ----------------------------- */ + + .noir-meta-rail { + position: sticky; + top: 1.5rem; + align-self: start; + color: hsl(var(--mutedForeground)); + } + + /* --- Image full-bleed override ------------------------------- */ + + .noir-figure { + margin: 0; + display: block; + } + + .noir-figure img { + width: 100%; + height: auto; + display: block; + } + + .noir-figure figcaption { + margin-top: 0.5rem; + color: hsl(var(--mutedForeground)); + } + + /* --- Reduced motion ------------------------------------------ */ + + @media (prefers-reduced-motion: reduce) { + [data-noir-lightbox] { animation: none; } + } diff --git a/master_pages.json b/master_pages.json new file mode 100644 index 0000000..6e2dc0f --- /dev/null +++ b/master_pages.json @@ -0,0 +1,24 @@ +[ + { + "key": "noir:default-master", + "title": "Noir Default Master", + "page_templates": ["default", "article"], + "blocks": [ + { "block_key": "navbar", "title": "Masthead", "content": { "menuName": "main", "variant": "minimal" }, "slot": "header", "sort_order": 0 }, + { "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main", "placeholder": "Photographs go here" }, "slot": "main", "sort_order": 0 }, + { "block_key": "noir:caption_strip", "title": "Caption Strip", "content": { "label": "INDEX", "right": "© studio" }, "slot": "footer", "sort_order": 0 }, + { "block_key": "noir:footer", "title": "Footer", "content": { "showColophon": "true" }, "slot": "footer", "sort_order": 1 } + ] + }, + { + "key": "noir:gallery-master", + "title": "Noir Gallery Master", + "page_templates": ["landing", "full-width"], + "blocks": [ + { "block_key": "navbar", "title": "Dissolved Masthead", "content": { "menuName": "main", "variant": "dissolved" }, "slot": "header", "sort_order": 0 }, + { "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main", "placeholder": "Photographs go here" }, "slot": "main", "sort_order": 0 }, + { "block_key": "noir:contact_sheet_footer", "title": "Contact Sheet Footer", "content": { "items": [] }, "slot": "footer", "sort_order": 0 }, + { "block_key": "noir:footer", "title": "Footer", "content": { "showColophon": "true" }, "slot": "footer", "sort_order": 1 } + ] + } +] diff --git a/overrides.go b/overrides.go deleted file mode 100644 index f5ec517..0000000 --- a/overrides.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "bytes" - "context" - "strconv" - - "git.dev.alexdunmow.com/block/core/blocks" -) - -// NoirHeadingBlock overrides the built-in heading. -// Renders with the display-serif family, no underline, generous tracking. -func NoirHeadingBlock(ctx context.Context, content map[string]any) string { - text := getString(content, "text") - textClass := getString(content, "textClass") - level := parseHeadingLevel(content) - - var buf bytes.Buffer - _ = noirHeadingComponent(level, text, textClass).Render(ctx, &buf) - return buf.String() -} - -// parseHeadingLevel parses the heading level from content (1-6, default 2). -func parseHeadingLevel(content map[string]any) int { - if level, ok := content["level"].(float64); ok { - l := int(level) - if l >= 1 && l <= 6 { - return l - } - } - if level, ok := content["level"].(int); ok { - if level >= 1 && level <= 6 { - return level - } - } - if level, ok := content["level"].(string); ok { - if l, err := strconv.Atoi(level); err == nil && l >= 1 && l <= 6 { - return l - } - } - return 2 -} - -// NoirTextBlock overrides the built-in text block. -// Renders with the humanist sans family and generous leading. -func NoirTextBlock(ctx context.Context, content map[string]any) string { - text := getString(content, "text") - class := getString(content, "class") - - var buf bytes.Buffer - _ = noirTextComponent(text, class).Render(ctx, &buf) - return buf.String() -} - -// NoirImageBlock overrides the built-in image block. -// Always full-bleed inside its container with a mono caption beneath. -func NoirImageBlock(ctx context.Context, content map[string]any) string { - src := blocks.ResolveMediaPath(getString(content, "src")) - alt := getString(content, "alt") - caption := getString(content, "caption") - if caption == "" { - caption = getString(content, "title") - } - - var buf bytes.Buffer - _ = noirImageComponent(src, alt, caption).Render(ctx, &buf) - return buf.String() -} - -// NoirButtonBlock overrides the built-in button. -// Renders as a hairline 1px outline, no fill, hover inverts. -func NoirButtonBlock(ctx context.Context, content map[string]any) string { - text := getString(content, "text") - if text == "" { - text = getString(content, "label") - } - href := getString(content, "url") - if href == "" { - href = getString(content, "href") - } - - var buf bytes.Buffer - _ = noirButtonComponent(text, href).Render(ctx, &buf) - return buf.String() -} - -// NoirCardBlock overrides the built-in card. -// Transparent background, hairline border only. -func NoirCardBlock(ctx context.Context, content map[string]any) string { - title := getString(content, "title") - body := getString(content, "body") - if body == "" { - body = getString(content, "text") - } - - var buf bytes.Buffer - _ = noirCardComponent(title, body).Render(ctx, &buf) - return buf.String() -} diff --git a/overrides.templ b/overrides.templ deleted file mode 100644 index 3a9c987..0000000 --- a/overrides.templ +++ /dev/null @@ -1,87 +0,0 @@ -package main - -// noirHeadingComponent renders a heading using the display-serif font slot. -templ noirHeadingComponent(level int, text, textClass string) { - switch level { - case 1: -

- { text } -

- case 2: -

- { text } -

- case 3: -

- { text } -

- case 4: -

- { text } -

- case 5: -
- { text } -
- case 6: -
- { text } -
- default: -

- { text } -

- } -} - -// noirTextComponent renders text with the humanist sans family and generous leading. -// The body family resolves through --font-body; the surrounding .noir-page already -// supplies the fallback stack from style.css, so we only need spacing here. -templ noirTextComponent(text, class string) { -
- @templ.Raw(text) -
-} - -// noirImageComponent renders an image full-bleed within its container with a mono caption. -templ noirImageComponent(src, alt, caption string) { -
- if src != "" { - { - } - if caption != "" { -
- { caption } -
- } -
-} - -// noirButtonComponent renders the hairline outline button. -templ noirButtonComponent(text, href string) { - if href != "" { - - { text } - - } else { - - } -} - -// noirCardComponent renders the transparent hairline-bordered card. -templ noirCardComponent(title, body string) { -
- if title != "" { -

- { title } -

- } - if body != "" { -
- @templ.Raw(body) -
- } -
-} diff --git a/overrides_templ.go b/overrides_templ.go deleted file mode 100644 index 521d837..0000000 --- a/overrides_templ.go +++ /dev/null @@ -1,577 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -// noirHeadingComponent renders a heading using the display-serif font slot. -func noirHeadingComponent(level int, text, textClass string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - switch level { - case 1: - var templ_7745c5c3_Var2 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 8, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case 2: - var templ_7745c5c3_Var5 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 12, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case 3: - var templ_7745c5c3_Var8 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 16, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case 4: - var templ_7745c5c3_Var11 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 20, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case 5: - var templ_7745c5c3_Var14 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 24, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case 6: - var templ_7745c5c3_Var17 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 28, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - default: - var templ_7745c5c3_Var20 = []any{"noir-display", textClass} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var20...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 32, Col: 10} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - return nil - }) -} - -// noirTextComponent renders text with the humanist sans family and generous leading. -// The body family resolves through --font-body; the surrounding .noir-page already -// supplies the fallback stack from style.css, so we only need spacing here. -func noirTextComponent(text, class string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var23 := templ.GetChildren(ctx) - if templ_7745c5c3_Var23 == nil { - templ_7745c5c3_Var23 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var24 = []any{"noir-text", class} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var24...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(text).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// noirImageComponent renders an image full-bleed within its container with a mono caption. -func noirImageComponent(src, alt, caption string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var26 := templ.GetChildren(ctx) - if templ_7745c5c3_Var26 == nil { - templ_7745c5c3_Var26 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if src != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "\"") ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if caption != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var29 string - templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(caption) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 54, Col: 13} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// noirButtonComponent renders the hairline outline button. -func noirButtonComponent(text, href string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var30 := templ.GetChildren(ctx) - if templ_7745c5c3_Var30 == nil { - templ_7745c5c3_Var30 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - if href != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var32 string - templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(text) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 64, Col: 9} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - return nil - }) -} - -// noirCardComponent renders the transparent hairline-bordered card. -func noirCardComponent(title, body string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var34 := templ.GetChildren(ctx) - if templ_7745c5c3_Var34 == nil { - templ_7745c5c3_Var34 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if title != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var35 string - templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(title) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `overrides.templ`, Line: 78, Col: 11} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if body != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(body).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/plugin.mod b/plugin.mod index 3a3f3a4..aab291c 100644 --- a/plugin.mod +++ b/plugin.mod @@ -2,11 +2,8 @@ name = "noir" display_name = "Noir" scope = "@themes" -version = "0.1.2" +version = "0.2.0" description = "Silver-on-black photography theme with full-bleed imagery, micro mono labels, lightbox galleries and contact-sheet layouts." kind = "theme" categories = ["templates"] tags = ["noir", "monochrome", "photography", "portfolio", "gallery", "filmmaker", "fashion", "darkroom"] - -[compatibility] -block_core = ">=0.15.0 <0.16.0" diff --git a/register.go b/register.go deleted file mode 100644 index 0ad851d..0000000 --- a/register.go +++ /dev/null @@ -1,176 +0,0 @@ -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 wires the Noir system template, page templates, blocks, overrides, -// and email wrapper into the host registries. -// -// Order matters: br.LoadSchemasFromFS(Schemas()) is called BEFORE any -// br.Register call so the schema metadata binds correctly. -func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error { - // System template. - tr.RegisterSystemTemplate(templates.SystemTemplateMeta{ - Key: "noir", - Title: "Noir", - Description: "Silver-on-black photography theme with full-bleed imagery, micro mono labels, lightbox galleries and contact-sheet layouts.", - }) - - // Page templates (4). - if err := tr.RegisterPageTemplate("noir", templates.PageTemplateMeta{ - Key: "default", - Title: "Default", - Description: "Centred gallery page with a thin masthead and dissolved footer.", - Slots: []string{"header", "main", "footer"}, - }, wrap(RenderNoirDefault)); err != nil { - return err - } - - if err := tr.RegisterPageTemplate("noir", templates.PageTemplateMeta{ - Key: "landing", - Title: "Landing", - Description: "Edge-to-edge hero image, micro caption strip, minimal CTA.", - Slots: []string{"hero", "main", "cta", "footer"}, - }, wrap(RenderNoirLanding)); err != nil { - return err - } - - if err := tr.RegisterPageTemplate("noir", templates.PageTemplateMeta{ - Key: "article", - Title: "Article / Project", - Description: "Long-form case study with sticky caption rail and image-led prose.", - Slots: []string{"header", "main", "aside", "footer"}, - }, wrap(RenderNoirArticle)); err != nil { - return err - } - - if err := tr.RegisterPageTemplate("noir", templates.PageTemplateMeta{ - Key: "full-width", - Title: "Full Width", - Description: "Contact-sheet or lightbox grid, no horizontal padding.", - Slots: []string{"header", "main", "footer"}, - }, wrap(RenderNoirFullWidth)); err != nil { - return err - } - - // Schemas must load BEFORE block registration so metadata binds. - if err := br.LoadSchemasFromFS(Schemas()); err != nil { - return err - } - - // Theme-specific blocks (6). Registered with unqualified keys — - // addressed as "noir:" at runtime. - br.Register(LightboxGalleryBlockMeta, LightboxGalleryBlock) - br.Register(ContactSheetBlockMeta, ContactSheetBlock) - br.Register(CaseStudyBlockMeta, CaseStudyBlock) - br.Register(CaptionStripBlockMeta, CaptionStripBlock) - br.Register(ImagePairBlockMeta, ImagePairBlock) - br.Register(FooterBlockMeta, FooterBlock) - - // Template overrides (5) — active only when this theme is selected. - br.RegisterTemplateOverride("noir", "heading", NoirHeadingBlock) - br.RegisterTemplateOverride("noir", "text", NoirTextBlock) - br.RegisterTemplateOverride("noir", "image", NoirImageBlock) - br.RegisterTemplateOverride("noir", "button", NoirButtonBlock) - br.RegisterTemplateOverride("noir", "card", NoirCardBlock) - - // Branded email wrapper. - tr.RegisterEmailWrapper("noir", NoirEmailWrapper) - - return nil -} - -// DefaultMasterPages returns the two master pages Noir provisions on first load. -// -// noir:default-master covers the `default` and `article` page templates. -// noir:gallery-master covers `landing` and `full-width`, swapping the -// caption strip for a contact-sheet-style footer and using the dissolved navbar. -func DefaultMasterPages() []plugin.MasterPageDefinition { - return []plugin.MasterPageDefinition{ - { - Key: "noir:default-master", - Title: "Noir Default Master", - PageTemplates: []string{"default", "article"}, - Blocks: []plugin.MasterPageBlock{ - { - BlockKey: "navbar", - Title: "Masthead", - Content: map[string]any{"menuName": "main", "variant": "minimal"}, - Slot: "header", - SortOrder: 0, - }, - { - BlockKey: "slot", - Title: "Main Slot", - Content: map[string]any{"slotName": "main", "placeholder": "Photographs go here"}, - Slot: "main", - SortOrder: 0, - }, - { - BlockKey: "noir:caption_strip", - Title: "Caption Strip", - Content: map[string]any{"label": "INDEX", "right": "© studio"}, - Slot: "footer", - SortOrder: 0, - }, - { - BlockKey: "noir:footer", - Title: "Footer", - Content: map[string]any{"showColophon": "true"}, - Slot: "footer", - SortOrder: 1, - }, - }, - }, - { - Key: "noir:gallery-master", - Title: "Noir Gallery Master", - PageTemplates: []string{"landing", "full-width"}, - Blocks: []plugin.MasterPageBlock{ - { - BlockKey: "navbar", - Title: "Dissolved Masthead", - Content: map[string]any{"menuName": "main", "variant": "dissolved"}, - Slot: "header", - SortOrder: 0, - }, - { - BlockKey: "slot", - Title: "Main Slot", - Content: map[string]any{"slotName": "main", "placeholder": "Photographs go here"}, - Slot: "main", - SortOrder: 0, - }, - { - BlockKey: "noir:contact_sheet_footer", - Title: "Contact Sheet Footer", - Content: map[string]any{"items": []any{}}, - Slot: "footer", - SortOrder: 0, - }, - { - BlockKey: "noir:footer", - Title: "Footer", - Content: map[string]any{"showColophon": "true"}, - Slot: "footer", - SortOrder: 1, - }, - }, - }, - } -} diff --git a/registration.go b/registration.go deleted file mode 100644 index 1194d49..0000000 --- a/registration.go +++ /dev/null @@ -1,25 +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" -) - -// Registration is the compile-time plugin registration for the Noir theme. -var Registration = plugin.PluginRegistration{ - Name: "noir", - 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 Schemas() }, - 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/template.templ b/template.templ deleted file mode 100644 index 0144c16..0000000 --- a/template.templ +++ /dev/null @@ -1,288 +0,0 @@ -package main - -import ( - "context" - - "git.dev.alexdunmow.com/block/core/templates/bn" -) - -// NoirPageData holds the parsed view-model for every Noir page template. -type NoirPageData struct { - Title string - Slots map[string]string - ThemeMode string - ThemeCSS string - SiteSettings bn.SiteSettingsData - PageMeta bn.PageMeta - StructuredData string - CSSHash string - PageviewNonce string - EngagementConfig bn.EngagementConfig -} - -func parseNoirPageData(doc map[string]any) NoirPageData { - title := "Untitled" - if t, ok := doc["title"].(string); ok { - title = t - } - - slots := make(map[string]string) - if s, ok := doc["slots"].(map[string]string); ok { - slots = s - } - - themeCSS := "" - if tc, ok := doc["theme_css"].(string); ok { - themeCSS = tc - } - - structuredData := "" - if sd, ok := doc["structured_data"].(string); ok { - structuredData = sd - } - - cssHash := "" - if ch, ok := doc["css_hash"].(string); ok { - cssHash = ch - } - - pageviewNonce := "" - if pn, ok := doc["pageview_nonce"].(string); ok { - pageviewNonce = pn - } - - themeMode := "dark" - if tm, ok := doc["theme_mode"].(string); ok && tm != "" { - themeMode = tm - } - - siteSettings := bn.ParseSiteSettings(doc) - pageMeta := bn.ParsePageMeta(doc) - engagementConfig := bn.ParseEngagementConfig(doc) - - return NoirPageData{ - Title: title, - Slots: slots, - ThemeMode: themeMode, - ThemeCSS: themeCSS, - SiteSettings: siteSettings, - PageMeta: pageMeta, - StructuredData: structuredData, - CSSHash: cssHash, - PageviewNonce: pageviewNonce, - EngagementConfig: engagementConfig, - } -} - -// noirHead emits the shared block plus the lightbox-bootstrap script. -templ noirHead(data NoirPageData) { - @bn.Head(bn.HeadData{ - Title: data.Title, - Settings: data.SiteSettings, - PageMeta: data.PageMeta, - ThemeMode: data.ThemeMode, - ThemeCSS: data.ThemeCSS, - PluginStyles: []string{"/templates/noir/style.css"}, - StructuredData: data.StructuredData, - CSSHash: data.CSSHash, - PageviewNonce: data.PageviewNonce, - EngagementConfig: data.EngagementConfig, - }) -} - -// noirLightboxScript injects the vanilla keyboard-aware lightbox handler. -// Stays tiny (no deps) and uses the data attributes set by lightbox_gallery. -templ noirLightboxScript() { - -} - -// NoirDefault — centred gallery page with thin masthead and dissolved footer. -templ NoirDefault(data NoirPageData) { - - - @noirHead(data) - - @bn.AdminBypassBanner(data.SiteSettings) -
-
- @templ.Raw(data.Slots["header"]) -
-
-
- if main, ok := data.Slots["main"]; ok && main != "" { - @templ.Raw(main) - } else { -
-

No photographs assigned to this page.

-
- } -
-
- @templ.Raw(data.Slots["footer"]) -
- @noirLightboxScript() - @bn.BodyEnd(data.SiteSettings) - - -} - -// NoirLanding — edge-to-edge hero, micro caption strip, minimal CTA. -templ NoirLanding(data NoirPageData) { - - - @noirHead(data) - - @bn.AdminBypassBanner(data.SiteSettings) -
- @templ.Raw(data.Slots["hero"]) -
-
- if main, ok := data.Slots["main"]; ok && main != "" { -
- @templ.Raw(main) -
- } -
-
- @templ.Raw(data.Slots["cta"]) -
-
- @templ.Raw(data.Slots["footer"]) -
- @noirLightboxScript() - @bn.BodyEnd(data.SiteSettings) - - -} - -// NoirArticle — long-form case study with sticky caption rail and image-led prose. -templ NoirArticle(data NoirPageData) { - - - @noirHead(data) - - @bn.AdminBypassBanner(data.SiteSettings) -
-
- @templ.Raw(data.Slots["header"]) -
-
-
-
- -
- if main, ok := data.Slots["main"]; ok && main != "" { - @templ.Raw(main) - } else { -
-

No content assigned to this article.

-
- } -
-
-
-
- @templ.Raw(data.Slots["footer"]) -
- @noirLightboxScript() - @bn.BodyEnd(data.SiteSettings) - - -} - -// NoirFullWidth — contact-sheet or lightbox grid, no horizontal padding. -templ NoirFullWidth(data NoirPageData) { - - - @noirHead(data) - - @bn.AdminBypassBanner(data.SiteSettings) -
-
- @templ.Raw(data.Slots["header"]) -
-
-
- if main, ok := data.Slots["main"]; ok && main != "" { - @templ.Raw(main) - } else { -
-

No photographs assigned to this page.

-
- } -
-
- @templ.Raw(data.Slots["footer"]) -
- @noirLightboxScript() - @bn.BodyEnd(data.SiteSettings) - - -} - -func RenderNoirDefault(ctx context.Context, doc map[string]any) templ.Component { - return NoirDefault(parseNoirPageData(doc)) -} - -func RenderNoirLanding(ctx context.Context, doc map[string]any) templ.Component { - return NoirLanding(parseNoirPageData(doc)) -} - -func RenderNoirArticle(ctx context.Context, doc map[string]any) templ.Component { - return NoirArticle(parseNoirPageData(doc)) -} - -func RenderNoirFullWidth(ctx context.Context, doc map[string]any) templ.Component { - return NoirFullWidth(parseNoirPageData(doc)) -} diff --git a/template_templ.go b/template_templ.go deleted file mode 100644 index f96f4c5..0000000 --- a/template_templ.go +++ /dev/null @@ -1,548 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package main - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -import ( - "context" - - "git.dev.alexdunmow.com/block/core/templates/bn" -) - -// NoirPageData holds the parsed view-model for every Noir page template. -type NoirPageData struct { - Title string - Slots map[string]string - ThemeMode string - ThemeCSS string - SiteSettings bn.SiteSettingsData - PageMeta bn.PageMeta - StructuredData string - CSSHash string - PageviewNonce string - EngagementConfig bn.EngagementConfig -} - -func parseNoirPageData(doc map[string]any) NoirPageData { - title := "Untitled" - if t, ok := doc["title"].(string); ok { - title = t - } - - slots := make(map[string]string) - if s, ok := doc["slots"].(map[string]string); ok { - slots = s - } - - themeCSS := "" - if tc, ok := doc["theme_css"].(string); ok { - themeCSS = tc - } - - structuredData := "" - if sd, ok := doc["structured_data"].(string); ok { - structuredData = sd - } - - cssHash := "" - if ch, ok := doc["css_hash"].(string); ok { - cssHash = ch - } - - pageviewNonce := "" - if pn, ok := doc["pageview_nonce"].(string); ok { - pageviewNonce = pn - } - - themeMode := "dark" - if tm, ok := doc["theme_mode"].(string); ok && tm != "" { - themeMode = tm - } - - siteSettings := bn.ParseSiteSettings(doc) - pageMeta := bn.ParsePageMeta(doc) - engagementConfig := bn.ParseEngagementConfig(doc) - - return NoirPageData{ - Title: title, - Slots: slots, - ThemeMode: themeMode, - ThemeCSS: themeCSS, - SiteSettings: siteSettings, - PageMeta: pageMeta, - StructuredData: structuredData, - CSSHash: cssHash, - PageviewNonce: pageviewNonce, - EngagementConfig: engagementConfig, - } -} - -// noirHead emits the shared block plus the lightbox-bootstrap script. -func noirHead(data NoirPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = bn.Head(bn.HeadData{ - Title: data.Title, - Settings: data.SiteSettings, - PageMeta: data.PageMeta, - ThemeMode: data.ThemeMode, - ThemeCSS: data.ThemeCSS, - PluginStyles: []string{"/templates/noir/style.css"}, - StructuredData: data.StructuredData, - CSSHash: data.CSSHash, - PageviewNonce: data.PageviewNonce, - EngagementConfig: data.EngagementConfig, - }).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// noirLightboxScript injects the vanilla keyboard-aware lightbox handler. -// Stays tiny (no deps) and uses the data attributes set by lightbox_gallery. -func noirLightboxScript() templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var2 := templ.GetChildren(ctx) - if templ_7745c5c3_Var2 == nil { - templ_7745c5c3_Var2 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// NoirDefault — centred gallery page with thin masthead and dissolved footer. -func NoirDefault(data NoirPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var3 := templ.GetChildren(ctx) - if templ_7745c5c3_Var3 == nil { - templ_7745c5c3_Var3 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirHead(data).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["header"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if main, ok := data.Slots["main"]; ok && main != "" { - templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

No photographs assigned to this page.

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirLightboxScript().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.BodyEnd(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// NoirLanding — edge-to-edge hero, micro caption strip, minimal CTA. -func NoirLanding(data NoirPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var4 := templ.GetChildren(ctx) - if templ_7745c5c3_Var4 == nil { - templ_7745c5c3_Var4 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirHead(data).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["hero"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if main, ok := data.Slots["main"]; ok && main != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["cta"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirLightboxScript().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.BodyEnd(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// NoirArticle — long-form case study with sticky caption rail and image-led prose. -func NoirArticle(data NoirPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirHead(data).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["header"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if main, ok := data.Slots["main"]; ok && main != "" { - templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "

No content assigned to this article.

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirLightboxScript().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.BodyEnd(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -// NoirFullWidth — contact-sheet or lightbox grid, no horizontal padding. -func NoirFullWidth(data NoirPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var6 := templ.GetChildren(ctx) - if templ_7745c5c3_Var6 == nil { - templ_7745c5c3_Var6 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirHead(data).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["header"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if main, ok := data.Slots["main"]; ok && main != "" { - templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "

No photographs assigned to this page.

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = noirLightboxScript().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = bn.BodyEnd(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -func RenderNoirDefault(ctx context.Context, doc map[string]any) templ.Component { - return NoirDefault(parseNoirPageData(doc)) -} - -func RenderNoirLanding(ctx context.Context, doc map[string]any) templ.Component { - return NoirLanding(parseNoirPageData(doc)) -} - -func RenderNoirArticle(ctx context.Context, doc map[string]any) templ.Component { - return NoirArticle(parseNoirPageData(doc)) -} - -func RenderNoirFullWidth(ctx context.Context, doc map[string]any) templ.Component { - return NoirFullWidth(parseNoirPageData(doc)) -} - -var _ = templruntime.GeneratedTemplate diff --git a/templates/email/noir.ninjatpl b/templates/email/noir.ninjatpl new file mode 100644 index 0000000..891667a --- /dev/null +++ b/templates/email/noir.ninjatpl @@ -0,0 +1,52 @@ + + + + + + + +{{ site_name }} + + +{% if preview_text %}
{{ preview_text }}
{% endif %} + + + + +
+ + + + + + +{% if logo_url %} + +{% endif %} + + + + + + + + + + + + +
+{% if site_name %}
{{ site_name }}
{% endif %} +
{{ site_name }}
{{ body|safe }}
+ + + + + +
{% if site_name %}© {{ site_name }}{% endif %}{% if unsubscribe_url %}Unsubscribe{% endif %}
+
+{% if site_url %}{{ site_url }}{% endif %} +
+
+ + diff --git a/templates/noir/article.ninjatpl b/templates/noir/article.ninjatpl new file mode 100644 index 0000000..f941b84 --- /dev/null +++ b/templates/noir/article.ninjatpl @@ -0,0 +1,68 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} +
+
{{ slots.header|safe }}
+
+
+
+ +
{% if slots.main %}{{ slots.main|safe }}{% else %}

No content assigned to this article.

{% endif %}
+
+
+
{{ slots.footer|safe }}
+ + {{ body_end_html|safe }} + + diff --git a/templates/noir/default.ninjatpl b/templates/noir/default.ninjatpl new file mode 100644 index 0000000..bc6e39d --- /dev/null +++ b/templates/noir/default.ninjatpl @@ -0,0 +1,65 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} +
+
{{ slots.header|safe }}
+
+
+ {% if slots.main %}{{ slots.main|safe }}{% else %}

No photographs assigned to this page.

{% endif %} +
+
{{ slots.footer|safe }}
+ + {{ body_end_html|safe }} + + diff --git a/templates/noir/full-width.ninjatpl b/templates/noir/full-width.ninjatpl new file mode 100644 index 0000000..3d017d3 --- /dev/null +++ b/templates/noir/full-width.ninjatpl @@ -0,0 +1,65 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} +
+
{{ slots.header|safe }}
+
+
+ {% if slots.main %}{{ slots.main|safe }}{% else %}

No photographs assigned to this page.

{% endif %} +
+
{{ slots.footer|safe }}
+ + {{ body_end_html|safe }} + + diff --git a/templates/noir/landing.ninjatpl b/templates/noir/landing.ninjatpl new file mode 100644 index 0000000..042fb21 --- /dev/null +++ b/templates/noir/landing.ninjatpl @@ -0,0 +1,64 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} +
{{ slots.hero|safe }}
+
+ {% if slots.main %}
{{ slots.main|safe }}
{% endif %} +
+
{{ slots.cta|safe }}
+
{{ slots.footer|safe }}
+ + {{ body_end_html|safe }} + + diff --git a/templates/overrides/noir/button.ninjatpl b/templates/overrides/noir/button.ninjatpl new file mode 100644 index 0000000..7c9096a --- /dev/null +++ b/templates/overrides/noir/button.ninjatpl @@ -0,0 +1 @@ +{% if url or href %}{% if text %}{{ text }}{% else %}{{ label }}{% endif %}{% else %}{% endif %} diff --git a/templates/overrides/noir/card.ninjatpl b/templates/overrides/noir/card.ninjatpl new file mode 100644 index 0000000..2a665b5 --- /dev/null +++ b/templates/overrides/noir/card.ninjatpl @@ -0,0 +1 @@ +
{% if title %}

{{ title }}

{% endif %}{% if body %}
{{ body|safe }}
{% elif text %}
{{ text|safe }}
{% endif %}
diff --git a/templates/overrides/noir/heading.ninjatpl b/templates/overrides/noir/heading.ninjatpl new file mode 100644 index 0000000..de2ff99 --- /dev/null +++ b/templates/overrides/noir/heading.ninjatpl @@ -0,0 +1 @@ +{% if level|integer == 1 %}

{{ text }}

{% elif level|integer == 3 %}

{{ text }}

{% elif level|integer == 4 %}

{{ text }}

{% elif level|integer == 5 %}
{{ text }}
{% elif level|integer == 6 %}
{{ text }}
{% else %}

{{ text }}

{% endif %} diff --git a/templates/overrides/noir/image.ninjatpl b/templates/overrides/noir/image.ninjatpl new file mode 100644 index 0000000..b5195de --- /dev/null +++ b/templates/overrides/noir/image.ninjatpl @@ -0,0 +1 @@ +
{% if src %}{{ alt }}{% endif %}{% if caption %}
{{ caption }}
{% elif title %}
{{ title }}
{% endif %}
diff --git a/templates/overrides/noir/text.ninjatpl b/templates/overrides/noir/text.ninjatpl new file mode 100644 index 0000000..abd9ea0 --- /dev/null +++ b/templates/overrides/noir/text.ninjatpl @@ -0,0 +1 @@ +
{{ text|safe }}