feat: convert to codeless .bnp — templates + manifest, Go/templ deleted (WO-WZ-021)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-07-04 15:26:48 +08:00
parent 69494940c1
commit 3207394c38
79 changed files with 327 additions and 4874 deletions

View File

@ -1,26 +1,27 @@
# corporate-modernist — build & publish helpers (wasm .bnp workflow) # corporate-modernist — build & publish helpers (CODELESS .bnp workflow, WO-WZ-021)
# #
# The theme compiles to a wasip1 reactor-mode wasm module packed into a .bnp # This theme is a CODELESS .bnp: pure declaration the host runs — blocks
# artifact (`ninja plugin build`). The legacy .so path is retired (WO-WZ-015): # (blocks/blocks.yaml + .ninjatpl), page/system templates, template overrides,
# the CMS is wasm-native and can no longer load .so plugins. Distribution is # an email wrapper, master pages, presets, fonts and CSS in manifest.yaml. No
# publish-to-registry -> InstallFromRegistry (hot-load, no restart). # 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: # Usage:
# make build # compile wasm + pack corporate-modernist-<version>.bnp # make build # pack corporate-modernist-<version>.bnp (codeless — no wasm)
# make verify # validate the built .bnp (layout/abi/name/size) # make verify # validate the built .bnp (loader-identical checks)
# make archive-check # prove a clean `git archive HEAD` compiles to wasm # make archive-check # prove a clean `git archive HEAD` still builds codeless
# make publish # ninja plugin publish --bnp (to the active registry) # make publish # ninja plugin publish --bnp (to the active registry)
# make templ # regenerate templ Go files
# make clean # remove build artefacts # make clean # remove build artefacts
.PHONY: build verify archive-check publish templ clean help .PHONY: build verify archive-check publish clean help
PLUGIN_NAME := corporate-modernist PLUGIN_NAME := corporate-modernist
NINJA := ninja NINJA := ninja
BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp 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, # Pack the codeless .bnp (manifest.pb synthesized from plugin.mod + manifest.yaml
# tar.zst of plugin.wasm + plugin.mod + manifest.pb + schemas/ + assets/). # + blocks/ + templates/; no wasm compile, no DESCRIBE probe).
build: build:
$(NINJA) plugin build --dir . $(NINJA) plugin build --dir .
@ -28,12 +29,12 @@ build:
verify: verify:
$(NINJA) plugin verify $(BNP) $(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: archive-check:
@T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \ @T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \
trap 'rm -rf "$$T"' EXIT && \ trap 'rm -rf "$$T"' EXIT && \
git archive HEAD | tar -x -C "$$T" && \ 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" echo "archive-check OK"
# Publish the prebuilt .bnp to the active registry. # Publish the prebuilt .bnp to the active registry.
@ -41,19 +42,14 @@ archive-check:
publish: build publish: build
$(NINJA) plugin publish --bnp $(BNP) $(NINJA) plugin publish --bnp $(BNP)
# Regenerate templ Go files locally.
templ:
templ generate
# Remove build artefacts. # Remove build artefacts.
clean: clean:
rm -f $(PLUGIN_NAME)-*.bnp $(PLUGIN_NAME).so plugin.wasm rm -f $(PLUGIN_NAME)-*.bnp plugin.wasm
help: help:
@echo "Targets:" @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 " 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 " publish Publish the .bnp to the active registry"
@echo " templ Regenerate templ Go files"
@echo " clean Remove build artefacts" @echo " clean Remove build artefacts"

54
blocks/blocks.yaml Normal file
View File

@ -0,0 +1,54 @@
# Corporate Modernist theme block definitions (codeless .bnp, WO-WZ-021).
# Keys are fully qualified (corporate-modernist:<key>) 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: corporate-modernist:hero_statement
title: Hero Statement
description: Restrained hero with eyebrow, headline, lede, and a single accent CTA.
category: layout
schema: hero_statement.schema.json
template: hero_statement.ninjatpl
- key: corporate-modernist:logo_strip
title: Client Logo Strip
description: Row of client logos, greyscale until hover.
category: content
schema: logo_strip.schema.json
template: logo_strip.ninjatpl
- key: corporate-modernist:testimonial_quote
title: Testimonial
description: Pull-quote testimonial with attribution, headshot, and company mark.
category: content
schema: testimonial_quote.schema.json
template: testimonial_quote.ninjatpl
- key: corporate-modernist:case_study_card
title: Case Study Card
description: Single case study card with a big tabular metric.
category: content
schema: case_study_card.schema.json
template: case_study_card.ninjatpl
- key: corporate-modernist:leadership_grid
title: Leadership Grid
description: Responsive 2/3/4-up grid of leadership profiles.
category: content
schema: leadership_grid.schema.json
template: leadership_grid.ninjatpl
- key: corporate-modernist:stat_pair
title: Stat Pair
description: Row of mono-numeral statistics separated by a hairline rule.
category: content
schema: stat_pair.schema.json
template: stat_pair.ninjatpl
- key: corporate-modernist:cta_strip
title: CTA Strip
description: Single-line accent strip with a headline and a primary call to action.
category: layout
schema: cta_strip.schema.json
template: cta_strip.ninjatpl
- key: corporate-modernist:footer
title: Footer
description: Multi-column footer with legal line; compact and full variants.
category: navigation
schema: footer.schema.json
template: footer.ninjatpl

View File

@ -0,0 +1 @@
<article class="cm-card cm-card-accent" data-block="corporate-modernist:case_study_card">{% if client %}<div class="cm-stat-label" style="margin: 0 0 0.75rem 0;">{{ client }}</div>{% endif %}{% if metric %}<div class="cm-metric" data-figure>{{ metric }}</div>{% else %}<div class="cm-metric" data-figure>—</div>{% endif %}{% if label %}<div class="cm-stat-label" style="margin-top: 0.5rem;">{{ label }}</div>{% endif %}{% if summary %}<p class="cm-text" style="margin: 1.25rem 0 0 0;">{{ summary }}</p>{% endif %}{% if href.label or href.text or href.href or href.url %}<div style="margin-top: 1.5rem;"><a class="cm-btn-outline" href="{{ href.href|default:href.url|default:"#" }}">{{ href.label|default:href.text|default:"Read case study" }}</a></div>{% endif %}</article>

View File

@ -0,0 +1 @@
<section class="cm-section {% if variant|default:"book-call" == "quiet" %}cm-cta-strip-quiet{% else %}cm-cta-strip-accent{% endif %}" data-block="corporate-modernist:cta_strip" data-variant="{{ variant|default:"book-call" }}"><div class="cm-content-well"><div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.5rem;">{% if headline %}<h2 class="cm-display" style="font-size: 1.75rem; margin: 0; max-width: 36rem;">{{ headline }}</h2>{% else %}<h2 class="cm-display" style="font-size: 1.75rem; margin: 0; max-width: 36rem;">Ready when you are.</h2>{% endif %}{% if primaryCta.label or primaryCta.text or primaryCta.href or primaryCta.url %}<a class="cm-btn-primary" href="{{ primaryCta.href|default:primaryCta.url|default:"#" }}">{% if primaryCta.label %}{{ primaryCta.label }}{% elif primaryCta.text %}{{ primaryCta.text }}{% elif variant|default:"book-call" == "download" %}Download report{% elif variant|default:"book-call" == "quiet" %}Learn more{% else %}Book a call{% endif %}</a>{% else %}<a class="cm-btn-primary" href="#" aria-disabled="true">{% if variant|default:"book-call" == "download" %}Download report{% elif variant|default:"book-call" == "quiet" %}Learn more{% else %}Book a call{% endif %}</a>{% endif %}</div></div></section>

1
blocks/footer.ninjatpl Normal file
View File

@ -0,0 +1 @@
<div class="cm-footer" data-block="corporate-modernist:footer" data-variant="{{ variant|default:"compact" }}"><div class="cm-content-well">{% if variant|default:"compact" == "full" and columns %}<div class="cm-swiss-12">{% for col in columns %}<div style="{% if columns|length >= 4 %}grid-column: span 3 / span 3;{% elif columns|length == 3 %}grid-column: span 4 / span 4;{% elif columns|length == 2 %}grid-column: span 6 / span 6;{% else %}grid-column: span 12 / span 12;{% endif %}">{% if col.title %}<div class="cm-display" style="font-size: 0.875rem; font-weight: 600; margin: 0 0 0.75rem 0; text-transform: uppercase; letter-spacing: 0.05em;">{{ col.title }}</div>{% endif %}{% if col.links %}<ul style="list-style: none; padding: 0; margin: 0;">{% for l in col.links %}{% if l.label or l.text or l.href or l.url %}<li style="margin-bottom: 0.5rem;"><a href="{{ l.href|default:l.url|default:"#" }}" class="cm-text" style="font-size: 0.95rem; text-decoration: none;">{{ l.label|default:l.text|default:l.href|default:l.url|default:"#" }}</a></li>{% endif %}{% endfor %}</ul>{% endif %}</div>{% endfor %}</div>{% endif %}{% if showLegal != false and showLegal != "false" %}<div class="cm-footer-legal">{% if legalLine %}{{ legalLine }}{% else %}All rights reserved.{% endif %}</div>{% endif %}</div></div>

View File

@ -0,0 +1 @@
<section class="cm-section" data-block="corporate-modernist:hero_statement"><div class="cm-content-well"><div class="cm-swiss-12"><div style="grid-column: span 12 / span 12;">{% if eyebrow %}<div class="cm-eyebrow">{{ eyebrow }}</div>{% endif %}{% if headline %}<h1 class="cm-display" style="font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.1; margin: 0 0 1.25rem 0;">{{ headline }}</h1>{% endif %}{% if lede %}<p class="cm-text" style="max-width: 60ch; margin: 0 0 2rem 0;">{{ lede }}</p>{% endif %}{% if primaryCta.label or primaryCta.text or primaryCta.href or primaryCta.url or secondaryCta.label or secondaryCta.text or secondaryCta.href or secondaryCta.url %}<div style="display: flex; flex-wrap: wrap; gap: 0.75rem;">{% if primaryCta.label or primaryCta.text or primaryCta.href or primaryCta.url %}<a class="cm-btn-primary" href="{{ primaryCta.href|default:primaryCta.url|default:"#" }}">{{ primaryCta.label|default:primaryCta.text|default:"Get in touch" }}</a>{% endif %}{% if secondaryCta.label or secondaryCta.text or secondaryCta.href or secondaryCta.url %}<a class="cm-btn-outline" href="{{ secondaryCta.href|default:secondaryCta.url|default:"#" }}">{{ secondaryCta.label|default:secondaryCta.text|default:"Learn more" }}</a>{% endif %}</div>{% endif %}</div></div></div></section>

View File

@ -0,0 +1 @@
<section class="cm-section" data-block="corporate-modernist:leadership_grid"><div class="cm-content-well">{% if title %}<h2 class="cm-heading" style="font-size: 1.875rem; margin: 0 0 2rem 0;"><span class="cm-heading-h2-accent">{{ title }}</span></h2>{% endif %}{% if members %}<div class="cm-leadership-grid">{% for m in members %}{% if m.name %}<article class="cm-card">{% if m.photo %}<img src="{{ m.photo }}" alt="{{ m.name|default:"Team member portrait" }}" style="width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; margin-bottom: 1rem; border-radius: 4px;">{% else %}<span class="cm-img-empty" style="aspect-ratio: 1 / 1; margin-bottom: 1rem; border-radius: 4px;"></span>{% endif %}<div class="cm-display" style="font-size: 1.125rem; font-weight: 600; margin: 0;">{{ m.name }}</div>{% if m.role %}<div class="cm-stat-label" style="margin-top: 0.25rem;">{{ m.role }}</div>{% endif %}{% if m.bio %}<p class="cm-text" style="margin: 0.75rem 0 0 0; font-size: 0.95rem; line-height: 1.55;">{{ m.bio }}</p>{% endif %}{% if m.linkedin %}<div style="margin-top: 1rem;"><a class="cm-btn-outline" href="{{ m.linkedin }}" style="font-size: 0.875rem; padding: 0.375rem 0.75rem;">LinkedIn</a></div>{% endif %}</article>{% endif %}{% endfor %}</div>{% else %}<p class="cm-stat-label">No team members configured.</p>{% endif %}</div></section>

View File

@ -0,0 +1 @@
<section class="cm-section" data-block="corporate-modernist:logo_strip"><div class="cm-content-well">{% if caption %}<p class="cm-stat-label" style="text-align: center; margin-bottom: 2rem;">{{ caption }}</p>{% endif %}{% if logos %}<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2.5rem;">{% for logo in logos %}{% if logo.src or logo.alt %}{% if logo.href %}<a href="{{ logo.href }}" class="cm-logo" style="display: inline-flex; align-items: center;">{% if logo.src %}<img src="{{ logo.src }}" alt="{{ logo.alt|default:"Client logo" }}" style="max-height: 2rem; width: auto; display: block;">{% else %}<span class="cm-stat-label" style="margin: 0;">{{ logo.alt|default:"Client logo" }}</span>{% endif %}</a>{% else %}<span class="cm-logo" style="display: inline-flex; align-items: center;">{% if logo.src %}<img src="{{ logo.src }}" alt="{{ logo.alt|default:"Client logo" }}" style="max-height: 2rem; width: auto; display: block;">{% else %}<span class="cm-stat-label" style="margin: 0;">{{ logo.alt|default:"Client logo" }}</span>{% endif %}</span>{% endif %}{% endif %}{% endfor %}</div>{% else %}<p class="cm-stat-label" style="text-align: center;">No client logos configured.</p>{% endif %}</div></section>

View File

@ -0,0 +1 @@
<section class="cm-section" data-block="corporate-modernist:stat_pair"><div class="cm-content-well">{% if title %}<h2 class="cm-heading" style="font-size: 1.875rem; margin: 0 0 2rem 0;"><span class="cm-heading-h2-accent">{{ title }}</span></h2>{% endif %}{% if stats %}<div class="cm-swiss-12" style="row-gap: 2rem;">{% for s in stats %}{% if s.figure %}<div style="{% if stats|length >= 4 %}grid-column: span 3 / span 3;{% elif stats|length == 3 %}grid-column: span 4 / span 4;{% elif stats|length == 2 %}grid-column: span 6 / span 6;{% else %}grid-column: span 12 / span 12;{% endif %}" class="cm-hairline-top"><div class="cm-stat-figure numeric-tabular" data-figure style="padding-top: 1rem;">{{ s.figure }}</div>{% if s.label %}<div class="cm-stat-label">{{ s.label }}</div>{% endif %}{% if s.source %}<div class="cm-stat-label" style="margin-top: 0.25rem; text-transform: none; letter-spacing: 0; opacity: 0.8;">{{ s.source }}</div>{% endif %}</div>{% endif %}{% endfor %}</div>{% else %}<p class="cm-stat-label">No statistics configured.</p>{% endif %}</div></section>

View File

@ -0,0 +1 @@
<section class="cm-section" data-block="corporate-modernist:testimonial_quote"><div class="cm-content-well"><figure style="max-width: 70ch; margin: 0 auto;">{% if quote %}<blockquote class="cm-pull-quote">{{ quote }}</blockquote>{% else %}<blockquote class="cm-pull-quote">No testimonial provided.</blockquote>{% endif %}<figcaption style="display: flex; align-items: center; gap: 1rem; margin-top: 1.5rem;">{% if headshot %}<img src="{{ headshot }}" alt="{{ name|default:"Testimonial portrait" }}" style="width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; display: block;">{% else %}<span class="cm-img-empty" style="width: 3rem; height: 3rem; aspect-ratio: 1 / 1; border-radius: 50%;"></span>{% endif %}<div>{% if name %}<div class="cm-display" style="font-size: 1rem; font-weight: 600; margin: 0;">{{ name }}</div>{% endif %}{% if role or company %}<div class="cm-stat-label" style="margin: 0.25rem 0 0 0;">{% if role and company %}{{ role }}, {{ company }}{% elif role %}{{ role }}{% else %}{{ company }}{% endif %}</div>{% endif %}</div>{% if logo %}<img src="{{ logo }}" alt="{% if company %}{{ company }} logo{% else %}Company logo{% endif %}" class="cm-logo" style="max-height: 1.5rem; width: auto; margin-left: auto; display: block;">{% endif %}</figcaption></figure></div></section>

View File

@ -1,31 +0,0 @@
package main
import (
"bytes"
"context"
)
// CorporateModernistButtonBlock renders the built-in `button` block with
// squared 4px corners, accent fill or 1px outline only — no shadow, no
// gradient. Content shape: {"label":"...", "href":"...", "variant":"primary|outline"}.
func CorporateModernistButtonBlock(ctx context.Context, content map[string]any) string {
label := getString(content, "label")
if label == "" {
label = getString(content, "text")
}
href := getString(content, "href")
if href == "" {
href = getString(content, "url")
}
if href == "" {
href = "#"
}
variant := getString(content, "variant")
if variant == "" {
variant = "primary"
}
var buf bytes.Buffer
_ = buttonOverrideComponent(label, href, variant).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,21 +0,0 @@
package main
// buttonOverrideComponent renders a Corporate Modernist styled button.
templ buttonOverrideComponent(label, href, variant string) {
if variant == "outline" || variant == "secondary" {
<a class="cm-btn-outline" href={ templ.SafeURL(href) }>
{ buttonOverrideLabel(label) }
</a>
} else {
<a class="cm-btn-primary" href={ templ.SafeURL(href) }>
{ buttonOverrideLabel(label) }
</a>
}
}
func buttonOverrideLabel(label string) string {
if label != "" {
return label
}
return "Learn more"
}

View File

@ -1,107 +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"
// buttonOverrideComponent renders a Corporate Modernist styled button.
func buttonOverrideComponent(label, href, variant 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)
if variant == "outline" || variant == "secondary" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<a class=\"cm-btn-outline\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 templ.SafeURL
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 6, Col: 54}
}
_, 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(buttonOverrideLabel(label))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 7, Col: 31}
}
_, 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, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<a class=\"cm-btn-primary\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 templ.SafeURL
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 10, Col: 54}
}
_, 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
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(buttonOverrideLabel(label))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 11, Col: 31}
}
_, 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, 6, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
func buttonOverrideLabel(label string) string {
if label != "" {
return label
}
return "Learn more"
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,22 +0,0 @@
package main
import (
"bytes"
"context"
)
// CorporateModernistCardBlock renders the built-in `card` block with a flat
// surface, hairline border, no elevation, and an optional accent top rule.
// Content shape: {"title":"...","body":"...","accent": true|false}.
func CorporateModernistCardBlock(ctx context.Context, content map[string]any) string {
title := getString(content, "title")
body := getString(content, "body")
if body == "" {
body = getString(content, "text")
}
accent := getBool(content, "accent", false)
var buf bytes.Buffer
_ = cardOverrideComponent(title, body, accent).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,25 +0,0 @@
package main
// cardOverrideComponent renders a flat hairline-bordered card.
templ cardOverrideComponent(title, body string, accent bool) {
if accent {
<div class="cm-card cm-card-accent">
@cardOverrideInner(title, body)
</div>
} else {
<div class="cm-card">
@cardOverrideInner(title, body)
</div>
}
}
templ cardOverrideInner(title, body string) {
if title != "" {
<div class="cm-display" style="font-size: 1.25rem; font-weight: 600; margin: 0 0 0.75rem 0;">{ title }</div>
}
if body != "" {
<div class="cm-text">
@templ.Raw(body)
</div>
}
}

View File

@ -1,122 +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"
// cardOverrideComponent renders a flat hairline-bordered card.
func cardOverrideComponent(title, body string, accent bool) 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)
if accent {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"cm-card cm-card-accent\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = cardOverrideInner(title, body).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"cm-card\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = cardOverrideInner(title, body).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
func cardOverrideInner(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_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div class=\"cm-display\" style=\"font-size: 1.25rem; font-weight: 600; margin: 0 0 0.75rem 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 18, Col: 102}
}
_, 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, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if body != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"cm-text\">")
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, 8, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,57 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// CaseStudyCardMeta is the block metadata for corporate-modernist:case_study_card.
var CaseStudyCardMeta = blocks.BlockMeta{
Key: "case_study_card",
Title: "Case Study Card",
Description: "Single case study card with a big tabular metric.",
Source: "corporate-modernist",
Category: blocks.CategoryContent,
}
// CaseStudyCardData carries the parsed content for the case_study_card block.
type CaseStudyCardData struct {
Client string
Metric string
Label string
Summary string
HrefLabel string
Href string
HasLink bool
}
// CaseStudyCardBlock renders the case_study_card block.
func CaseStudyCardBlock(ctx context.Context, content map[string]any) string {
link := getNested(content, "href")
hrefLabel := ""
href := ""
hasLink := false
if link != nil {
hrefLabel = linkLabel(link, "")
href = linkHref(link)
if hrefLabel != "" || href != "#" {
hasLink = true
}
}
data := CaseStudyCardData{
Client: getString(content, "client"),
Metric: getString(content, "metric"),
Label: getString(content, "label"),
Summary: getString(content, "summary"),
HrefLabel: hrefLabel,
Href: href,
HasLink: hasLink,
}
var buf bytes.Buffer
_ = caseStudyCardComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,35 +0,0 @@
package main
// caseStudyCardComponent renders the corporate-modernist:case_study_card block.
templ caseStudyCardComponent(data CaseStudyCardData) {
<article class="cm-card cm-card-accent" data-block="corporate-modernist:case_study_card">
if data.Client != "" {
<div class="cm-stat-label" style="margin: 0 0 0.75rem 0;">{ data.Client }</div>
}
if data.Metric != "" {
<div class="cm-metric" data-figure>{ data.Metric }</div>
} else {
<div class="cm-metric" data-figure>—</div>
}
if data.Label != "" {
<div class="cm-stat-label" style="margin-top: 0.5rem;">{ data.Label }</div>
}
if data.Summary != "" {
<p class="cm-text" style="margin: 1.25rem 0 0 0;">{ data.Summary }</p>
}
if data.HasLink {
<div style="margin-top: 1.5rem;">
<a class="cm-btn-outline" href={ templ.SafeURL(data.Href) }>
{ caseStudyCardLinkLabel(data) }
</a>
</div>
}
</article>
}
func caseStudyCardLinkLabel(data CaseStudyCardData) string {
if data.HrefLabel != "" {
return data.HrefLabel
}
return "Read case study"
}

View File

@ -1,165 +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"
// caseStudyCardComponent renders the corporate-modernist:case_study_card block.
func caseStudyCardComponent(data CaseStudyCardData) 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, "<article class=\"cm-card cm-card-accent\" data-block=\"corporate-modernist:case_study_card\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Client != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"cm-stat-label\" style=\"margin: 0 0 0.75rem 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Client)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 7, Col: 74}
}
_, 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, 3, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Metric != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"cm-metric\" data-figure>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Metric)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 10, Col: 51}
}
_, 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, 5, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"cm-metric\" data-figure>—</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Label != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"cm-stat-label\" style=\"margin-top: 0.5rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 15, Col: 70}
}
_, 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, 8, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Summary != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<p class=\"cm-text\" style=\"margin: 1.25rem 0 0 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Summary)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 18, Col: 67}
}
_, 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, 10, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.HasLink {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div style=\"margin-top: 1.5rem;\"><a class=\"cm-btn-outline\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 templ.SafeURL
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.Href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 22, Col: 61}
}
_, 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
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(caseStudyCardLinkLabel(data))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `case_study_card.templ`, Line: 23, Col: 35}
}
_, 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, 13, "</a></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</article>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func caseStudyCardLinkLabel(data CaseStudyCardData) string {
if data.HrefLabel != "" {
return data.HrefLabel
}
return "Read case study"
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,53 +0,0 @@
package main
// corporateModernistUtilityCSS is appended to the host Tailwind input.css so the
// theme's .cm-* utility classes resolve in the production CSS bundle. The same
// rules also live in assets/style.css so the standalone stylesheet served at
// /templates/corporate-modernist/style.css is self-contained for fallback usage.
//
// Per FONTS.md: no @font-face declarations here. Font faces are emitted by the
// CMS from fonts.json — currently [], so the theme relies on the
// --font-heading / --font-body / --font-mono CSS variables with fallback stacks.
const corporateModernistUtilityCSS = `
/* Corporate Modernist — appended utility CSS. */
.cm-content-well { width: 100%; max-width: 1280px; margin-left: auto; margin-right: auto; padding-left: 1.5rem; padding-right: 1.5rem; box-sizing: border-box; }
.cm-swiss-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; row-gap: 1.5rem; }
.cm-hairline { border-color: hsl(var(--border)); border-width: 1px; border-style: solid; }
.cm-hairline-top { border-top: 1px solid hsl(var(--border)); }
.cm-hairline-bottom { border-bottom: 1px solid hsl(var(--border)); }
.numeric-tabular { font-variant-numeric: tabular-nums; }
.cm-display { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; }
.cm-body { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; font-variant-numeric: tabular-nums; }
.cm-mono { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; }
.cm-accent-rule { border-top: 2px solid hsl(var(--accent)); }
.cm-btn-primary { display: inline-block; padding: 0.625rem 1.25rem; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border: 1px solid hsl(var(--accent)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: background-color 150ms ease; }
.cm-btn-primary:hover { background-color: hsl(var(--accent) / 0.9); }
.cm-btn-primary:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
.cm-btn-outline { display: inline-block; padding: 0.625rem 1.25rem; background-color: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: border-color 150ms ease; }
.cm-btn-outline:hover { border-color: hsl(var(--foreground)); }
.cm-btn-outline:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
.cm-card { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; padding: 1.5rem; box-shadow: none; }
.cm-card.cm-card-accent { border-top: 2px solid hsl(var(--accent)); }
.cm-heading { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; color: hsl(var(--foreground)); margin: 0; }
.cm-heading-h2-accent { border-bottom: 2px solid hsl(var(--accent)); padding-bottom: 0.25rem; display: inline-block; }
.cm-text { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); font-variant-numeric: tabular-nums; hanging-punctuation: first last; }
.cm-logo { filter: grayscale(1); opacity: 0.7; transition: filter 200ms ease, opacity 200ms ease; }
.cm-logo:hover { filter: grayscale(0); opacity: 1; }
.cm-pull-quote { border-top: 2px solid hsl(var(--accent)); padding-top: 1.25rem; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 1.5rem; line-height: 1.4; font-weight: 500; color: hsl(var(--foreground)); }
.cm-metric { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 3rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--accent)); }
.cm-stat-figure { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 2.5rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); }
.cm-stat-label { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.875rem; color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.5rem; }
.cm-eyebrow { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 0.875rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.1em; color: hsl(var(--accent)); margin-bottom: 1rem; }
.cm-cta-strip-accent { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
.cm-cta-strip-accent .cm-btn-primary { background-color: hsl(var(--accent-foreground)); color: hsl(var(--accent)); border-color: hsl(var(--accent-foreground)); }
.cm-cta-strip-quiet { background-color: hsl(var(--muted)); color: hsl(var(--foreground)); }
.cm-footer { background-color: hsl(var(--background)); color: hsl(var(--foreground)); border-top: 1px solid hsl(var(--border)); padding: 3rem 0; }
.cm-footer-legal { color: hsl(var(--muted-foreground)); font-size: 0.875rem; border-top: 1px solid hsl(var(--border)); padding-top: 1.5rem; margin-top: 2rem; }
.cm-leadership-grid { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); gap: 1.5rem; }
@media (min-width: 640px) { .cm-leadership-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cm-leadership-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .cm-leadership-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cm-article-measure { max-width: 70ch; margin-left: auto; margin-right: auto; font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); }
.cm-section { padding-top: 4rem; padding-bottom: 4rem; }
.cm-img-empty { display: block; width: 100%; aspect-ratio: 4 / 3; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }
`

View File

@ -1,58 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// CTAStripMeta is the block metadata for corporate-modernist:cta_strip.
var CTAStripMeta = blocks.BlockMeta{
Key: "cta_strip",
Title: "CTA Strip",
Description: "Single-line accent strip with a headline and a primary call to action.",
Source: "corporate-modernist",
Category: blocks.CategoryLayout,
}
// CTAStripData carries the parsed content for the cta_strip block.
type CTAStripData struct {
Headline string
CTALabel string
CTAHref string
HasCTA bool
Variant string
}
// CTAStripBlock renders the cta_strip block.
func CTAStripBlock(ctx context.Context, content map[string]any) string {
primary := getNested(content, "primaryCta")
ctaLabel := ""
ctaHref := ""
hasCTA := false
if primary != nil {
ctaLabel = linkLabel(primary, "")
ctaHref = linkHref(primary)
if ctaLabel != "" || ctaHref != "#" {
hasCTA = true
}
}
variant := getString(content, "variant")
if variant == "" {
variant = "book-call"
}
data := CTAStripData{
Headline: getString(content, "headline"),
CTALabel: ctaLabel,
CTAHref: ctaHref,
HasCTA: hasCTA,
Variant: variant,
}
var buf bytes.Buffer
_ = ctaStripComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,56 +0,0 @@
package main
// ctaStripComponent renders the corporate-modernist:cta_strip block.
templ ctaStripComponent(data CTAStripData) {
<section
class={ "cm-section", ctaStripVariantClass(data.Variant) }
data-block="corporate-modernist:cta_strip"
data-variant={ data.Variant }
>
<div class="cm-content-well">
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.5rem;">
if data.Headline != "" {
<h2 class="cm-display" style="font-size: 1.75rem; margin: 0; max-width: 36rem;">{ data.Headline }</h2>
} else {
<h2 class="cm-display" style="font-size: 1.75rem; margin: 0; max-width: 36rem;">Ready when you are.</h2>
}
if data.HasCTA {
<a class="cm-btn-primary" href={ templ.SafeURL(data.CTAHref) }>
{ ctaStripLabel(data) }
</a>
} else {
<a class="cm-btn-primary" href="#" aria-disabled="true">
{ ctaStripDefaultLabel(data.Variant) }
</a>
}
</div>
</div>
</section>
}
func ctaStripVariantClass(variant string) string {
switch variant {
case "quiet":
return "cm-cta-strip-quiet"
default:
return "cm-cta-strip-accent"
}
}
func ctaStripLabel(data CTAStripData) string {
if data.CTALabel != "" {
return data.CTALabel
}
return ctaStripDefaultLabel(data.Variant)
}
func ctaStripDefaultLabel(variant string) string {
switch variant {
case "download":
return "Download report"
case "quiet":
return "Learn more"
default:
return "Book a call"
}
}

View File

@ -1,177 +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"
// ctaStripComponent renders the corporate-modernist:cta_strip block.
func ctaStripComponent(data CTAStripData) 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)
var templ_7745c5c3_Var2 = []any{"cm-section", ctaStripVariantClass(data.Variant)}
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, "<section class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" data-block=\"corporate-modernist:cta_strip\" data-variant=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Variant)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 8, Col: 29}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><div class=\"cm-content-well\"><div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.5rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Headline != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h2 class=\"cm-display\" style=\"font-size: 1.75rem; margin: 0; max-width: 36rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Headline)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 13, Col: 100}
}
_, 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, 5, "</h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<h2 class=\"cm-display\" style=\"font-size: 1.75rem; margin: 0; max-width: 36rem;\">Ready when you are.</h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.HasCTA {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<a class=\"cm-btn-primary\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 templ.SafeURL
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.CTAHref))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 18, Col: 65}
}
_, 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, 8, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ctaStripLabel(data))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 19, Col: 27}
}
_, 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, 9, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<a class=\"cm-btn-primary\" href=\"#\" aria-disabled=\"true\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(ctaStripDefaultLabel(data.Variant))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_strip.templ`, Line: 23, Col: 42}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func ctaStripVariantClass(variant string) string {
switch variant {
case "quiet":
return "cm-cta-strip-quiet"
default:
return "cm-cta-strip-accent"
}
}
func ctaStripLabel(data CTAStripData) string {
if data.CTALabel != "" {
return data.CTALabel
}
return ctaStripDefaultLabel(data.Variant)
}
func ctaStripDefaultLabel(variant string) string {
switch variant {
case "download":
return "Download report"
case "quiet":
return "Learn more"
default:
return "Book a call"
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,21 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/templates"
)
// CorporateModernistEmailWrapper wraps body content in a 600px-wide
// Corporate Modernist email. Tokens are locked to the navy-classic light
// preset regardless of the active site preset, in line with §10 of the
// spec, to maximise email-client compatibility.
//
// Colours are expressed via hsl() with the navy-classic HSL triples; no
// hex literals appear in the source.
func CorporateModernistEmailWrapper(body string, emailCtx templates.EmailContext) string {
var buf bytes.Buffer
_ = emailWrapperComponent(emailCtx, body).Render(context.Background(), &buf)
return buf.String()
}

View File

@ -1,117 +0,0 @@
package main
import "git.dev.alexdunmow.com/block/core/templates"
// emailWrapperComponent renders the Corporate Modernist email wrapper.
//
// The wrapper is locked to the navy-classic light preset regardless of the
// active site preset (per spec §10) for email-client compatibility. CSS
// custom properties are declared in <head>; every inline `style="…"`
// references them via var(--cm-email-*) with the navy-classic HSL triple
// as the fallback, so:
// - email clients that strip <style> still get the navy-classic colour;
// - the check-safety inline-colour rule is satisfied (each line uses
// var(--…)).
templ emailWrapperComponent(emailCtx templates.EmailContext, body string) {
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="x-apple-disable-message-reformatting"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>{ emailCtx.SiteSettings.SiteName }</title>
<style type="text/css">
:root {
--cm-email-bg: hsl(220 14% 96%);
--cm-email-surface: hsl(0 0% 100%);
--cm-email-fg: hsl(220 20% 12%);
--cm-email-muted-fg: hsl(220 10% 40%);
--cm-email-border: hsl(220 14% 90%);
--cm-email-accent: hsl(218 65% 22%);
}
body, table, td, p, a, li, blockquote { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
h1, h2, h3, h4, h5, h6 { font-family: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 600; letter-spacing: -0.02em; }
@media only screen and (max-width: 620px) {
.cm-email-container { width: 100% !important; max-width: 100% !important; }
.cm-email-padding { padding-left: 24px !important; padding-right: 24px !important; }
}
</style>
</head>
<body style="background-color: var(--cm-email-bg, hsl(220 14% 96%)); margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
if emailCtx.PreviewText != "" {
<div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">
{ emailCtx.PreviewText }
</div>
}
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td align="center" style="padding: 32px 12px; background-color: var(--cm-email-bg, hsl(220 14% 96%));">
<table role="presentation" class="cm-email-container" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; width: 600px; background-color: var(--cm-email-surface, hsl(0 0% 100%)); border: 1px solid var(--cm-email-border, hsl(220 14% 90%)); border-collapse: separate;">
<!-- Header: title + single accent rule -->
<tr>
<td class="cm-email-padding" style="padding: 32px 48px 16px 48px; background-color: var(--cm-email-surface, hsl(0 0% 100%));">
if emailCtx.SiteSettings.LogoURL != "" {
<img src={ emailCtx.SiteSettings.LogoURL } alt={ emailCtx.SiteSettings.SiteName } style="max-height: 36px; width: auto; display: block;"/>
} else if emailCtx.SiteSettings.SiteName != "" {
<h1 style="margin: 0; font-size: 20px; font-weight: 600; color: var(--cm-email-fg, hsl(220 20% 12%)); letter-spacing: -0.02em; font-family: 'Inter Tight', 'Inter', sans-serif;">
{ emailCtx.SiteSettings.SiteName }
</h1>
}
</td>
</tr>
<tr>
<td style="padding: 0 48px;">
<div style="height: 2px; background-color: var(--cm-email-accent, hsl(218 65% 22%)); line-height: 2px; font-size: 0;">&nbsp;</div>
</td>
</tr>
<!-- Body -->
<tr>
<td class="cm-email-padding" style="padding: 32px 48px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-size: 16px; line-height: 1.6; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
@templ.Raw(body)
</td>
</tr>
<!-- Footer: legal line + unsubscribe -->
<tr>
<td class="cm-email-padding" style="padding: 24px 48px 32px 48px; border-top: 1px solid var(--cm-email-border, hsl(220 14% 90%));">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td align="left">
if emailCtx.SiteSettings.SiteName != "" {
<p style="margin: 0 0 6px 0; font-size: 13px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-family: 'Inter Tight', 'Inter', sans-serif; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;">
{ emailCtx.SiteSettings.SiteName }
</p>
}
<p style="margin: 0 0 12px 0; font-size: 12px; color: var(--cm-email-muted-fg, hsl(220 10% 40%)); font-family: 'Inter', sans-serif;">
You are receiving this email because you subscribed to updates.
</p>
if emailCtx.SiteSettings.SiteURL != "" {
<p style="margin: 0 0 8px 0; font-size: 12px;">
<a href={ templ.SafeURL(emailCtx.SiteSettings.SiteURL) } style="color: var(--cm-email-accent, hsl(218 65% 22%)); text-decoration: none;">
{ emailCtx.SiteSettings.SiteURL }
</a>
</p>
}
if emailCtx.UnsubscribeURL != "" {
<p style="margin: 0; font-size: 11px;">
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style="color: var(--cm-email-muted-fg, hsl(220 10% 40%)); text-decoration: underline;">
Unsubscribe
</a>
</p>
}
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
}

View File

@ -1,228 +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 "git.dev.alexdunmow.com/block/core/templates"
// emailWrapperComponent renders the Corporate Modernist email wrapper.
//
// The wrapper is locked to the navy-classic light preset regardless of the
// active site preset (per spec §10) for email-client compatibility. CSS
// custom properties are declared in <head>; every inline `style="…"`
// references them via var(--cm-email-*) with the navy-classic HSL triple
// as the fallback, so:
// - email clients that strip <style> still get the navy-classic colour;
// - the check-safety inline-colour rule is satisfied (each line uses
// var(--…)).
func emailWrapperComponent(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, "<!doctype html><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"x-apple-disable-message-reformatting\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><title>")
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: 23, Col: 42}
}
_, 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, "</title><style type=\"text/css\">\n\t\t\t\t:root {\n\t\t\t\t\t--cm-email-bg: hsl(220 14% 96%);\n\t\t\t\t\t--cm-email-surface: hsl(0 0% 100%);\n\t\t\t\t\t--cm-email-fg: hsl(220 20% 12%);\n\t\t\t\t\t--cm-email-muted-fg: hsl(220 10% 40%);\n\t\t\t\t\t--cm-email-border: hsl(220 14% 90%);\n\t\t\t\t\t--cm-email-accent: hsl(218 65% 22%);\n\t\t\t\t}\n\t\t\t\tbody, table, td, p, a, li, blockquote { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }\n\t\t\t\ttable, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }\n\t\t\t\timg { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }\n\t\t\t\tbody { margin: 0 !important; padding: 0 !important; width: 100% !important; }\n\t\t\t\ta[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }\n\t\t\t\th1, h2, h3, h4, h5, h6 { font-family: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 600; letter-spacing: -0.02em; }\n\t\t\t\t@media only screen and (max-width: 620px) {\n\t\t\t\t\t.cm-email-container { width: 100% !important; max-width: 100% !important; }\n\t\t\t\t\t.cm-email-padding { padding-left: 24px !important; padding-right: 24px !important; }\n\t\t\t\t}\n\t\t\t</style></head><body style=\"background-color: var(--cm-email-bg, hsl(220 14% 96%)); margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.PreviewText != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div style=\"display: none; max-height: 0; overflow: hidden; mso-hide: all;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.PreviewText)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 48, Col: 27}
}
_, 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, 4, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tr><td align=\"center\" style=\"padding: 32px 12px; background-color: var(--cm-email-bg, hsl(220 14% 96%));\"><table role=\"presentation\" class=\"cm-email-container\" width=\"600\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"max-width: 600px; width: 600px; background-color: var(--cm-email-surface, hsl(0 0% 100%)); border: 1px solid var(--cm-email-border, hsl(220 14% 90%)); border-collapse: separate;\"><!-- Header: title + single accent rule --><tr><td class=\"cm-email-padding\" style=\"padding: 32px 48px 16px 48px; background-color: var(--cm-email-surface, hsl(0 0% 100%));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.SiteSettings.LogoURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(emailCtx.SiteSettings.LogoURL)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 59, Col: 50}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(emailCtx.SiteSettings.SiteName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 59, Col: 89}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"max-height: 36px; width: auto; display: block;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else if emailCtx.SiteSettings.SiteName != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<h1 style=\"margin: 0; font-size: 20px; font-weight: 600; color: var(--cm-email-fg, hsl(220 20% 12%)); letter-spacing: -0.02em; font-family: 'Inter Tight', 'Inter', sans-serif;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, 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: 62, Col: 43}
}
_, 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, 10, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</td></tr><tr><td style=\"padding: 0 48px;\"><div style=\"height: 2px; background-color: var(--cm-email-accent, hsl(218 65% 22%)); line-height: 2px; font-size: 0;\">&nbsp;</div></td></tr><!-- Body --><tr><td class=\"cm-email-padding\" style=\"padding: 32px 48px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-size: 16px; line-height: 1.6; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\">")
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, 12, "</td></tr><!-- Footer: legal line + unsubscribe --><tr><td class=\"cm-email-padding\" style=\"padding: 24px 48px 32px 48px; border-top: 1px solid var(--cm-email-border, hsl(220 14% 90%));\"><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tr><td align=\"left\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.SiteSettings.SiteName != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<p style=\"margin: 0 0 6px 0; font-size: 13px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-family: 'Inter Tight', 'Inter', sans-serif; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, 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: 86, Col: 46}
}
_, 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, 14, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<p style=\"margin: 0 0 12px 0; font-size: 12px; color: var(--cm-email-muted-fg, hsl(220 10% 40%)); font-family: 'Inter', sans-serif;\">You are receiving this email because you subscribed to updates.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.SiteSettings.SiteURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<p style=\"margin: 0 0 8px 0; font-size: 12px;\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 templ.SafeURL
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(emailCtx.SiteSettings.SiteURL))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 94, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" style=\"color: var(--cm-email-accent, hsl(218 65% 22%)); text-decoration: none;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, 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: 95, Col: 46}
}
_, 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, 18, "</a></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if emailCtx.UnsubscribeURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<p style=\"margin: 0; font-size: 11px;\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 templ.SafeURL
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(emailCtx.UnsubscribeURL))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 101, Col: 62}
}
_, 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, 20, "\" style=\"color: var(--cm-email-muted-fg, hsl(220 10% 40%)); text-decoration: underline;\">Unsubscribe</a></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</td></tr></table></td></tr></table></td></tr></table></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,49 +0,0 @@
package main
import (
"embed"
"io/fs"
"net/http"
)
//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 rooted at assets/.
func Assets() fs.FS {
sub, _ := fs.Sub(assetsFS, "assets")
return sub
}
// Schemas returns the embedded schemas filesystem rooted at schemas/.
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
}

View File

@ -1,75 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// FooterMeta is the block metadata for corporate-modernist:footer.
var FooterMeta = blocks.BlockMeta{
Key: "footer",
Title: "Footer",
Description: "Multi-column footer with legal line; compact and full variants.",
Source: "corporate-modernist",
Category: blocks.CategoryNavigation,
}
// FooterLink represents a single link in a footer column.
type FooterLink struct {
Label string
Href string
}
// FooterColumn is a single labelled column of footer links.
type FooterColumn struct {
Title string
Links []FooterLink
}
// FooterData carries the parsed content for the footer block.
type FooterData struct {
Columns []FooterColumn
LegalLine string
ShowLegal bool
Variant string
}
// FooterBlock renders the footer block.
func FooterBlock(ctx context.Context, content map[string]any) string {
rawColumns := getSlice(content, "columns")
columns := make([]FooterColumn, 0, len(rawColumns))
for _, c := range rawColumns {
rawLinks := getSlice(c, "links")
links := make([]FooterLink, 0, len(rawLinks))
for _, l := range rawLinks {
label := linkLabel(l, "")
href := linkHref(l)
if label == "" && href == "#" {
continue
}
links = append(links, FooterLink{Label: label, Href: href})
}
columns = append(columns, FooterColumn{
Title: getString(c, "title"),
Links: links,
})
}
variant := getString(content, "variant")
if variant == "" {
variant = "compact"
}
data := FooterData{
Columns: columns,
LegalLine: getString(content, "legalLine"),
ShowLegal: getBool(content, "showLegal", true),
Variant: variant,
}
var buf bytes.Buffer
_ = footerComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,60 +0,0 @@
package main
// footerComponent renders the corporate-modernist:footer block.
templ footerComponent(data FooterData) {
<div class="cm-footer" data-block="corporate-modernist:footer" data-variant={ data.Variant }>
<div class="cm-content-well">
if data.Variant == "full" && len(data.Columns) > 0 {
<div class="cm-swiss-12">
for _, col := range data.Columns {
<div style={ footerColumnSpan(len(data.Columns)) }>
if col.Title != "" {
<div class="cm-display" style="font-size: 0.875rem; font-weight: 600; margin: 0 0 0.75rem 0; text-transform: uppercase; letter-spacing: 0.05em;">{ col.Title }</div>
}
if len(col.Links) > 0 {
<ul style="list-style: none; padding: 0; margin: 0;">
for _, l := range col.Links {
<li style="margin-bottom: 0.5rem;">
<a href={ templ.SafeURL(l.Href) } class="cm-text" style="font-size: 0.95rem; text-decoration: none;">
{ footerLinkLabel(l) }
</a>
</li>
}
</ul>
}
</div>
}
</div>
}
if data.ShowLegal {
<div class="cm-footer-legal">
if data.LegalLine != "" {
{ data.LegalLine }
} else {
All rights reserved.
}
</div>
}
</div>
</div>
}
func footerLinkLabel(l FooterLink) string {
if l.Label != "" {
return l.Label
}
return l.Href
}
func footerColumnSpan(count int) string {
switch {
case count >= 4:
return "grid-column: span 3 / span 3;"
case count == 3:
return "grid-column: span 4 / span 4;"
case count == 2:
return "grid-column: span 6 / span 6;"
default:
return "grid-column: span 12 / span 12;"
}
}

View File

@ -1,198 +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 corporate-modernist:footer block.
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, "<div class=\"cm-footer\" data-block=\"corporate-modernist:footer\" data-variant=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Variant)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 5, Col: 91}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\"><div class=\"cm-content-well\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Variant == "full" && len(data.Columns) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"cm-swiss-12\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, col := range data.Columns {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(footerColumnSpan(len(data.Columns)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 10, Col: 54}
}
_, 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, 5, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if col.Title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"cm-display\" style=\"font-size: 0.875rem; font-weight: 600; margin: 0 0 0.75rem 0; text-transform: uppercase; letter-spacing: 0.05em;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(col.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 12, Col: 164}
}
_, 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, 7, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(col.Links) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<ul style=\"list-style: none; padding: 0; margin: 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, l := range col.Links {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<li style=\"margin-bottom: 0.5rem;\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(l.Href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 18, Col: 42}
}
_, 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, 10, "\" class=\"cm-text\" style=\"font-size: 0.95rem; text-decoration: none;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(footerLinkLabel(l))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 19, Col: 32}
}
_, 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, 11, "</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</ul>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.ShowLegal {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<div class=\"cm-footer-legal\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.LegalLine != "" {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(data.LegalLine)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 32, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "All rights reserved.")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func footerLinkLabel(l FooterLink) string {
if l.Label != "" {
return l.Label
}
return l.Href
}
func footerColumnSpan(count int) string {
switch {
case count >= 4:
return "grid-column: span 3 / span 3;"
case count == 3:
return "grid-column: span 4 / span 4;"
case count == 2:
return "grid-column: span 6 / span 6;"
default:
return "grid-column: span 12 / span 12;"
}
}
var _ = templruntime.GeneratedTemplate

20
go.mod
View File

@ -1,20 +0,0 @@
module git.dev.alexdunmow.com/block/themes/corporate-modernist
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
)

46
go.sum
View File

@ -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=

View File

@ -1,41 +0,0 @@
package main
import (
"bytes"
"context"
"strconv"
)
// CorporateModernistHeadingBlock renders the built-in `heading` block with
// the Corporate Modernist treatment: tighter tracking, weights restricted to
// 500/600, accent underline on H2.
func CorporateModernistHeadingBlock(ctx context.Context, content map[string]any) string {
text := getString(content, "text")
textClass := getString(content, "textClass")
level := parseHeadingLevel(content)
var buf bytes.Buffer
_ = headingOverrideComponent(level, text, textClass).Render(ctx, &buf)
return buf.String()
}
// parseHeadingLevel pulls a level (1-6) from the block content map.
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
}

View File

@ -1,57 +0,0 @@
package main
// headingOverrideComponent renders the Corporate Modernist heading override.
// All levels share the .cm-heading base; H2 picks up the accent underline.
templ headingOverrideComponent(level int, text, textClass string) {
switch level {
case 1:
<h1 class={ "cm-heading", headingOverrideSizeClass(1), textClass } style="font-size: clamp(2rem, 4vw, 3rem); line-height: 1.1;">
{ text }
</h1>
case 2:
<h2 class={ "cm-heading", headingOverrideSizeClass(2), textClass } style="font-size: clamp(1.5rem, 3vw, 2.25rem); line-height: 1.2;">
<span class="cm-heading-h2-accent">{ text }</span>
</h2>
case 3:
<h3 class={ "cm-heading", headingOverrideSizeClass(3), textClass } style="font-size: 1.5rem; line-height: 1.3;">
{ text }
</h3>
case 4:
<h4 class={ "cm-heading", headingOverrideSizeClass(4), textClass } style="font-size: 1.25rem; line-height: 1.3;">
{ text }
</h4>
case 5:
<h5 class={ "cm-heading", headingOverrideSizeClass(5), textClass } style="font-size: 1.125rem; line-height: 1.4;">
{ text }
</h5>
case 6:
<h6 class={ "cm-heading", headingOverrideSizeClass(6), textClass } style="font-size: 1rem; line-height: 1.4;">
{ text }
</h6>
default:
<h2 class={ "cm-heading", headingOverrideSizeClass(2), textClass } style="font-size: clamp(1.5rem, 3vw, 2.25rem); line-height: 1.2;">
<span class="cm-heading-h2-accent">{ text }</span>
</h2>
}
}
// headingOverrideSizeClass keeps the Tailwind-style size hooks predictable for
// downstream tooling without baking sizes into hardcoded classes.
func headingOverrideSizeClass(level int) string {
switch level {
case 1:
return "cm-heading-h1"
case 2:
return "cm-heading-h2"
case 3:
return "cm-heading-h3"
case 4:
return "cm-heading-h4"
case 5:
return "cm-heading-h5"
case 6:
return "cm-heading-h6"
default:
return "cm-heading-h2"
}
}

View File

@ -1,313 +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"
// headingOverrideComponent renders the Corporate Modernist heading override.
// All levels share the .cm-heading base; H2 picks up the accent underline.
func headingOverrideComponent(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{"cm-heading", headingOverrideSizeClass(1), 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, "<h1 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" style=\"font-size: clamp(2rem, 4vw, 3rem); line-height: 1.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: `heading_override.templ`, Line: 9, 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, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 2:
var templ_7745c5c3_Var5 = []any{"cm-heading", headingOverrideSizeClass(2), 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, "<h2 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var5).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" style=\"font-size: clamp(1.5rem, 3vw, 2.25rem); line-height: 1.2;\"><span class=\"cm-heading-h2-accent\">")
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: `heading_override.templ`, Line: 13, Col: 45}
}
_, 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, "</span></h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 3:
var templ_7745c5c3_Var8 = []any{"cm-heading", headingOverrideSizeClass(3), 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, "<h3 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var8).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"font-size: 1.5rem; line-height: 1.3;\">")
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: `heading_override.templ`, Line: 17, 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, "</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 4:
var templ_7745c5c3_Var11 = []any{"cm-heading", headingOverrideSizeClass(4), 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, "<h4 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var11).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\" style=\"font-size: 1.25rem; line-height: 1.3;\">")
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: `heading_override.templ`, Line: 21, 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, "</h4>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 5:
var templ_7745c5c3_Var14 = []any{"cm-heading", headingOverrideSizeClass(5), 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, "<h5 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var14).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" style=\"font-size: 1.125rem; line-height: 1.4;\">")
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: `heading_override.templ`, Line: 25, 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, "</h5>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 6:
var templ_7745c5c3_Var17 = []any{"cm-heading", headingOverrideSizeClass(6), 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, "<h6 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var17).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" style=\"font-size: 1rem; line-height: 1.4;\">")
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: `heading_override.templ`, Line: 29, 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, "</h6>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
default:
var templ_7745c5c3_Var20 = []any{"cm-heading", headingOverrideSizeClass(2), 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, "<h2 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var20).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\" style=\"font-size: clamp(1.5rem, 3vw, 2.25rem); line-height: 1.2;\"><span class=\"cm-heading-h2-accent\">")
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: `heading_override.templ`, Line: 33, Col: 45}
}
_, 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, "</span></h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
// headingOverrideSizeClass keeps the Tailwind-style size hooks predictable for
// downstream tooling without baking sizes into hardcoded classes.
func headingOverrideSizeClass(level int) string {
switch level {
case 1:
return "cm-heading-h1"
case 2:
return "cm-heading-h2"
case 3:
return "cm-heading-h3"
case 4:
return "cm-heading-h4"
case 5:
return "cm-heading-h5"
case 6:
return "cm-heading-h6"
default:
return "cm-heading-h2"
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,82 +0,0 @@
package main
import "strconv"
// getString extracts a string value from content map.
func getString(content map[string]any, key string) string {
if content == nil {
return ""
}
if v, ok := content[key].(string); ok {
return v
}
return ""
}
// getBool extracts a bool value from content map (handles JSON unmarshalling forms).
func getBool(content map[string]any, key string, defaultVal bool) bool {
if content == nil {
return defaultVal
}
if v, ok := content[key].(bool); ok {
return v
}
if v, ok := content[key].(string); ok {
if b, err := strconv.ParseBool(v); err == nil {
return b
}
}
return defaultVal
}
// getSlice extracts a slice of maps from content.
func getSlice(content map[string]any, key string) []map[string]any {
if content == nil {
return nil
}
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
}
// getNested extracts a nested map from content for sub-object fields (e.g. CTA link).
func getNested(content map[string]any, key string) map[string]any {
if content == nil {
return nil
}
if v, ok := content[key].(map[string]any); ok {
return v
}
return nil
}
// linkHref returns the href value from a link object (label/href shape),
// defaulting to "#" when missing so anchors stay valid.
func linkHref(link map[string]any) string {
if href := getString(link, "href"); href != "" {
return href
}
if url := getString(link, "url"); url != "" {
return url
}
return "#"
}
// linkLabel returns the visible label for a link object.
func linkLabel(link map[string]any, fallback string) string {
if label := getString(link, "label"); label != "" {
return label
}
if text := getString(link, "text"); text != "" {
return text
}
return fallback
}

View File

@ -1,66 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// HeroStatementMeta is the block metadata for corporate-modernist:hero_statement.
var HeroStatementMeta = blocks.BlockMeta{
Key: "hero_statement",
Title: "Hero Statement",
Description: "Restrained hero with eyebrow, headline, lede, and a single accent CTA.",
Source: "corporate-modernist",
Category: blocks.CategoryLayout,
}
// HeroStatementCTA captures a single label/href pair for hero CTAs.
type HeroStatementCTA struct {
Label string
Href string
}
// HeroStatementData carries the parsed content for the hero_statement block.
type HeroStatementData struct {
Eyebrow string
Headline string
Lede string
PrimaryCTA HeroStatementCTA
HasPrimary bool
SecondaryCTA HeroStatementCTA
HasSecondary bool
}
// HeroStatementBlock renders the hero_statement block.
func HeroStatementBlock(ctx context.Context, content map[string]any) string {
primary := getNested(content, "primaryCta")
secondary := getNested(content, "secondaryCta")
data := HeroStatementData{
Eyebrow: getString(content, "eyebrow"),
Headline: getString(content, "headline"),
Lede: getString(content, "lede"),
}
if primary != nil {
label := linkLabel(primary, "")
href := linkHref(primary)
if label != "" || href != "#" {
data.PrimaryCTA = HeroStatementCTA{Label: label, Href: href}
data.HasPrimary = true
}
}
if secondary != nil {
label := linkLabel(secondary, "")
href := linkHref(secondary)
if label != "" || href != "#" {
data.SecondaryCTA = HeroStatementCTA{Label: label, Href: href}
data.HasSecondary = true
}
}
var buf bytes.Buffer
_ = heroStatementComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,45 +0,0 @@
package main
// heroStatementComponent renders the corporate-modernist:hero_statement block.
templ heroStatementComponent(data HeroStatementData) {
<section class="cm-section" data-block="corporate-modernist:hero_statement">
<div class="cm-content-well">
<div class="cm-swiss-12">
<div style="grid-column: span 12 / span 12;">
if data.Eyebrow != "" {
<div class="cm-eyebrow">{ data.Eyebrow }</div>
}
if data.Headline != "" {
<h1 class="cm-display" style="font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.1; margin: 0 0 1.25rem 0;">
{ data.Headline }
</h1>
}
if data.Lede != "" {
<p class="cm-text" style="max-width: 60ch; margin: 0 0 2rem 0;">{ data.Lede }</p>
}
if data.HasPrimary || data.HasSecondary {
<div style="display: flex; flex-wrap: wrap; gap: 0.75rem;">
if data.HasPrimary {
<a class="cm-btn-primary" href={ templ.SafeURL(data.PrimaryCTA.Href) }>
{ heroStatementLabel(data.PrimaryCTA.Label, "Get in touch") }
</a>
}
if data.HasSecondary {
<a class="cm-btn-outline" href={ templ.SafeURL(data.SecondaryCTA.Href) }>
{ heroStatementLabel(data.SecondaryCTA.Label, "Learn more") }
</a>
}
</div>
}
</div>
</div>
</div>
</section>
}
func heroStatementLabel(label, fallback string) string {
if label != "" {
return label
}
return fallback
}

View File

@ -1,183 +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"
// heroStatementComponent renders the corporate-modernist:hero_statement block.
func heroStatementComponent(data HeroStatementData) 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, "<section class=\"cm-section\" data-block=\"corporate-modernist:hero_statement\"><div class=\"cm-content-well\"><div class=\"cm-swiss-12\"><div style=\"grid-column: span 12 / span 12;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Eyebrow != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"cm-eyebrow\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Eyebrow)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 10, Col: 44}
}
_, 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, 3, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Headline != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h1 class=\"cm-display\" style=\"font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.1; margin: 0 0 1.25rem 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Headline)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 14, Col: 22}
}
_, 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, 5, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Lede != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<p class=\"cm-text\" style=\"max-width: 60ch; margin: 0 0 2rem 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Lede)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 18, Col: 81}
}
_, 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, 7, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.HasPrimary || data.HasSecondary {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div style=\"display: flex; flex-wrap: wrap; gap: 0.75rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.HasPrimary {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<a class=\"cm-btn-primary\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.PrimaryCTA.Href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 23, Col: 76}
}
_, 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, 10, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(heroStatementLabel(data.PrimaryCTA.Label, "Get in touch"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 24, Col: 68}
}
_, 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, 11, "</a> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.HasSecondary {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<a class=\"cm-btn-outline\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 templ.SafeURL
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.SecondaryCTA.Href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 28, Col: 78}
}
_, 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, 13, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(heroStatementLabel(data.SecondaryCTA.Label, "Learn more"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_statement.templ`, Line: 29, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</div></div></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func heroStatementLabel(label, fallback string) string {
if label != "" {
return label
}
return fallback
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,60 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// LeadershipGridMeta is the block metadata for corporate-modernist:leadership_grid.
var LeadershipGridMeta = blocks.BlockMeta{
Key: "leadership_grid",
Title: "Leadership Grid",
Description: "Responsive 2/3/4-up grid of leadership profiles.",
Source: "corporate-modernist",
Category: blocks.CategoryContent,
}
// LeadershipGridMember represents one leader entry.
type LeadershipGridMember struct {
Name string
Role string
Bio string
Photo string
LinkedIn string
}
// LeadershipGridData carries the parsed content for the leadership_grid block.
type LeadershipGridData struct {
Title string
Members []LeadershipGridMember
}
// LeadershipGridBlock renders the leadership_grid block.
func LeadershipGridBlock(ctx context.Context, content map[string]any) string {
rawMembers := getSlice(content, "members")
members := make([]LeadershipGridMember, 0, len(rawMembers))
for _, m := range rawMembers {
name := getString(m, "name")
if name == "" {
continue
}
members = append(members, LeadershipGridMember{
Name: name,
Role: getString(m, "role"),
Bio: getString(m, "bio"),
Photo: getString(m, "photo"),
LinkedIn: getString(m, "linkedin"),
})
}
data := LeadershipGridData{
Title: getString(content, "title"),
Members: members,
}
var buf bytes.Buffer
_ = leadershipGridComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,48 +0,0 @@
package main
// leadershipGridComponent renders the corporate-modernist:leadership_grid block.
templ leadershipGridComponent(data LeadershipGridData) {
<section class="cm-section" data-block="corporate-modernist:leadership_grid">
<div class="cm-content-well">
if data.Title != "" {
<h2 class="cm-heading" style="font-size: 1.875rem; margin: 0 0 2rem 0;">
<span class="cm-heading-h2-accent">{ data.Title }</span>
</h2>
}
if len(data.Members) > 0 {
<div class="cm-leadership-grid">
for _, m := range data.Members {
<article class="cm-card">
if m.Photo != "" {
<img src={ m.Photo } alt={ leadershipGridPhotoAlt(m) } style="width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; margin-bottom: 1rem; border-radius: 4px;"/>
} else {
<span class="cm-img-empty" style="aspect-ratio: 1 / 1; margin-bottom: 1rem; border-radius: 4px;"></span>
}
<div class="cm-display" style="font-size: 1.125rem; font-weight: 600; margin: 0;">{ m.Name }</div>
if m.Role != "" {
<div class="cm-stat-label" style="margin-top: 0.25rem;">{ m.Role }</div>
}
if m.Bio != "" {
<p class="cm-text" style="margin: 0.75rem 0 0 0; font-size: 0.95rem; line-height: 1.55;">{ m.Bio }</p>
}
if m.LinkedIn != "" {
<div style="margin-top: 1rem;">
<a class="cm-btn-outline" href={ templ.SafeURL(m.LinkedIn) } style="font-size: 0.875rem; padding: 0.375rem 0.75rem;">LinkedIn</a>
</div>
}
</article>
}
</div>
} else {
<p class="cm-stat-label">No team members configured.</p>
}
</div>
</section>
}
func leadershipGridPhotoAlt(m LeadershipGridMember) string {
if m.Name != "" {
return m.Name
}
return "Team member portrait"
}

View File

@ -1,207 +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"
// leadershipGridComponent renders the corporate-modernist:leadership_grid block.
func leadershipGridComponent(data LeadershipGridData) 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, "<section class=\"cm-section\" data-block=\"corporate-modernist:leadership_grid\"><div class=\"cm-content-well\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<h2 class=\"cm-heading\" style=\"font-size: 1.875rem; margin: 0 0 2rem 0;\"><span class=\"cm-heading-h2-accent\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 9, Col: 52}
}
_, 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, 3, "</span></h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(data.Members) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"cm-leadership-grid\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, m := range data.Members {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<article class=\"cm-card\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if m.Photo != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Photo)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 17, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(leadershipGridPhotoAlt(m))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 17, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; margin-bottom: 1rem; border-radius: 4px;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<span class=\"cm-img-empty\" style=\"aspect-ratio: 1 / 1; margin-bottom: 1rem; border-radius: 4px;\"></span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"cm-display\" style=\"font-size: 1.125rem; font-weight: 600; margin: 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(m.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 21, Col: 97}
}
_, 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, 11, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if m.Role != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<div class=\"cm-stat-label\" style=\"margin-top: 0.25rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(m.Role)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 23, Col: 72}
}
_, 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, 13, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if m.Bio != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<p class=\"cm-text\" style=\"margin: 0.75rem 0 0 0; font-size: 0.95rem; line-height: 1.55;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(m.Bio)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 26, Col: 104}
}
_, 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, 15, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if m.LinkedIn != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<div style=\"margin-top: 1rem;\"><a class=\"cm-btn-outline\" href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 templ.SafeURL
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(m.LinkedIn))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `leadership_grid.templ`, Line: 30, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" style=\"font-size: 0.875rem; padding: 0.375rem 0.75rem;\">LinkedIn</a></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</article>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<p class=\"cm-stat-label\">No team members configured.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func leadershipGridPhotoAlt(m LeadershipGridMember) string {
if m.Name != "" {
return m.Name
}
return "Team member portrait"
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,55 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// LogoStripMeta is the block metadata for corporate-modernist:logo_strip.
var LogoStripMeta = blocks.BlockMeta{
Key: "logo_strip",
Title: "Client Logo Strip",
Description: "Row of client logos, greyscale until hover.",
Source: "corporate-modernist",
Category: blocks.CategoryContent,
}
// LogoStripItem represents a single logo entry in the strip.
type LogoStripItem struct {
Src string
Alt string
Href string
}
// LogoStripData carries the parsed content for the logo_strip block.
type LogoStripData struct {
Caption string
Logos []LogoStripItem
}
// LogoStripBlock renders the logo_strip block.
func LogoStripBlock(ctx context.Context, content map[string]any) string {
rawLogos := getSlice(content, "logos")
logos := make([]LogoStripItem, 0, len(rawLogos))
for _, l := range rawLogos {
alt := getString(l, "alt")
src := getString(l, "src")
href := getString(l, "href")
// Skip entries with no asset reference and no alt text.
if src == "" && alt == "" {
continue
}
logos = append(logos, LogoStripItem{Src: src, Alt: alt, Href: href})
}
data := LogoStripData{
Caption: getString(content, "caption"),
Logos: logos,
}
var buf bytes.Buffer
_ = logoStripComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,44 +0,0 @@
package main
// logoStripComponent renders the corporate-modernist:logo_strip block.
templ logoStripComponent(data LogoStripData) {
<section class="cm-section" data-block="corporate-modernist:logo_strip">
<div class="cm-content-well">
if data.Caption != "" {
<p class="cm-stat-label" style="text-align: center; margin-bottom: 2rem;">{ data.Caption }</p>
}
if len(data.Logos) > 0 {
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2.5rem;">
for _, logo := range data.Logos {
if logo.Href != "" {
<a href={ templ.SafeURL(logo.Href) } class="cm-logo" style="display: inline-flex; align-items: center;">
@logoStripImage(logo)
</a>
} else {
<span class="cm-logo" style="display: inline-flex; align-items: center;">
@logoStripImage(logo)
</span>
}
}
</div>
} else {
<p class="cm-stat-label" style="text-align: center;">No client logos configured.</p>
}
</div>
</section>
}
templ logoStripImage(logo LogoStripItem) {
if logo.Src != "" {
<img src={ logo.Src } alt={ logoStripAlt(logo) } style="max-height: 2rem; width: auto; display: block;"/>
} else {
<span class="cm-stat-label" style="margin: 0;">{ logoStripAlt(logo) }</span>
}
}
func logoStripAlt(logo LogoStripItem) string {
if logo.Alt != "" {
return logo.Alt
}
return "Client logo"
}

View File

@ -1,203 +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"
// logoStripComponent renders the corporate-modernist:logo_strip block.
func logoStripComponent(data LogoStripData) 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, "<section class=\"cm-section\" data-block=\"corporate-modernist:logo_strip\"><div class=\"cm-content-well\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Caption != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"cm-stat-label\" style=\"text-align: center; margin-bottom: 2rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Caption)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `logo_strip.templ`, Line: 8, Col: 92}
}
_, 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, 3, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(data.Logos) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2.5rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, logo := range data.Logos {
if logo.Href != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 templ.SafeURL
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(logo.Href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `logo_strip.templ`, Line: 14, 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, 6, "\" class=\"cm-logo\" style=\"display: inline-flex; align-items: center;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = logoStripImage(logo).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<span class=\"cm-logo\" style=\"display: inline-flex; align-items: center;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = logoStripImage(logo).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<p class=\"cm-stat-label\" style=\"text-align: center;\">No client logos configured.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func logoStripImage(logo LogoStripItem) 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)
if logo.Src != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Src)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `logo_strip.templ`, Line: 33, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(logoStripAlt(logo))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `logo_strip.templ`, Line: 33, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\" style=\"max-height: 2rem; width: auto; display: block;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<span class=\"cm-stat-label\" style=\"margin: 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(logoStripAlt(logo))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `logo_strip.templ`, Line: 35, Col: 69}
}
_, 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, 17, "</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
func logoStripAlt(logo LogoStripItem) string {
if logo.Alt != "" {
return logo.Alt
}
return "Client logo"
}
var _ = templruntime.GeneratedTemplate

17
main.go
View File

@ -1,17 +0,0 @@
//go:build wasip1
// Package main compiles the corporate-modernist 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

85
manifest.yaml Normal file
View File

@ -0,0 +1,85 @@
# Corporate Modernist theme — codeless .bnp manifest (WO-WZ-021 Phase B).
# 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: corporate-modernist
title: Corporate Modernist
description: "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites."
page_templates:
- system: corporate-modernist
key: default
title: Default
description: "Header + 12-col main + footer, capped at 1280px."
slots: [header, main, footer]
- system: corporate-modernist
key: landing
title: Landing
description: "Hero band + main + closing CTA + footer."
slots: [hero, main, cta, footer]
- system: corporate-modernist
key: article
title: Article
description: "Centered measure for long-form thought leadership."
slots: [header, main, aside, footer]
- system: corporate-modernist
key: full-width
title: Full width
description: "Edge-to-edge sections, internal grid kept."
slots: [header, main, footer]
template_overrides:
- { template: corporate-modernist, block: heading }
- { template: corporate-modernist, block: text }
- { template: corporate-modernist, block: button }
- { template: corporate-modernist, block: card }
email_wrappers:
- corporate-modernist
css:
input_css_append: |
/* Corporate Modernist — appended utility CSS. */
.cm-content-well { width: 100%; max-width: 1280px; margin-left: auto; margin-right: auto; padding-left: 1.5rem; padding-right: 1.5rem; box-sizing: border-box; }
.cm-swiss-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; row-gap: 1.5rem; }
.cm-hairline { border-color: hsl(var(--border)); border-width: 1px; border-style: solid; }
.cm-hairline-top { border-top: 1px solid hsl(var(--border)); }
.cm-hairline-bottom { border-bottom: 1px solid hsl(var(--border)); }
.numeric-tabular { font-variant-numeric: tabular-nums; }
.cm-display { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; }
.cm-body { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; font-variant-numeric: tabular-nums; }
.cm-mono { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; }
.cm-accent-rule { border-top: 2px solid hsl(var(--accent)); }
.cm-btn-primary { display: inline-block; padding: 0.625rem 1.25rem; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border: 1px solid hsl(var(--accent)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: background-color 150ms ease; }
.cm-btn-primary:hover { background-color: hsl(var(--accent) / 0.9); }
.cm-btn-primary:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
.cm-btn-outline { display: inline-block; padding: 0.625rem 1.25rem; background-color: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: border-color 150ms ease; }
.cm-btn-outline:hover { border-color: hsl(var(--foreground)); }
.cm-btn-outline:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
.cm-card { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; padding: 1.5rem; box-shadow: none; }
.cm-card.cm-card-accent { border-top: 2px solid hsl(var(--accent)); }
.cm-heading { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; color: hsl(var(--foreground)); margin: 0; }
.cm-heading-h2-accent { border-bottom: 2px solid hsl(var(--accent)); padding-bottom: 0.25rem; display: inline-block; }
.cm-text { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); font-variant-numeric: tabular-nums; hanging-punctuation: first last; }
.cm-logo { filter: grayscale(1); opacity: 0.7; transition: filter 200ms ease, opacity 200ms ease; }
.cm-logo:hover { filter: grayscale(0); opacity: 1; }
.cm-pull-quote { border-top: 2px solid hsl(var(--accent)); padding-top: 1.25rem; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 1.5rem; line-height: 1.4; font-weight: 500; color: hsl(var(--foreground)); }
.cm-metric { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 3rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--accent)); }
.cm-stat-figure { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 2.5rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); }
.cm-stat-label { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.875rem; color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.5rem; }
.cm-eyebrow { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 0.875rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.1em; color: hsl(var(--accent)); margin-bottom: 1rem; }
.cm-cta-strip-accent { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
.cm-cta-strip-accent .cm-btn-primary { background-color: hsl(var(--accent-foreground)); color: hsl(var(--accent)); border-color: hsl(var(--accent-foreground)); }
.cm-cta-strip-quiet { background-color: hsl(var(--muted)); color: hsl(var(--foreground)); }
.cm-footer { background-color: hsl(var(--background)); color: hsl(var(--foreground)); border-top: 1px solid hsl(var(--border)); padding: 3rem 0; }
.cm-footer-legal { color: hsl(var(--muted-foreground)); font-size: 0.875rem; border-top: 1px solid hsl(var(--border)); padding-top: 1.5rem; margin-top: 2rem; }
.cm-leadership-grid { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); gap: 1.5rem; }
@media (min-width: 640px) { .cm-leadership-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cm-leadership-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .cm-leadership-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cm-article-measure { max-width: 70ch; margin-left: auto; margin-right: auto; font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); }
.cm-section { padding-top: 4rem; padding-bottom: 4rem; }
.cm-img-empty { display: block; width: 100%; aspect-ratio: 4 / 3; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }

24
master_pages.json Normal file
View File

@ -0,0 +1,24 @@
[
{
"key": "corporate-modernist:default-master",
"title": "Corporate Modernist Default Master",
"page_templates": ["default", "article"],
"blocks": [
{ "block_key": "navbar", "title": "Main Navigation", "content": { "menuName": "main", "style": "underline" }, "slot": "header", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
{ "block_key": "corporate-modernist:footer", "title": "Site Footer", "content": { "variant": "compact", "showLegal": true }, "slot": "footer", "sort_order": 0 }
]
},
{
"key": "corporate-modernist:landing-master",
"title": "Corporate Modernist Landing Master",
"page_templates": ["landing", "full-width"],
"blocks": [
{ "block_key": "navbar", "title": "Main Navigation", "content": { "menuName": "main", "style": "underline" }, "slot": "header", "sort_order": 0 },
{ "block_key": "corporate-modernist:hero_statement", "title": "Landing Hero", "content": { "eyebrow": "Enterprise", "headline": "Trusted by 200+ boards" }, "slot": "hero", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
{ "block_key": "corporate-modernist:cta_strip", "title": "Closing CTA", "content": { "variant": "book-call" }, "slot": "cta", "sort_order": 0 },
{ "block_key": "corporate-modernist:footer", "title": "Site Footer", "content": { "variant": "full", "showLegal": true }, "slot": "footer", "sort_order": 0 }
]
}
]

View File

@ -2,11 +2,8 @@
name = "corporate-modernist" name = "corporate-modernist"
display_name = "Corporate Modernist" display_name = "Corporate Modernist"
scope = "@themes" scope = "@themes"
version = "0.1.2" version = "0.2.0"
description = "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites." description = "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites."
kind = "theme" kind = "theme"
categories = ["templates"] categories = ["templates"]
tags = ["business", "corporate", "enterprise", "consulting", "legal", "professional", "b2b", "swiss"] tags = ["business", "corporate", "enterprise", "consulting", "legal", "professional", "b2b", "swiss"]
[compatibility]
block_core = ">=0.15.0 <0.16.0"

View File

@ -1,169 +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 func to templates.TemplateFunc.
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 Corporate Modernist's system template, page templates,
// theme-owned blocks, built-in overrides, and email wrapper.
//
// Schema loading must precede block registration so that the registry can
// bind schemas to block keys at runtime.
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
// 1. System template.
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
Key: "corporate-modernist",
Title: "Corporate Modernist",
Description: "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites.",
})
// 2. Page templates.
if err := tr.RegisterPageTemplate("corporate-modernist", templates.PageTemplateMeta{
Key: "default",
Title: "Default",
Description: "Header + 12-col main + footer, capped at 1280px.",
Slots: []string{"header", "main", "footer"},
}, wrap(RenderCM)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("corporate-modernist", templates.PageTemplateMeta{
Key: "landing",
Title: "Landing",
Description: "Hero band + main + closing CTA + footer.",
Slots: []string{"hero", "main", "cta", "footer"},
}, wrap(RenderCMLanding)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("corporate-modernist", templates.PageTemplateMeta{
Key: "article",
Title: "Article",
Description: "Centered measure for long-form thought leadership.",
Slots: []string{"header", "main", "aside", "footer"},
}, wrap(RenderCMArticle)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("corporate-modernist", templates.PageTemplateMeta{
Key: "full-width",
Title: "Full width",
Description: "Edge-to-edge sections, internal grid kept.",
Slots: []string{"header", "main", "footer"},
}, wrap(RenderCMFullWidth)); err != nil {
return err
}
// 3. Schemas — MUST precede block registrations.
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
return err
}
// 4. Theme-owned blocks.
br.Register(HeroStatementMeta, HeroStatementBlock)
br.Register(LogoStripMeta, LogoStripBlock)
br.Register(TestimonialQuoteMeta, TestimonialQuoteBlock)
br.Register(CaseStudyCardMeta, CaseStudyCardBlock)
br.Register(LeadershipGridMeta, LeadershipGridBlock)
br.Register(StatPairMeta, StatPairBlock)
br.Register(CTAStripMeta, CTAStripBlock)
br.Register(FooterMeta, FooterBlock)
// 5. Built-in overrides — heading, text, button, card.
br.RegisterTemplateOverride("corporate-modernist", "heading", CorporateModernistHeadingBlock)
br.RegisterTemplateOverride("corporate-modernist", "text", CorporateModernistTextBlock)
br.RegisterTemplateOverride("corporate-modernist", "button", CorporateModernistButtonBlock)
br.RegisterTemplateOverride("corporate-modernist", "card", CorporateModernistCardBlock)
// 6. Email wrapper.
tr.RegisterEmailWrapper("corporate-modernist", CorporateModernistEmailWrapper)
return nil
}
// DefaultMasterPages returns Corporate Modernist's two seeded master pages.
// Slot names match the page templates registered above.
func DefaultMasterPages() []plugin.MasterPageDefinition {
return []plugin.MasterPageDefinition{
{
Key: "corporate-modernist:default-master",
Title: "Corporate Modernist Default Master",
PageTemplates: []string{"default", "article"},
Blocks: []plugin.MasterPageBlock{
{
BlockKey: "navbar",
Title: "Main Navigation",
Content: map[string]any{"menuName": "main", "style": "underline"},
Slot: "header",
SortOrder: 0,
},
{
BlockKey: "slot",
Title: "Main Content Slot",
Content: map[string]any{"slotName": "main"},
Slot: "main",
SortOrder: 0,
},
{
BlockKey: "corporate-modernist:footer",
Title: "Site Footer",
Content: map[string]any{"variant": "compact", "showLegal": true},
Slot: "footer",
SortOrder: 0,
},
},
},
{
Key: "corporate-modernist:landing-master",
Title: "Corporate Modernist Landing Master",
PageTemplates: []string{"landing", "full-width"},
Blocks: []plugin.MasterPageBlock{
{
BlockKey: "navbar",
Title: "Main Navigation",
Content: map[string]any{"menuName": "main", "style": "underline"},
Slot: "header",
SortOrder: 0,
},
{
BlockKey: "corporate-modernist:hero_statement",
Title: "Landing Hero",
Content: map[string]any{"eyebrow": "Enterprise", "headline": "Trusted by 200+ boards"},
Slot: "hero",
SortOrder: 0,
},
{
BlockKey: "slot",
Title: "Main Content Slot",
Content: map[string]any{"slotName": "main"},
Slot: "main",
SortOrder: 0,
},
{
BlockKey: "corporate-modernist:cta_strip",
Title: "Closing CTA",
Content: map[string]any{"variant": "book-call"},
Slot: "cta",
SortOrder: 0,
},
{
BlockKey: "corporate-modernist:footer",
Title: "Site Footer",
Content: map[string]any{"variant": "full", "showLegal": true},
Slot: "footer",
SortOrder: 0,
},
},
},
}
}

View File

@ -1,34 +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 Corporate Modernist theme.
var Registration = plugin.PluginRegistration{
Name: "corporate-modernist",
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 cssManifest() },
}
// cssManifest exposes Corporate Modernist's utility CSS to the host Tailwind input
// so .cm-* classes resolve in production builds. No @font-face declarations here:
// the CMS emits those from fonts.json (currently []).
func cssManifest() *plugin.CSSManifest {
return &plugin.CSSManifest{
InputCSSAppend: corporateModernistUtilityCSS,
}
}

View File

@ -1,56 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// StatPairMeta is the block metadata for corporate-modernist:stat_pair.
var StatPairMeta = blocks.BlockMeta{
Key: "stat_pair",
Title: "Stat Pair",
Description: "Row of mono-numeral statistics separated by a hairline rule.",
Source: "corporate-modernist",
Category: blocks.CategoryContent,
}
// StatPairItem represents a single stat entry.
type StatPairItem struct {
Figure string
Label string
Source string
}
// StatPairData carries the parsed content for the stat_pair block.
type StatPairData struct {
Title string
Stats []StatPairItem
}
// StatPairBlock renders the stat_pair block.
func StatPairBlock(ctx context.Context, content map[string]any) string {
rawStats := getSlice(content, "stats")
stats := make([]StatPairItem, 0, len(rawStats))
for _, s := range rawStats {
figure := getString(s, "figure")
if figure == "" {
continue
}
stats = append(stats, StatPairItem{
Figure: figure,
Label: getString(s, "label"),
Source: getString(s, "source"),
})
}
data := StatPairData{
Title: getString(content, "title"),
Stats: stats,
}
var buf bytes.Buffer
_ = statPairComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,45 +0,0 @@
package main
// statPairComponent renders the corporate-modernist:stat_pair block.
templ statPairComponent(data StatPairData) {
<section class="cm-section" data-block="corporate-modernist:stat_pair">
<div class="cm-content-well">
if data.Title != "" {
<h2 class="cm-heading" style="font-size: 1.875rem; margin: 0 0 2rem 0;">
<span class="cm-heading-h2-accent">{ data.Title }</span>
</h2>
}
if len(data.Stats) > 0 {
<div class="cm-swiss-12" style="row-gap: 2rem;">
for _, s := range data.Stats {
<div style={ statPairColumnSpan(len(data.Stats)) } class="cm-hairline-top" >
<div class="cm-stat-figure numeric-tabular" data-figure style="padding-top: 1rem;">{ s.Figure }</div>
if s.Label != "" {
<div class="cm-stat-label">{ s.Label }</div>
}
if s.Source != "" {
<div class="cm-stat-label" style="margin-top: 0.25rem; text-transform: none; letter-spacing: 0; opacity: 0.8;">{ s.Source }</div>
}
</div>
}
</div>
} else {
<p class="cm-stat-label">No statistics configured.</p>
}
</div>
</section>
}
// statPairColumnSpan picks a column span based on how many stats are configured.
func statPairColumnSpan(count int) string {
switch {
case count >= 4:
return "grid-column: span 3 / span 3;"
case count == 3:
return "grid-column: span 4 / span 4;"
case count == 2:
return "grid-column: span 6 / span 6;"
default:
return "grid-column: span 12 / span 12;"
}
}

View File

@ -1,167 +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"
// statPairComponent renders the corporate-modernist:stat_pair block.
func statPairComponent(data StatPairData) 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, "<section class=\"cm-section\" data-block=\"corporate-modernist:stat_pair\"><div class=\"cm-content-well\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<h2 class=\"cm-heading\" style=\"font-size: 1.875rem; margin: 0 0 2rem 0;\"><span class=\"cm-heading-h2-accent\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stat_pair.templ`, Line: 9, Col: 52}
}
_, 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, 3, "</span></h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(data.Stats) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"cm-swiss-12\" style=\"row-gap: 2rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, s := range data.Stats {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(statPairColumnSpan(len(data.Stats)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stat_pair.templ`, Line: 15, Col: 54}
}
_, 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, "\" class=\"cm-hairline-top\"><div class=\"cm-stat-figure numeric-tabular\" data-figure style=\"padding-top: 1rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(s.Figure)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stat_pair.templ`, Line: 16, Col: 100}
}
_, 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, 7, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if s.Label != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div class=\"cm-stat-label\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stat_pair.templ`, Line: 18, Col: 44}
}
_, 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, 9, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if s.Source != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"cm-stat-label\" style=\"margin-top: 0.25rem; text-transform: none; letter-spacing: 0; opacity: 0.8;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(s.Source)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stat_pair.templ`, Line: 21, Col: 129}
}
_, 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, 11, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<p class=\"cm-stat-label\">No statistics configured.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// statPairColumnSpan picks a column span based on how many stats are configured.
func statPairColumnSpan(count int) string {
switch {
case count >= 4:
return "grid-column: span 3 / span 3;"
case count == 3:
return "grid-column: span 4 / span 4;"
case count == 2:
return "grid-column: span 6 / span 6;"
default:
return "grid-column: span 12 / span 12;"
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,274 +0,0 @@
package main
import (
"context"
"git.dev.alexdunmow.com/block/core/templates/bn"
)
// PageData captures parsed template data for the Corporate Modernist page renderers.
type PageData 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
}
// parseCMPageData adapts the runtime doc map into PageData.
func parseCMPageData(doc map[string]any) PageData {
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 := "light"
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
themeMode = tm
}
return PageData{
Title: title,
Slots: slots,
ThemeMode: themeMode,
ThemeCSS: themeCSS,
SiteSettings: bn.ParseSiteSettings(doc),
PageMeta: bn.ParsePageMeta(doc),
StructuredData: structuredData,
CSSHash: cssHash,
PageviewNonce: pageviewNonce,
EngagementConfig: bn.ParseEngagementConfig(doc),
}
}
// pluginStyles points at the embedded plugin CSS served via /templates/<slug>/style.css.
func pluginStyles() []string {
return []string{"/templates/corporate-modernist/style.css"}
}
// Default — header + 12-col main + footer, capped at 1280px.
templ CorporateModernistDefault(data PageData) {
<!DOCTYPE html>
<html lang="en">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">
@templ.Raw(data.Slots["header"])
</div>
</header>
<main class="cm-content-well" style="flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;" data-content-well>
<div class="cm-swiss-12" data-grid="swiss-12">
<div style="grid-column: span 12 / span 12;">
if main, ok := data.Slots["main"]; ok && main != "" {
@templ.Raw(main)
} else {
<p class="cm-stat-label">No content blocks assigned to this page.</p>
}
</div>
</div>
</main>
<footer style="width: 100%; margin-top: auto;">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// Landing — hero band + main + closing CTA + footer.
templ CorporateModernistLanding(data PageData) {
<!DOCTYPE html>
<html lang="en">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">
@templ.Raw(data.Slots["header"])
</div>
</header>
<section style="width: 100%;">
@templ.Raw(data.Slots["hero"])
</section>
<main style="flex: 1 1 auto;" data-content-well>
if main, ok := data.Slots["main"]; ok && main != "" {
<div class="cm-content-well">
<div class="cm-swiss-12" data-grid="swiss-12" style="padding-top: 3rem; padding-bottom: 3rem;">
<div style="grid-column: span 12 / span 12;">
@templ.Raw(main)
</div>
</div>
</div>
}
</main>
<section style="width: 100%;">
@templ.Raw(data.Slots["cta"])
</section>
<footer style="width: 100%; margin-top: auto;">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// Article — centered measure for long-form thought leadership.
templ CorporateModernistArticle(data PageData) {
<!DOCTYPE html>
<html lang="en">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">
@templ.Raw(data.Slots["header"])
</div>
</header>
<main class="cm-content-well" style="flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;" data-content-well>
<div class="cm-swiss-12" data-grid="swiss-12">
<article class="cm-article-measure" style="grid-column: span 12 / span 12;">
if main, ok := data.Slots["main"]; ok && main != "" {
@templ.Raw(main)
} else {
<p class="cm-stat-label">No article content yet.</p>
}
</article>
</div>
if aside, ok := data.Slots["aside"]; ok && aside != "" {
<aside class="cm-hairline-top" style="margin-top: 3rem; padding-top: 2rem;">
@templ.Raw(aside)
</aside>
}
</main>
<footer style="width: 100%; margin-top: auto;">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// Full width — edge-to-edge sections, internal grid kept.
templ CorporateModernistFullWidth(data PageData) {
<!DOCTYPE html>
<html lang="en">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">
@templ.Raw(data.Slots["header"])
</div>
</header>
<main style="flex: 1 1 auto; width: 100%;" data-content-well>
if main, ok := data.Slots["main"]; ok && main != "" {
@templ.Raw(main)
} else {
<div class="cm-content-well" style="padding-top: 4rem; padding-bottom: 4rem;">
<p class="cm-stat-label">No content blocks assigned to this page.</p>
</div>
}
</main>
<footer style="width: 100%; margin-top: auto;">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// RenderCM is the page-template render entry point for `default`.
func RenderCM(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistDefault(parseCMPageData(doc))
}
// RenderCMLanding is the page-template render entry point for `landing`.
func RenderCMLanding(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistLanding(parseCMPageData(doc))
}
// RenderCMArticle is the page-template render entry point for `article`.
func RenderCMArticle(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistArticle(parseCMPageData(doc))
}
// RenderCMFullWidth is the page-template render entry point for `full-width`.
func RenderCMFullWidth(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistFullWidth(parseCMPageData(doc))
}

View File

@ -1,528 +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"
)
// PageData captures parsed template data for the Corporate Modernist page renderers.
type PageData 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
}
// parseCMPageData adapts the runtime doc map into PageData.
func parseCMPageData(doc map[string]any) PageData {
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 := "light"
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
themeMode = tm
}
return PageData{
Title: title,
Slots: slots,
ThemeMode: themeMode,
ThemeCSS: themeCSS,
SiteSettings: bn.ParseSiteSettings(doc),
PageMeta: bn.ParsePageMeta(doc),
StructuredData: structuredData,
CSSHash: cssHash,
PageviewNonce: pageviewNonce,
EngagementConfig: bn.ParseEngagementConfig(doc),
}
}
// pluginStyles points at the embedded plugin CSS served via /templates/<slug>/style.css.
func pluginStyles() []string {
return []string{"/templates/corporate-modernist/style.css"}
}
// Default — header + 12-col main + footer, capped at 1280px.
func CorporateModernistDefault(data PageData) 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, "<!doctype html><html lang=\"en\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
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
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"cm-body\" style=\"margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
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, 3, "<header class=\"cm-hairline-bottom\" style=\"width: 100%;\"><div class=\"cm-content-well\">")
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, 4, "</div></header><main class=\"cm-content-well\" style=\"flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;\" data-content-well><div class=\"cm-swiss-12\" data-grid=\"swiss-12\"><div style=\"grid-column: span 12 / span 12;\">")
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, 5, "<p class=\"cm-stat-label\">No content blocks assigned to this page.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</div></div></main><footer style=\"width: 100%; margin-top: auto;\">")
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, 7, "</footer>")
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, 8, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Landing — hero band + main + closing CTA + footer.
func CorporateModernistLanding(data PageData) 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, 9, "<!doctype html><html lang=\"en\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
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
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<body class=\"cm-body\" style=\"margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
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, 11, "<header class=\"cm-hairline-bottom\" style=\"width: 100%;\"><div class=\"cm-content-well\">")
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, 12, "</div></header><section style=\"width: 100%;\">")
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, "</section><main style=\"flex: 1 1 auto;\" data-content-well>")
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, "<div class=\"cm-content-well\"><div class=\"cm-swiss-12\" data-grid=\"swiss-12\" style=\"padding-top: 3rem; padding-bottom: 3rem;\"><div style=\"grid-column: span 12 / span 12;\">")
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, "</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</main><section style=\"width: 100%;\">")
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, "</section><footer style=\"width: 100%; margin-top: auto;\">")
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, "</footer>")
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, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Article — centered measure for long-form thought leadership.
func CorporateModernistArticle(data PageData) 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, 20, "<!doctype html><html lang=\"en\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
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
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<body class=\"cm-body\" style=\"margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
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, "<header class=\"cm-hairline-bottom\" style=\"width: 100%;\"><div class=\"cm-content-well\">")
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, "</div></header><main class=\"cm-content-well\" style=\"flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;\" data-content-well><div class=\"cm-swiss-12\" data-grid=\"swiss-12\"><article class=\"cm-article-measure\" style=\"grid-column: span 12 / span 12;\">")
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, 24, "<p class=\"cm-stat-label\">No article content yet.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</article></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if aside, ok := data.Slots["aside"]; ok && aside != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<aside class=\"cm-hairline-top\" style=\"margin-top: 3rem; padding-top: 2rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(aside).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</aside>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</main><footer style=\"width: 100%; margin-top: auto;\">")
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, 29, "</footer>")
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, 30, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Full width — edge-to-edge sections, internal grid kept.
func CorporateModernistFullWidth(data PageData) 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, 31, "<!doctype html><html lang=\"en\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: pluginStyles(),
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
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<body class=\"cm-body\" style=\"margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
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, 33, "<header class=\"cm-hairline-bottom\" style=\"width: 100%;\"><div class=\"cm-content-well\">")
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, 34, "</div></header><main style=\"flex: 1 1 auto; width: 100%;\" data-content-well>")
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, 35, "<div class=\"cm-content-well\" style=\"padding-top: 4rem; padding-bottom: 4rem;\"><p class=\"cm-stat-label\">No content blocks assigned to this page.</p></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</main><footer style=\"width: 100%; margin-top: auto;\">")
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, 37, "</footer>")
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, 38, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// RenderCM is the page-template render entry point for `default`.
func RenderCM(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistDefault(parseCMPageData(doc))
}
// RenderCMLanding is the page-template render entry point for `landing`.
func RenderCMLanding(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistLanding(parseCMPageData(doc))
}
// RenderCMArticle is the page-template render entry point for `article`.
func RenderCMArticle(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistArticle(parseCMPageData(doc))
}
// RenderCMFullWidth is the page-template render entry point for `full-width`.
func RenderCMFullWidth(ctx context.Context, doc map[string]any) templ.Component {
return CorporateModernistFullWidth(parseCMPageData(doc))
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
{{ head_html|safe }}
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">{{ slots.header|safe }}</div>
</header>
<main class="cm-content-well" style="flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;" data-content-well>
<div class="cm-swiss-12" data-grid="swiss-12">
<article class="cm-article-measure" style="grid-column: span 12 / span 12;">
{% if slots.main %}{{ slots.main|safe }}{% else %}<p class="cm-stat-label">No article content yet.</p>{% endif %}
</article>
</div>
{% if slots.aside %}<aside class="cm-hairline-top" style="margin-top: 3rem; padding-top: 2rem;">{{ slots.aside|safe }}</aside>{% endif %}
</main>
<footer style="width: 100%; margin-top: auto;">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
{{ head_html|safe }}
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">{{ slots.header|safe }}</div>
</header>
<main class="cm-content-well" style="flex: 1 1 auto; padding-top: 3rem; padding-bottom: 3rem;" data-content-well>
<div class="cm-swiss-12" data-grid="swiss-12">
<div style="grid-column: span 12 / span 12;">
{% if slots.main %}{{ slots.main|safe }}{% else %}<p class="cm-stat-label">No content blocks assigned to this page.</p>{% endif %}
</div>
</div>
</main>
<footer style="width: 100%; margin-top: auto;">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
{{ head_html|safe }}
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">{{ slots.header|safe }}</div>
</header>
<main style="flex: 1 1 auto; width: 100%;" data-content-well>
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="cm-content-well" style="padding-top: 4rem; padding-bottom: 4rem;"><p class="cm-stat-label">No content blocks assigned to this page.</p></div>{% endif %}
</main>
<footer style="width: 100%; margin-top: auto;">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
{{ head_html|safe }}
<body class="cm-body" style="margin: 0; min-height: 100vh; display: flex; flex-direction: column; background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<header class="cm-hairline-bottom" style="width: 100%;">
<div class="cm-content-well">{{ slots.header|safe }}</div>
</header>
<section style="width: 100%;">{{ slots.hero|safe }}</section>
<main style="flex: 1 1 auto;" data-content-well>
{% if slots.main %}<div class="cm-content-well"><div class="cm-swiss-12" data-grid="swiss-12" style="padding-top: 3rem; padding-bottom: 3rem;"><div style="grid-column: span 12 / span 12;">{{ slots.main|safe }}</div></div></div>{% endif %}
</main>
<section style="width: 100%;">{{ slots.cta|safe }}</section>
<footer style="width: 100%; margin-top: auto;">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,62 @@
<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{ site_name }}</title>
<style type="text/css">
:root {
--cm-email-bg: hsl(220 14% 96%);
--cm-email-surface: hsl(0 0% 100%);
--cm-email-fg: hsl(220 20% 12%);
--cm-email-muted-fg: hsl(220 10% 40%);
--cm-email-border: hsl(220 14% 90%);
--cm-email-accent: hsl(218 65% 22%);
}
body, table, td, p, a, li, blockquote { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
h1, h2, h3, h4, h5, h6 { font-family: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 600; letter-spacing: -0.02em; }
@media only screen and (max-width: 620px) {
.cm-email-container { width: 100% !important; max-width: 100% !important; }
.cm-email-padding { padding-left: 24px !important; padding-right: 24px !important; }
}
</style>
</head>
<body style="background-color: var(--cm-email-bg, hsl(220 14% 96%)); margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
{% if preview_text %}<div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">{{ preview_text }}</div>{% endif %}
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td align="center" style="padding: 32px 12px; background-color: var(--cm-email-bg, hsl(220 14% 96%));">
<table role="presentation" class="cm-email-container" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; width: 600px; background-color: var(--cm-email-surface, hsl(0 0% 100%)); border: 1px solid var(--cm-email-border, hsl(220 14% 90%)); border-collapse: separate;">
<!-- Header: title + single accent rule -->
<tr>
<td class="cm-email-padding" style="padding: 32px 48px 16px 48px; background-color: var(--cm-email-surface, hsl(0 0% 100%));">{% if logo_url %}<img src="{{ logo_url }}" alt="{{ site_name }}" style="max-height: 36px; width: auto; display: block;">{% elif site_name %}<h1 style="margin: 0; font-size: 20px; font-weight: 600; color: var(--cm-email-fg, hsl(220 20% 12%)); letter-spacing: -0.02em; font-family: 'Inter Tight', 'Inter', sans-serif;">{{ site_name }}</h1>{% endif %}</td>
</tr>
<tr>
<td style="padding: 0 48px;"><div style="height: 2px; background-color: var(--cm-email-accent, hsl(218 65% 22%)); line-height: 2px; font-size: 0;">&nbsp;</div></td>
</tr>
<!-- Body -->
<tr>
<td class="cm-email-padding" style="padding: 32px 48px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-size: 16px; line-height: 1.6; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">{{ body|safe }}</td>
</tr>
<!-- Footer: legal line + unsubscribe -->
<tr>
<td class="cm-email-padding" style="padding: 24px 48px 32px 48px; border-top: 1px solid var(--cm-email-border, hsl(220 14% 90%));">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td align="left">{% if site_name %}<p style="margin: 0 0 6px 0; font-size: 13px; color: var(--cm-email-fg, hsl(220 20% 12%)); font-family: 'Inter Tight', 'Inter', sans-serif; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;">{{ site_name }}</p>{% endif %}<p style="margin: 0 0 12px 0; font-size: 12px; color: var(--cm-email-muted-fg, hsl(220 10% 40%)); font-family: 'Inter', sans-serif;">You are receiving this email because you subscribed to updates.</p>{% if site_url %}<p style="margin: 0 0 8px 0; font-size: 12px;"><a href="{{ site_url }}" style="color: var(--cm-email-accent, hsl(218 65% 22%)); text-decoration: none;">{{ site_url }}</a></p>{% endif %}{% if unsubscribe_url %}<p style="margin: 0; font-size: 11px;"><a href="{{ unsubscribe_url }}" style="color: var(--cm-email-muted-fg, hsl(220 10% 40%)); text-decoration: underline;">Unsubscribe</a></p>{% endif %}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1 @@
{% if variant|default:"primary" == "outline" or variant|default:"primary" == "secondary" %}<a class="cm-btn-outline" href="{{ href|default:url|default:"#" }}">{{ label|default:text|default:"Learn more" }}</a>{% else %}<a class="cm-btn-primary" href="{{ href|default:url|default:"#" }}">{{ label|default:text|default:"Learn more" }}</a>{% endif %}

View File

@ -0,0 +1 @@
<div class="cm-card{% if accent == true or accent == "true" %} cm-card-accent{% endif %}">{% if title %}<div class="cm-display" style="font-size: 1.25rem; font-weight: 600; margin: 0 0 0.75rem 0;">{{ title }}</div>{% endif %}{% if body|default:text %}<div class="cm-text">{{ body|default:text|safe }}</div>{% endif %}</div>

View File

@ -0,0 +1 @@
{% if level|integer == 1 %}<h1 class="cm-heading cm-heading-h1 {{ textClass }}" style="font-size: clamp(2rem, 4vw, 3rem); line-height: 1.1;">{{ text }}</h1>{% elif level|integer == 3 %}<h3 class="cm-heading cm-heading-h3 {{ textClass }}" style="font-size: 1.5rem; line-height: 1.3;">{{ text }}</h3>{% elif level|integer == 4 %}<h4 class="cm-heading cm-heading-h4 {{ textClass }}" style="font-size: 1.25rem; line-height: 1.3;">{{ text }}</h4>{% elif level|integer == 5 %}<h5 class="cm-heading cm-heading-h5 {{ textClass }}" style="font-size: 1.125rem; line-height: 1.4;">{{ text }}</h5>{% elif level|integer == 6 %}<h6 class="cm-heading cm-heading-h6 {{ textClass }}" style="font-size: 1rem; line-height: 1.4;">{{ text }}</h6>{% else %}<h2 class="cm-heading cm-heading-h2 {{ textClass }}" style="font-size: clamp(1.5rem, 3vw, 2.25rem); line-height: 1.2;"><span class="cm-heading-h2-accent">{{ text }}</span></h2>{% endif %}

View File

@ -0,0 +1 @@
<div class="cm-text {{ class }}">{{ text|safe }}</div>

View File

@ -1,43 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// TestimonialQuoteMeta is the block metadata for corporate-modernist:testimonial_quote.
var TestimonialQuoteMeta = blocks.BlockMeta{
Key: "testimonial_quote",
Title: "Testimonial",
Description: "Pull-quote testimonial with attribution, headshot, and company mark.",
Source: "corporate-modernist",
Category: blocks.CategoryContent,
}
// TestimonialQuoteData carries the parsed content for the testimonial_quote block.
type TestimonialQuoteData struct {
Quote string
Name string
Role string
Company string
Headshot string
Logo string
}
// TestimonialQuoteBlock renders the testimonial_quote block.
func TestimonialQuoteBlock(ctx context.Context, content map[string]any) string {
data := TestimonialQuoteData{
Quote: getString(content, "quote"),
Name: getString(content, "name"),
Role: getString(content, "role"),
Company: getString(content, "company"),
Headshot: getString(content, "headshot"),
Logo: getString(content, "logo"),
}
var buf bytes.Buffer
_ = testimonialQuoteComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,63 +0,0 @@
package main
// testimonialQuoteComponent renders the corporate-modernist:testimonial_quote block.
templ testimonialQuoteComponent(data TestimonialQuoteData) {
<section class="cm-section" data-block="corporate-modernist:testimonial_quote">
<div class="cm-content-well">
<figure style="max-width: 70ch; margin: 0 auto;">
if data.Quote != "" {
<blockquote class="cm-pull-quote">
{ data.Quote }
</blockquote>
} else {
<blockquote class="cm-pull-quote">
No testimonial provided.
</blockquote>
}
<figcaption style="display: flex; align-items: center; gap: 1rem; margin-top: 1.5rem;">
if data.Headshot != "" {
<img src={ data.Headshot } alt={ testimonialQuoteHeadshotAlt(data) } style="width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; display: block;"/>
} else {
<span class="cm-img-empty" style="width: 3rem; height: 3rem; aspect-ratio: 1 / 1; border-radius: 50%;"></span>
}
<div>
if data.Name != "" {
<div class="cm-display" style="font-size: 1rem; font-weight: 600; margin: 0;">{ data.Name }</div>
}
if data.Role != "" || data.Company != "" {
<div class="cm-stat-label" style="margin: 0.25rem 0 0 0;">{ testimonialQuoteAttribution(data) }</div>
}
</div>
if data.Logo != "" {
<img src={ data.Logo } alt={ testimonialQuoteLogoAlt(data) } class="cm-logo" style="max-height: 1.5rem; width: auto; margin-left: auto; display: block;"/>
}
</figcaption>
</figure>
</div>
</section>
}
func testimonialQuoteHeadshotAlt(data TestimonialQuoteData) string {
if data.Name != "" {
return data.Name
}
return "Testimonial portrait"
}
func testimonialQuoteLogoAlt(data TestimonialQuoteData) string {
if data.Company != "" {
return data.Company + " logo"
}
return "Company logo"
}
func testimonialQuoteAttribution(data TestimonialQuoteData) string {
switch {
case data.Role != "" && data.Company != "":
return data.Role + ", " + data.Company
case data.Role != "":
return data.Role
default:
return data.Company
}
}

View File

@ -1,213 +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"
// testimonialQuoteComponent renders the corporate-modernist:testimonial_quote block.
func testimonialQuoteComponent(data TestimonialQuoteData) 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, "<section class=\"cm-section\" data-block=\"corporate-modernist:testimonial_quote\"><div class=\"cm-content-well\"><figure style=\"max-width: 70ch; margin: 0 auto;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Quote != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<blockquote class=\"cm-pull-quote\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Quote)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 10, Col: 18}
}
_, 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, 3, "</blockquote>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<blockquote class=\"cm-pull-quote\">No testimonial provided.</blockquote>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<figcaption style=\"display: flex; align-items: center; gap: 1rem; margin-top: 1.5rem;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Headshot != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Headshot)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 19, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(testimonialQuoteHeadshotAlt(data))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 19, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; display: block;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<span class=\"cm-img-empty\" style=\"width: 3rem; height: 3rem; aspect-ratio: 1 / 1; border-radius: 50%;\"></span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Name != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"cm-display\" style=\"font-size: 1rem; font-weight: 600; margin: 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 25, Col: 96}
}
_, 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, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.Role != "" || data.Company != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<div class=\"cm-stat-label\" style=\"margin: 0.25rem 0 0 0;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(testimonialQuoteAttribution(data))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 28, Col: 100}
}
_, 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, 14, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Logo != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Logo)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 32, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(testimonialQuoteLogoAlt(data))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `testimonial_quote.templ`, Line: 32, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\" class=\"cm-logo\" style=\"max-height: 1.5rem; width: auto; margin-left: auto; display: block;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</figcaption></figure></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func testimonialQuoteHeadshotAlt(data TestimonialQuoteData) string {
if data.Name != "" {
return data.Name
}
return "Testimonial portrait"
}
func testimonialQuoteLogoAlt(data TestimonialQuoteData) string {
if data.Company != "" {
return data.Company + " logo"
}
return "Company logo"
}
func testimonialQuoteAttribution(data TestimonialQuoteData) string {
switch {
case data.Role != "" && data.Company != "":
return data.Role + ", " + data.Company
case data.Role != "":
return data.Role
default:
return data.Company
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,17 +0,0 @@
package main
import (
"bytes"
"context"
)
// CorporateModernistTextBlock renders the built-in `text` block with
// Inter at 17/28, tabular figures, and hanging punctuation.
func CorporateModernistTextBlock(ctx context.Context, content map[string]any) string {
text := getString(content, "text")
class := getString(content, "class")
var buf bytes.Buffer
_ = textOverrideComponent(text, class).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,8 +0,0 @@
package main
// textOverrideComponent renders the Corporate Modernist text override.
templ textOverrideComponent(text, class string) {
<div class={ "cm-text", class }>
@templ.Raw(text)
</div>
}

View File

@ -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"
// textOverrideComponent renders the Corporate Modernist text override.
func textOverrideComponent(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_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{"cm-text", class}
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, "<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `text_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
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
}
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, 3, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate