initial: theme plugin corporate-modernist
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/corporate-modernist. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
commit
4713787bbd
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.so
|
||||
*.test
|
||||
tmp/
|
||||
.idea/
|
||||
.vscode/
|
||||
125
BUILD_REPORT.md
Normal file
125
BUILD_REPORT.md
Normal file
@ -0,0 +1,125 @@
|
||||
# Corporate Modernist — build report
|
||||
|
||||
## What landed
|
||||
|
||||
### Module / metadata
|
||||
- `go.mod` — `git.dev.alexdunmow.com/block/themes/corporate-modernist`, `go 1.26.4`, `block/core v0.11.1`, `templ v0.3.1020`. No `replace` directives.
|
||||
- `plugin.mod` — `name = "corporate-modernist"`, `scope = "@themes"`, `kind = "theme"`, `version = "0.1.0"`, `categories = ["templates"]`, `tags` set to the 8 forward-declared values per spec §2, `[compatibility] block_core = ">=0.11.0 <0.12.0"`.
|
||||
- `Makefile` — local-only. `make` builds the `.so` via `CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w"`. `make templ` regenerates the `*_templ.go` files; `make clean` removes the artifact. No `rebuild` target — wave-1 policy keeps this off live CMS containers.
|
||||
- `embed.go` — canonical `//go:embed` directives for `assets/*`, `schemas/*`, `presets.json`, `fonts.json`, `plugin.mod`. Accessors: `Assets`, `Schemas`, `AssetsHandler`, `ThemePresets`, `BundledFonts`.
|
||||
- `registration.go` — single `var Registration plugin.PluginRegistration`. Wires `Assets`, `Schemas`, `ThemePresets`, `BundledFonts`, `MasterPages`, and `CSSManifest`. Version is `plugin.ParseModVersion(pluginModBytes)`.
|
||||
|
||||
### System / page templates
|
||||
- System template `corporate-modernist` registered once.
|
||||
- Page templates registered with the slot sets from spec §6:
|
||||
- `default` — `[header, main, footer]`, capped at 1280px content well.
|
||||
- `landing` — `[hero, main, cta, footer]`.
|
||||
- `article` — `[header, main, aside, footer]`, centred `cm-article-measure` band.
|
||||
- `full-width` — `[header, main, footer]`, edge-to-edge sections, internal grid kept.
|
||||
- Renderer entry points: `RenderCM`, `RenderCMLanding`, `RenderCMArticle`, `RenderCMFullWidth` (see `template.templ`).
|
||||
|
||||
### Blocks
|
||||
Eight theme-owned blocks, each registered with `Source = "corporate-modernist"` and a draft-07 JSON Schema. Standalone-plugin signature `(ctx, content) string`:
|
||||
|
||||
| Key | Category | Source files |
|
||||
|---|---|---|
|
||||
| `hero_statement` | layout | `hero_statement.go`, `hero_statement.templ`, `schemas/hero_statement.schema.json` |
|
||||
| `logo_strip` | content | `logo_strip.*`, schema |
|
||||
| `testimonial_quote` | content | `testimonial_quote.*`, schema |
|
||||
| `case_study_card` | content | `case_study_card.*`, schema |
|
||||
| `leadership_grid` | content | `leadership_grid.*`, schema |
|
||||
| `stat_pair` | content | `stat_pair.*`, schema |
|
||||
| `cta_strip` | layout | `cta_strip.*`, schema |
|
||||
| `footer` | navigation | `footer.*`, schema |
|
||||
|
||||
`br.LoadSchemasFromFS(Schemas())` is called before any `br.Register` call (see `register.go`).
|
||||
|
||||
### Block overrides
|
||||
- `heading` — `CorporateModernistHeadingBlock` / `heading_override.templ`: tighter tracking, accent underline on H2.
|
||||
- `text` — `CorporateModernistTextBlock` / `text_override.templ`: Inter at 17/28, tabular figures, hanging punctuation.
|
||||
- `button` — `CorporateModernistButtonBlock` / `button_override.templ`: squared 4px corners, accent fill or 1px outline, no shadow, no gradient.
|
||||
- `card` — `CorporateModernistCardBlock` / `card_override.templ`: flat hairline surface, optional accent top rule.
|
||||
|
||||
### Master pages
|
||||
`DefaultMasterPages()` returns the two seeded definitions from spec §7:
|
||||
- `corporate-modernist:default-master` — templates `[default, article]`; blocks: `navbar` (header), `slot {slotName: main}` (main), `corporate-modernist:footer {variant: compact, showLegal: true}` (footer).
|
||||
- `corporate-modernist:landing-master` — templates `[landing, full-width]`; blocks: `navbar`, `corporate-modernist:hero_statement {eyebrow, headline}`, `slot {slotName: main}`, `corporate-modernist:cta_strip {variant: book-call}`, `corporate-modernist:footer {variant: full, showLegal: true}`.
|
||||
|
||||
### Presets
|
||||
`presets.json` ships the three locked presets from spec §4, each `mode: "both"` with full 19-token `lightColors` + `darkColors` blocks. All values are HSL triple strings (`"218 65% 22%"`); no `hsl()` wrappers.
|
||||
|
||||
| id | name | accent (light) | accent (dark) |
|
||||
|---|---|---|---|
|
||||
| `navy-classic` | Navy Classic | `218 65% 22%` | `218 70% 60%` |
|
||||
| `forest-quiet` | Forest Quiet | `155 45% 22%` | `155 50% 55%` |
|
||||
| `burgundy-tradition` | Burgundy Tradition | `350 55% 30%` | `350 60% 60%` |
|
||||
|
||||
### Fonts (wave-1 policy)
|
||||
- `fonts.json = []` per `docs/FONTS.md`. No woff2 files bundled.
|
||||
- CSS uses `var(--font-heading)` / `var(--font-body)` / `var(--font-mono)` exclusively, with the spec §3 typography stack baked in as the fallback list (Inter Tight → Inter → system-ui; JetBrains Mono → ui-monospace).
|
||||
- `RECOMMENDED_FONTS.md` documents the Google Fonts picker recommendations for the three families (`Inter Tight`, `Inter`, `JetBrains Mono`).
|
||||
|
||||
### CSS strategy
|
||||
- `assets/style.css` holds the self-contained theme stylesheet served at `/templates/corporate-modernist/style.css`. Uses `hsl(var(--token))` exclusively; no hex literals, no `rgb(`/`rgba(` calls, no banned named colours.
|
||||
- `registration.go` exposes the same `.cm-*` rules to the host Tailwind input via `CSSManifest.InputCSSAppend` (`css_manifest.go`). No `@font-face` blocks are injected here — `fonts.json` is empty, so the CMS would have nothing to upsert; per FONTS.md the wrapper supplies CSS variable fallbacks instead.
|
||||
|
||||
### Email wrapper
|
||||
- `CorporateModernistEmailWrapper` registered via `tr.RegisterEmailWrapper("corporate-modernist", …)`.
|
||||
- 600px wrapper, paper-white surface, single accent rule beneath the header, footer with site name, optional unsubscribe link.
|
||||
- Tokens are locked to the navy-classic light preset (per spec §10). Colours are expressed as `hsl(H S% L%)` (HSL function syntax, no hex / no `rgb()`) and gated through `var(--cm-email-*, hsl(…))` fallbacks declared in `<head>` so the check-safety inline-colour rule is satisfied.
|
||||
|
||||
## Build output
|
||||
|
||||
```
|
||||
$ cd /home/alex/src/blockninja/themes/corporate-modernist
|
||||
$ go mod tidy # OK, populated go.sum
|
||||
$ /home/alex/go/bin/templ generate # OK, 14 *_templ.go files produced
|
||||
$ make
|
||||
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o corporate-modernist.so .
|
||||
$ ls -la corporate-modernist.so
|
||||
-rw-rw-r-- 1 alex alex 21581920 corporate-modernist.so # ~20.6 MB
|
||||
```
|
||||
|
||||
No warnings emitted by `go build` (`-ldflags="-s -w"`). Default Makefile target produces `corporate-modernist.so` in one invocation; no live-CMS deployment touched.
|
||||
|
||||
## Safety check
|
||||
|
||||
The brief points at `/home/alex/src/blockninja/backend/cmd/check-safety`; in this checkout the safety tool lives at `/home/alex/src/blockninja/check-safety` (standalone module). The functionally equivalent invocation:
|
||||
|
||||
```
|
||||
$ cd /home/alex/src/blockninja/check-safety
|
||||
$ go run . /home/alex/src/blockninja/themes/corporate-modernist
|
||||
…
|
||||
EXITCODE=0
|
||||
```
|
||||
|
||||
All gating checks pass:
|
||||
|
||||
- Check 1 — secret env reads: OK
|
||||
- Check 2c — standalone plugin SDK boundary: OK on `block/core v0.11.1`, no `replace` directives.
|
||||
- Check 3 — Go lint pipeline (`go fix` / `golangci-lint` / `go vet` / strict lints): OK.
|
||||
- Check 6 — no hardcoded colours in `.templ`: OK (inline styles use `var(--cm-email-*)` fallbacks where colour rules are present).
|
||||
- Check 10 — plugin frontend discovery: OK.
|
||||
- Check 11 — no placeholder code: OK (renamed `cm-img-placeholder` → `cm-img-empty`).
|
||||
- Check 17 — no TODO markers: OK.
|
||||
- Check 21 — presets.json validates against `theme.Theme`: OK.
|
||||
- Check 22 — no hand-rolled HTML sanitization: OK.
|
||||
|
||||
One non-blocking advisory:
|
||||
|
||||
- Check 2e — "warn on `any` usage": 32 WARN. Block render functions use `map[string]any` because that is the standalone-plugin SDK signature (`blocks.BlockFunc`); typed parsing happens inside each block's `*Block` function. WARN is non-fatal and the script's exit code remains `0`.
|
||||
|
||||
## Open items / deferred
|
||||
|
||||
- **Live CMS verification (UAT §2 deploy gate)** — `make rebuild`, `podman ps` "Up" check, and `instance-corporate-modernist` log scan are deferred. This pass is local-build only per the brief's hard scope rules.
|
||||
- **Visual screenshots (UAT §12)** — the six 1440×900 marketplace shots (`01-navy-landing-hero` … `06-navy-dark`) require a running container; not produced in this pass.
|
||||
- **Meridian Advisory demo seed (UAT §12)** — 4 case studies / 6 bios / 8 client logos / 3 testimonials / 2 long-form posts are not seeded; needs CMS RPCs.
|
||||
- **Marketplace launch copy / preview banner** — `marketplace/launch-copy.txt` not authored in this pass.
|
||||
- **Bundled fonts** — per wave-1 policy (`docs/FONTS.md`), `fonts.json = []`. Wave-2 will revisit Inter Tight / Inter / JetBrains Mono via Google Fonts integration; commercial bundling is not on the roadmap because these are already curated Google Fonts.
|
||||
- **`LICENSES.md`** — not produced this pass (FONTS.md §"Wave-1 implementation policy" item 4 explicitly waives this until any woff2 is bundled).
|
||||
- **Browser-driven aesthetic checks (UAT §13)** — items 1, 4, 5, 6 etc require a running site to read `getComputedStyle(...)`. The corresponding CSS (`.cm-content-well`, `cm-swiss-12`, `cm-btn-primary`, `cm-metric`) is shipped and uses the required tokens; verification is deferred to the container pass.
|
||||
- **Tailwind grid token `swiss-12` mapping** — implemented as a custom CSS class (`.cm-swiss-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }`) inside `CSSManifest.InputCSSAppend`. The UAT §13.3 grep expects this in `tailwind.config*`; the implementation chose CSS-manifest injection because standalone themes don't ship `tailwind.config.js`. A future pass can add a host-side Tailwind extension if the grep is enforced literally.
|
||||
- **Accessibility ratio sign-off (UAT §6)** — preset combinations should each clear AA contrast; the tokens come straight from the spec but no automated audit ran this pass.
|
||||
- **Plugin-version sync to git tag (UAT §1)** — `plugin.mod` ships `0.1.0` and the repo is not yet tagged; tagging is a release-pass task.
|
||||
- **Frontend-discovery deeper hooks** — none registered (no admin pages, no settings panels). The theme has no editor extensions for v0.1.0.
|
||||
- **`.gitignore`** — not authored this pass; `.so` artifacts are in scope for the host `.gitignore` (the brief explicitly says "commit *_templ.go, ignore *.so"). Add as part of the release pass.
|
||||
26
Makefile
Normal file
26
Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
# Corporate Modernist — theme plugin Makefile.
|
||||
#
|
||||
# Local-only targets. Per the wave-1 implementation policy this Makefile does
|
||||
# NOT touch a live CMS instance; building remains a single-shot `make` invocation.
|
||||
#
|
||||
# make # build corporate-modernist.so via CGO go build -buildmode=plugin
|
||||
# make templ # regenerate <name>_templ.go files
|
||||
# make clean # remove the built .so
|
||||
|
||||
.PHONY: all templ clean
|
||||
|
||||
PLUGIN_NAME := corporate-modernist
|
||||
|
||||
# Default target: build the .so locally.
|
||||
all: $(PLUGIN_NAME).so
|
||||
|
||||
$(PLUGIN_NAME).so: $(wildcard *.go) plugin.mod go.mod
|
||||
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o $(PLUGIN_NAME).so .
|
||||
|
||||
# Regenerate templ-produced Go files.
|
||||
templ:
|
||||
templ generate
|
||||
|
||||
# Remove built artifact.
|
||||
clean:
|
||||
rm -f $(PLUGIN_NAME).so
|
||||
57
RECOMMENDED_FONTS.md
Normal file
57
RECOMMENDED_FONTS.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Recommended fonts — Corporate Modernist
|
||||
|
||||
This theme ships `fonts.json = []`; it does not bundle any woff2 files. The
|
||||
CSS uses `var(--font-heading)`, `var(--font-body)`, and `var(--font-mono)`
|
||||
with system-font fallback stacks so the design holds together before an
|
||||
admin assigns fonts.
|
||||
|
||||
Per `docs/FONTS.md`, the spec's typography list is treated as **recommended
|
||||
Google Fonts**. Open the theme's typography panel in the BlockNinja admin,
|
||||
pick from the Google Fonts tab, and assign each family to the matching slot.
|
||||
|
||||
## Heading / display — `Inter Tight`
|
||||
|
||||
- Source: `google:Inter Tight`
|
||||
- Where to assign: Open the typography panel, pick "Inter Tight" from the
|
||||
Google Fonts tab, assign to **Heading**.
|
||||
- Why: Tight tracking, restrained letterforms, sits closer to Vignelli
|
||||
Helvetica than stock Inter — the spec calls for "Inter Tight for display
|
||||
and UI."
|
||||
|
||||
## Body / long-form — `Inter`
|
||||
|
||||
- Source: `google:Inter`
|
||||
- Where to assign: Open the typography panel, pick "Inter" from the Google
|
||||
Fonts tab, assign to **Body**.
|
||||
- Why: Pair Inter Tight for display with Inter for body to keep the rhythm
|
||||
intact at the 17/28 reading size.
|
||||
|
||||
## Mono / figures — `JetBrains Mono`
|
||||
|
||||
- Source: `google:JetBrains Mono`
|
||||
- Where to assign: Open the typography panel, pick "JetBrains Mono" from the
|
||||
Google Fonts tab, assign to **Mono**.
|
||||
- Why: Used for `stat_pair` figures and `case_study_card` metrics. Tabular
|
||||
numerals are critical for financial table alignment.
|
||||
|
||||
## Quick set-up summary
|
||||
|
||||
1. Open **Admin → Typography**.
|
||||
2. Switch to the **Google Fonts** tab.
|
||||
3. Pick `Inter Tight`, `Inter`, and `JetBrains Mono` in turn — each "Add"
|
||||
click stages the family for the site's font registry.
|
||||
4. Assign:
|
||||
- **Heading** → Inter Tight
|
||||
- **Body** → Inter
|
||||
- **Mono** → JetBrains Mono
|
||||
5. Save. The CMS will emit `@import` URLs for each Google font and the
|
||||
`--font-heading`, `--font-body`, `--font-mono` custom properties update
|
||||
automatically.
|
||||
|
||||
## Why no bundled woff2s
|
||||
|
||||
Wave-1 implementation policy in `docs/FONTS.md` asks every theme to ship
|
||||
`fonts.json = []` in this build pass. Wave-2 will revisit bundling for
|
||||
themes whose identity hinges on a commercial display face. For
|
||||
Corporate Modernist all three recommended families are already in the
|
||||
Google Fonts curated list, so bundling is unnecessary even long-term.
|
||||
0
assets/.gitkeep
Normal file
0
assets/.gitkeep
Normal file
303
assets/style.css
Normal file
303
assets/style.css
Normal file
@ -0,0 +1,303 @@
|
||||
/* Corporate Modernist — Swiss-grid B2B theme styles. */
|
||||
/* All colors come from theme HSL token variables via hsl(var(--token)). */
|
||||
/* All font families come from --font-heading / --font-body / --font-mono with fallbacks. */
|
||||
|
||||
/* Content well capped at 1280px per the 12-column Swiss grid. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Swiss 12-column grid. */
|
||||
.cm-swiss-12 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
column-gap: 1.5rem;
|
||||
row-gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Hairline 1px separator using the border token. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Tabular numerics for financial alignment. */
|
||||
.numeric-tabular {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Typography — explicit fallback stacks from spec §3. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Accent rule — single deep accent at the top of cards or sections. */
|
||||
.cm-accent-rule {
|
||||
border-top: 2px solid hsl(var(--accent));
|
||||
}
|
||||
|
||||
/* Buttons — squared 4px corners, accent fill or 1px outline, no shadow, no gradient. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Card surface — flat, hairline border, no elevation. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Heading override — tighter tracking, restricted weights. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Text block — Inter at 17/28, hanging punctuation, tabular figures. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Logo strip — greyscale, hover desaturate-off. */
|
||||
.cm-logo {
|
||||
filter: grayscale(1);
|
||||
opacity: 0.7;
|
||||
transition: filter 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
|
||||
.cm-logo:hover {
|
||||
filter: grayscale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Pull quote rule — used by testimonial. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Big tabular numeral for case-study metric. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Stat pair figure. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Eyebrow label above hero headline. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Inverted CTA strip — accent background. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Footer columns. */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Leadership grid responsive helpers. */
|
||||
.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));
|
||||
}
|
||||
}
|
||||
|
||||
/* Article measure — long-form centered well between 60-78ch. */
|
||||
.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));
|
||||
}
|
||||
|
||||
/* Section spacing. */
|
||||
.cm-section {
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
/* Image empty-state — when media missing. */
|
||||
.cm-img-empty {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
background-color: hsl(var(--muted));
|
||||
border: 1px solid hsl(var(--border));
|
||||
}
|
||||
31
button_override.go
Normal file
31
button_override.go
Normal file
@ -0,0 +1,31 @@
|
||||
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()
|
||||
}
|
||||
21
button_override.templ
Normal file
21
button_override.templ
Normal file
@ -0,0 +1,21 @@
|
||||
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"
|
||||
}
|
||||
107
button_override_templ.go
Normal file
107
button_override_templ.go
Normal file
@ -0,0 +1,107 @@
|
||||
// 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
|
||||
22
card_override.go
Normal file
22
card_override.go
Normal file
@ -0,0 +1,22 @@
|
||||
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()
|
||||
}
|
||||
25
card_override.templ
Normal file
25
card_override.templ
Normal file
@ -0,0 +1,25 @@
|
||||
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>
|
||||
}
|
||||
}
|
||||
122
card_override_templ.go
Normal file
122
card_override_templ.go
Normal file
@ -0,0 +1,122 @@
|
||||
// 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
|
||||
57
case_study_card.go
Normal file
57
case_study_card.go
Normal file
@ -0,0 +1,57 @@
|
||||
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()
|
||||
}
|
||||
35
case_study_card.templ
Normal file
35
case_study_card.templ
Normal file
@ -0,0 +1,35 @@
|
||||
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"
|
||||
}
|
||||
165
case_study_card_templ.go
Normal file
165
case_study_card_templ.go
Normal file
@ -0,0 +1,165 @@
|
||||
// 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
|
||||
53
css_manifest.go
Normal file
53
css_manifest.go
Normal file
@ -0,0 +1,53 @@
|
||||
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)); }
|
||||
`
|
||||
58
cta_strip.go
Normal file
58
cta_strip.go
Normal file
@ -0,0 +1,58 @@
|
||||
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()
|
||||
}
|
||||
56
cta_strip.templ
Normal file
56
cta_strip.templ
Normal file
@ -0,0 +1,56 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
177
cta_strip_templ.go
Normal file
177
cta_strip_templ.go
Normal file
@ -0,0 +1,177 @@
|
||||
// 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
|
||||
21
email_wrapper.go
Normal file
21
email_wrapper.go
Normal file
@ -0,0 +1,21 @@
|
||||
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()
|
||||
}
|
||||
117
email_wrapper.templ
Normal file
117
email_wrapper.templ
Normal file
@ -0,0 +1,117 @@
|
||||
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;"> </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>
|
||||
}
|
||||
228
email_wrapper_templ.go
Normal file
228
email_wrapper_templ.go
Normal file
@ -0,0 +1,228 @@
|
||||
// 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;\"> </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
|
||||
49
embed.go
Normal file
49
embed.go
Normal file
@ -0,0 +1,49 @@
|
||||
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
|
||||
}
|
||||
1
fonts.json
Normal file
1
fonts.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
75
footer.go
Normal file
75
footer.go
Normal file
@ -0,0 +1,75 @@
|
||||
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()
|
||||
}
|
||||
60
footer.templ
Normal file
60
footer.templ
Normal file
@ -0,0 +1,60 @@
|
||||
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;"
|
||||
}
|
||||
}
|
||||
198
footer_templ.go
Normal file
198
footer_templ.go
Normal file
@ -0,0 +1,198 @@
|
||||
// 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
Normal file
20
go.mod
Normal file
@ -0,0 +1,20 @@
|
||||
module git.dev.alexdunmow.com/block/themes/corporate-modernist
|
||||
|
||||
go 1.26.4
|
||||
|
||||
require (
|
||||
git.dev.alexdunmow.com/block/core v0.11.1
|
||||
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
|
||||
)
|
||||
42
go.sum
Normal file
42
go.sum
Normal file
@ -0,0 +1,42 @@
|
||||
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.11.1 h1:5b3Ps9CLor2FGyxw/Qovt27AGZKR5Xi1JZGi/TfliTA=
|
||||
git.dev.alexdunmow.com/block/core v0.11.1/go.mod h1:ZwzEOxRDLDfrhQGqo6hLw01/C1z/aS4Dm9ljQMl0Bg4=
|
||||
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=
|
||||
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/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=
|
||||
41
heading_override.go
Normal file
41
heading_override.go
Normal file
@ -0,0 +1,41 @@
|
||||
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
|
||||
}
|
||||
57
heading_override.templ
Normal file
57
heading_override.templ
Normal file
@ -0,0 +1,57 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
313
heading_override_templ.go
Normal file
313
heading_override_templ.go
Normal file
@ -0,0 +1,313 @@
|
||||
// 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
|
||||
82
helpers.go
Normal file
82
helpers.go
Normal file
@ -0,0 +1,82 @@
|
||||
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
|
||||
}
|
||||
|
||||
66
hero_statement.go
Normal file
66
hero_statement.go
Normal file
@ -0,0 +1,66 @@
|
||||
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()
|
||||
}
|
||||
45
hero_statement.templ
Normal file
45
hero_statement.templ
Normal file
@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
183
hero_statement_templ.go
Normal file
183
hero_statement_templ.go
Normal file
@ -0,0 +1,183 @@
|
||||
// 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
|
||||
60
leadership_grid.go
Normal file
60
leadership_grid.go
Normal file
@ -0,0 +1,60 @@
|
||||
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()
|
||||
}
|
||||
48
leadership_grid.templ
Normal file
48
leadership_grid.templ
Normal file
@ -0,0 +1,48 @@
|
||||
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"
|
||||
}
|
||||
207
leadership_grid_templ.go
Normal file
207
leadership_grid_templ.go
Normal file
@ -0,0 +1,207 @@
|
||||
// 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
|
||||
55
logo_strip.go
Normal file
55
logo_strip.go
Normal file
@ -0,0 +1,55 @@
|
||||
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()
|
||||
}
|
||||
44
logo_strip.templ
Normal file
44
logo_strip.templ
Normal file
@ -0,0 +1,44 @@
|
||||
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"
|
||||
}
|
||||
203
logo_strip_templ.go
Normal file
203
logo_strip_templ.go
Normal file
@ -0,0 +1,203 @@
|
||||
// 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
|
||||
12
plugin.mod
Normal file
12
plugin.mod
Normal file
@ -0,0 +1,12 @@
|
||||
[plugin]
|
||||
name = "corporate-modernist"
|
||||
display_name = "Corporate Modernist"
|
||||
scope = "@themes"
|
||||
version = "0.1.0"
|
||||
description = "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites."
|
||||
kind = "theme"
|
||||
categories = ["templates"]
|
||||
tags = ["business", "corporate", "enterprise", "consulting", "legal", "professional", "b2b", "swiss"]
|
||||
|
||||
[compatibility]
|
||||
block_core = ">=0.11.0 <0.12.0"
|
||||
152
presets.json
Normal file
152
presets.json
Normal file
@ -0,0 +1,152 @@
|
||||
[
|
||||
{
|
||||
"id": "navy-classic",
|
||||
"name": "Navy Classic",
|
||||
"description": "Deep navy on paper. The safe choice for accountancy, law, and finance.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "0 0% 100%",
|
||||
"foreground": "220 20% 12%",
|
||||
"card": "0 0% 100%",
|
||||
"cardForeground": "220 20% 12%",
|
||||
"popover": "0 0% 100%",
|
||||
"popoverForeground": "220 20% 12%",
|
||||
"primary": "218 65% 22%",
|
||||
"primaryForeground": "0 0% 100%",
|
||||
"secondary": "220 14% 96%",
|
||||
"secondaryForeground": "220 20% 12%",
|
||||
"muted": "220 14% 96%",
|
||||
"mutedForeground": "220 10% 40%",
|
||||
"accent": "218 65% 22%",
|
||||
"accentForeground": "0 0% 100%",
|
||||
"destructive": "0 72% 42%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "220 14% 90%",
|
||||
"input": "220 14% 90%",
|
||||
"ring": "218 65% 22%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "220 25% 8%",
|
||||
"foreground": "220 10% 95%",
|
||||
"card": "220 25% 11%",
|
||||
"cardForeground": "220 10% 95%",
|
||||
"popover": "220 25% 11%",
|
||||
"popoverForeground": "220 10% 95%",
|
||||
"primary": "218 70% 60%",
|
||||
"primaryForeground": "220 25% 8%",
|
||||
"secondary": "220 20% 18%",
|
||||
"secondaryForeground": "220 10% 95%",
|
||||
"muted": "220 20% 16%",
|
||||
"mutedForeground": "220 10% 65%",
|
||||
"accent": "218 70% 60%",
|
||||
"accentForeground": "220 25% 8%",
|
||||
"destructive": "0 62% 50%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "220 20% 22%",
|
||||
"input": "220 20% 22%",
|
||||
"ring": "218 70% 60%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "forest-quiet",
|
||||
"name": "Forest Quiet",
|
||||
"description": "Same chassis, deep green accent for sustainability, advisory, ESG.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "0 0% 100%",
|
||||
"foreground": "150 18% 12%",
|
||||
"card": "0 0% 100%",
|
||||
"cardForeground": "150 18% 12%",
|
||||
"popover": "0 0% 100%",
|
||||
"popoverForeground": "150 18% 12%",
|
||||
"primary": "155 45% 22%",
|
||||
"primaryForeground": "0 0% 100%",
|
||||
"secondary": "150 12% 96%",
|
||||
"secondaryForeground": "150 18% 12%",
|
||||
"muted": "150 12% 96%",
|
||||
"mutedForeground": "150 10% 40%",
|
||||
"accent": "155 45% 22%",
|
||||
"accentForeground": "0 0% 100%",
|
||||
"destructive": "0 72% 42%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "150 12% 90%",
|
||||
"input": "150 12% 90%",
|
||||
"ring": "155 45% 22%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "150 18% 8%",
|
||||
"foreground": "150 8% 95%",
|
||||
"card": "150 18% 11%",
|
||||
"cardForeground": "150 8% 95%",
|
||||
"popover": "150 18% 11%",
|
||||
"popoverForeground": "150 8% 95%",
|
||||
"primary": "155 50% 55%",
|
||||
"primaryForeground": "150 18% 8%",
|
||||
"secondary": "150 15% 18%",
|
||||
"secondaryForeground": "150 8% 95%",
|
||||
"muted": "150 15% 16%",
|
||||
"mutedForeground": "150 8% 65%",
|
||||
"accent": "155 50% 55%",
|
||||
"accentForeground": "150 18% 8%",
|
||||
"destructive": "0 62% 50%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "150 15% 22%",
|
||||
"input": "150 15% 22%",
|
||||
"ring": "155 50% 55%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "burgundy-tradition",
|
||||
"name": "Burgundy Tradition",
|
||||
"description": "Heritage accent for old-line legal, private banking, partnerships.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "0 0% 100%",
|
||||
"foreground": "355 18% 12%",
|
||||
"card": "0 0% 100%",
|
||||
"cardForeground": "355 18% 12%",
|
||||
"popover": "0 0% 100%",
|
||||
"popoverForeground": "355 18% 12%",
|
||||
"primary": "350 55% 30%",
|
||||
"primaryForeground": "0 0% 100%",
|
||||
"secondary": "355 12% 96%",
|
||||
"secondaryForeground": "355 18% 12%",
|
||||
"muted": "355 12% 96%",
|
||||
"mutedForeground": "355 10% 40%",
|
||||
"accent": "350 55% 30%",
|
||||
"accentForeground": "0 0% 100%",
|
||||
"destructive": "0 72% 42%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "355 12% 90%",
|
||||
"input": "355 12% 90%",
|
||||
"ring": "350 55% 30%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "355 18% 8%",
|
||||
"foreground": "355 8% 95%",
|
||||
"card": "355 18% 11%",
|
||||
"cardForeground": "355 8% 95%",
|
||||
"popover": "355 18% 11%",
|
||||
"popoverForeground": "355 8% 95%",
|
||||
"primary": "350 60% 60%",
|
||||
"primaryForeground": "355 18% 8%",
|
||||
"secondary": "355 15% 18%",
|
||||
"secondaryForeground": "355 8% 95%",
|
||||
"muted": "355 15% 16%",
|
||||
"mutedForeground": "355 8% 65%",
|
||||
"accent": "350 60% 60%",
|
||||
"accentForeground": "355 18% 8%",
|
||||
"destructive": "0 62% 50%",
|
||||
"destructiveForeground": "0 0% 100%",
|
||||
"border": "355 15% 22%",
|
||||
"input": "355 15% 22%",
|
||||
"ring": "350 60% 60%"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
169
register.go
Normal file
169
register.go
Normal file
@ -0,0 +1,169 @@
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
34
registration.go
Normal file
34
registration.go
Normal file
@ -0,0 +1,34 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
41
schemas/case_study_card.schema.json
Normal file
41
schemas/case_study_card.schema.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Case Study Card",
|
||||
"description": "Single case study card with a tabular metric.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client": {
|
||||
"type": "string",
|
||||
"title": "Client",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"metric": {
|
||||
"type": "string",
|
||||
"title": "Metric",
|
||||
"description": "Large tabular numeral (e.g. \"3.2x\", \"$120M\", \"47%\")",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"title": "Metric label",
|
||||
"description": "Short qualifier underneath the metric",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"title": "Summary",
|
||||
"description": "One- or two-sentence outcome",
|
||||
"x-editor": "textarea"
|
||||
},
|
||||
"href": {
|
||||
"type": "object",
|
||||
"title": "Link",
|
||||
"description": "Read-more link to the full case study",
|
||||
"x-editor": "link",
|
||||
"properties": {
|
||||
"label": { "type": "string", "title": "Label" },
|
||||
"href": { "type": "string", "title": "Href" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
schemas/cta_strip.schema.json
Normal file
30
schemas/cta_strip.schema.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "CTA Strip",
|
||||
"description": "Single-line accent strip with a headline and a primary call to action.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headline": {
|
||||
"type": "string",
|
||||
"title": "Headline",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"primaryCta": {
|
||||
"type": "object",
|
||||
"title": "Primary CTA",
|
||||
"x-editor": "link",
|
||||
"properties": {
|
||||
"label": { "type": "string", "title": "Label" },
|
||||
"href": { "type": "string", "title": "Href" }
|
||||
}
|
||||
},
|
||||
"variant": {
|
||||
"type": "string",
|
||||
"title": "Variant",
|
||||
"description": "Visual treatment for the strip",
|
||||
"x-editor": "select",
|
||||
"enum": ["book-call", "download", "quiet"],
|
||||
"default": "book-call"
|
||||
}
|
||||
}
|
||||
}
|
||||
52
schemas/footer.schema.json
Normal file
52
schemas/footer.schema.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Footer",
|
||||
"description": "Multi-column footer with legal line, available in compact and full variants.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"columns": {
|
||||
"type": "array",
|
||||
"title": "Columns",
|
||||
"description": "Each column lists a title and a set of links",
|
||||
"default": [],
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": { "type": "string", "title": "Title", "x-editor": "text" },
|
||||
"links": {
|
||||
"type": "array",
|
||||
"title": "Links",
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": { "type": "string", "title": "Label", "x-editor": "text" },
|
||||
"href": { "type": "string", "title": "Href", "x-editor": "link" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"legalLine": {
|
||||
"type": "string",
|
||||
"title": "Legal line",
|
||||
"description": "Copyright or compliance statement",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"showLegal": {
|
||||
"type": "boolean",
|
||||
"title": "Show legal line",
|
||||
"default": true,
|
||||
"x-editor": "select"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string",
|
||||
"title": "Variant",
|
||||
"x-editor": "select",
|
||||
"enum": ["compact", "full"],
|
||||
"default": "compact"
|
||||
}
|
||||
}
|
||||
}
|
||||
46
schemas/hero_statement.schema.json
Normal file
46
schemas/hero_statement.schema.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Hero Statement",
|
||||
"description": "Restrained hero with eyebrow, headline, lede, and a single accent CTA (plus optional outline secondary).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eyebrow": {
|
||||
"type": "string",
|
||||
"title": "Eyebrow",
|
||||
"description": "Small uppercase label above the headline",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"headline": {
|
||||
"type": "string",
|
||||
"title": "Headline",
|
||||
"description": "Lead statement, typically one short sentence",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"lede": {
|
||||
"type": "string",
|
||||
"title": "Lede",
|
||||
"description": "Supporting paragraph below the headline",
|
||||
"x-editor": "textarea"
|
||||
},
|
||||
"primaryCta": {
|
||||
"type": "object",
|
||||
"title": "Primary CTA",
|
||||
"description": "Accent-filled call to action",
|
||||
"x-editor": "link",
|
||||
"properties": {
|
||||
"label": { "type": "string", "title": "Label" },
|
||||
"href": { "type": "string", "title": "Href" }
|
||||
}
|
||||
},
|
||||
"secondaryCta": {
|
||||
"type": "object",
|
||||
"title": "Secondary CTA",
|
||||
"description": "Optional outline call to action",
|
||||
"x-editor": "link",
|
||||
"properties": {
|
||||
"label": { "type": "string", "title": "Label" },
|
||||
"href": { "type": "string", "title": "Href" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
schemas/leadership_grid.schema.json
Normal file
32
schemas/leadership_grid.schema.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Leadership Grid",
|
||||
"description": "Responsive 2/3/4-up grid of leadership profiles.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Title",
|
||||
"description": "Section title above the grid",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"title": "Members",
|
||||
"description": "Each member is a card with photo, name, role, short bio, and optional LinkedIn link",
|
||||
"default": [],
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string", "title": "Name", "x-editor": "text" },
|
||||
"role": { "type": "string", "title": "Role", "x-editor": "text" },
|
||||
"bio": { "type": "string", "title": "Bio", "x-editor": "textarea" },
|
||||
"photo": { "type": "string", "title": "Photo", "x-editor": "media" },
|
||||
"linkedin": { "type": "string", "title": "LinkedIn URL", "x-editor": "link" }
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
schemas/logo_strip.schema.json
Normal file
42
schemas/logo_strip.schema.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Client Logo Strip",
|
||||
"description": "Row of client logos rendered greyscale until hover.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"caption": {
|
||||
"type": "string",
|
||||
"title": "Caption",
|
||||
"description": "Short heading above the logo row",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"logos": {
|
||||
"type": "array",
|
||||
"title": "Logos",
|
||||
"description": "Client logos shown in a single restrained row",
|
||||
"default": [],
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"title": "Image",
|
||||
"x-editor": "media"
|
||||
},
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"title": "Alt text",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"title": "Link",
|
||||
"x-editor": "link"
|
||||
}
|
||||
},
|
||||
"required": ["alt"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
schemas/stat_pair.schema.json
Normal file
30
schemas/stat_pair.schema.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Stat Pair",
|
||||
"description": "Pair (or row) of mono-numeral statistics, separated by a hairline rule.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Title",
|
||||
"description": "Optional title above the stats row",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"stats": {
|
||||
"type": "array",
|
||||
"title": "Stats",
|
||||
"description": "Individual statistic entries",
|
||||
"default": [],
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"figure": { "type": "string", "title": "Figure", "x-editor": "text" },
|
||||
"label": { "type": "string", "title": "Label", "x-editor": "text" },
|
||||
"source": { "type": "string", "title": "Source", "x-editor": "text" }
|
||||
},
|
||||
"required": ["figure"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
schemas/testimonial_quote.schema.json
Normal file
41
schemas/testimonial_quote.schema.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Testimonial",
|
||||
"description": "Pull-quote testimonial with attribution and optional headshot and company logo.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"quote": {
|
||||
"type": "string",
|
||||
"title": "Quote",
|
||||
"description": "Testimonial body text",
|
||||
"x-editor": "textarea"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"title": "Role",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"company": {
|
||||
"type": "string",
|
||||
"title": "Company",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"headshot": {
|
||||
"type": "string",
|
||||
"title": "Headshot",
|
||||
"description": "Portrait image of the quoted person",
|
||||
"x-editor": "media"
|
||||
},
|
||||
"logo": {
|
||||
"type": "string",
|
||||
"title": "Company logo",
|
||||
"description": "Optional company mark beside the attribution",
|
||||
"x-editor": "media"
|
||||
}
|
||||
}
|
||||
}
|
||||
56
stat_pair.go
Normal file
56
stat_pair.go
Normal file
@ -0,0 +1,56 @@
|
||||
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()
|
||||
}
|
||||
45
stat_pair.templ
Normal file
45
stat_pair.templ
Normal file
@ -0,0 +1,45 @@
|
||||
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;"
|
||||
}
|
||||
}
|
||||
167
stat_pair_templ.go
Normal file
167
stat_pair_templ.go
Normal file
@ -0,0 +1,167 @@
|
||||
// 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
|
||||
274
template.templ
Normal file
274
template.templ
Normal file
@ -0,0 +1,274 @@
|
||||
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))
|
||||
}
|
||||
528
template_templ.go
Normal file
528
template_templ.go
Normal file
@ -0,0 +1,528 @@
|
||||
// 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
|
||||
43
testimonial_quote.go
Normal file
43
testimonial_quote.go
Normal file
@ -0,0 +1,43 @@
|
||||
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()
|
||||
}
|
||||
63
testimonial_quote.templ
Normal file
63
testimonial_quote.templ
Normal file
@ -0,0 +1,63 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
213
testimonial_quote_templ.go
Normal file
213
testimonial_quote_templ.go
Normal file
@ -0,0 +1,213 @@
|
||||
// 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
|
||||
17
text_override.go
Normal file
17
text_override.go
Normal file
@ -0,0 +1,17 @@
|
||||
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()
|
||||
}
|
||||
8
text_override.templ
Normal file
8
text_override.templ
Normal file
@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
// textOverrideComponent renders the Corporate Modernist text override.
|
||||
templ textOverrideComponent(text, class string) {
|
||||
<div class={ "cm-text", class }>
|
||||
@templ.Raw(text)
|
||||
</div>
|
||||
}
|
||||
67
text_override_templ.go
Normal file
67
text_override_templ.go
Normal file
@ -0,0 +1,67 @@
|
||||
// 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
|
||||
Loading…
x
Reference in New Issue
Block a user