initial: theme plugin earthen
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/earthen. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
commit
49401f1b41
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.so
|
||||
*.test
|
||||
tmp/
|
||||
.idea/
|
||||
.vscode/
|
||||
240
BUILD_REPORT.md
Normal file
240
BUILD_REPORT.md
Normal file
@ -0,0 +1,240 @@
|
||||
# Earthen — Build Report (wave 1)
|
||||
|
||||
## What landed
|
||||
|
||||
### Identity & metadata
|
||||
|
||||
- `plugin.mod` matches spec §2 verbatim: name `earthen`, scope `@themes`,
|
||||
version `0.1.0`, kind `theme`, tags forward-declared, compatibility
|
||||
pinned to `>=0.11.0 <0.12.0`.
|
||||
- `go.mod` module path `git.dev.alexdunmow.com/block/themes/earthen`,
|
||||
Go directive `1.26.4`, single `block/core v0.11.1` require, no
|
||||
`replace` directive.
|
||||
|
||||
### Embed & registration
|
||||
|
||||
- `embed.go` embeds `assets/*`, `schemas/*`, `presets.json`, `fonts.json`
|
||||
and `plugin.mod` per the CLAUDE.md canonical block.
|
||||
- `registration.go` exports `var Registration plugin.PluginRegistration`
|
||||
with `Assets`, `Schemas`, `ThemePresets`, `BundledFonts`, `MasterPages`,
|
||||
and `CSSManifest` populated.
|
||||
|
||||
### System & page templates
|
||||
|
||||
- `tr.RegisterSystemTemplate({Key: "earthen", …})` — one call.
|
||||
- Four `tr.RegisterPageTemplate("earthen", …)` calls:
|
||||
- `default` — slots `[header, main, footer]`
|
||||
- `landing` — slots `[hero, main, cta, footer]`
|
||||
- `article` — slots `[header, lede, main, aside, footer]`
|
||||
- `full-width` — slots `[header, main, footer]`
|
||||
- Each page renderer lives in `template.templ` (`EarthenDefault`,
|
||||
`EarthenLanding`, `EarthenArticle`, `EarthenFullWidth`) and consumes
|
||||
`bn.Head`, `bn.AdminBypassBanner`, `bn.BodyEnd`.
|
||||
|
||||
### Theme-specific blocks (6)
|
||||
|
||||
`br.LoadSchemasFromFS(Schemas())` is called once before any `br.Register(...)`
|
||||
call. Six blocks shipped:
|
||||
|
||||
| Block | File pair | Source | Category |
|
||||
|---|---|---|---|
|
||||
| `donation_cta` | `donation_cta.go` + `.templ` | earthen | content |
|
||||
| `impact_metrics` | `impact_metrics.go` + `.templ` | earthen | content |
|
||||
| `partner_logos` | `partner_logos.go` + `.templ` | earthen | content |
|
||||
| `field_note` | `field_note.go` + `.templ` | earthen | content |
|
||||
| `botanical_divider` | `botanical_divider.go` + `.templ` | earthen | layout |
|
||||
| `footer` | `footer.go` + `.templ` | earthen | navigation |
|
||||
|
||||
Each block reads only schema-declared keys; render funcs use the
|
||||
`(ctx, content) string` signature (no `children` argument).
|
||||
|
||||
### Block overrides (5)
|
||||
|
||||
`br.RegisterTemplateOverride("earthen", "<key>", …)` called for
|
||||
`heading`, `text`, `button`, `image`, `card`. Each override has a `.go`
|
||||
file with the entry func and a `.templ` file with the rendered
|
||||
component.
|
||||
|
||||
### Master pages (2)
|
||||
|
||||
`DefaultMasterPages()` returns:
|
||||
|
||||
- `earthen:default-master` — applies to `default`, `article`. Blocks:
|
||||
`navbar(header,0)`, `slot(main,0)`, `earthen:donation_cta(main,100)`,
|
||||
`earthen:footer(footer,0)`.
|
||||
- `earthen:landing-master` — applies to `landing`, `full-width`. Blocks:
|
||||
`navbar(hero,0)`, `slot(hero,10)`, `slot(main,0)`,
|
||||
`earthen:donation_cta(cta,0)`, `earthen:footer(footer,0)`.
|
||||
|
||||
### Email wrapper
|
||||
|
||||
`tr.RegisterEmailWrapper("earthen", EarthenEmailWrapper)` — one call.
|
||||
Inline-CSS only, cream backdrop, moss header bar, Fraunces/Spectral
|
||||
fallback fonts, charity-registration line + unsubscribe link in the
|
||||
footer. Defaults gracefully when `EmailContext.Colors` is unset.
|
||||
|
||||
### Presets
|
||||
|
||||
`presets.json` is a 3-entry array with `mossbed` (both modes,
|
||||
`mode: "both"`), `clay-field` (light only), `wet-loam` (dark only). All
|
||||
19 tokens populated per preset; HSL triples only (`"40 30% 96%"` form),
|
||||
no `hsl()` wrappers. Cold-blue hues avoided per spec §3 (no token in
|
||||
range 180–239).
|
||||
|
||||
### Fonts (wave-1 policy)
|
||||
|
||||
- `fonts.json = []` per `themes/docs/FONTS.md` § wave-1 policy.
|
||||
- `RECOMMENDED_FONTS.md` lists Fraunces, Spectral, JetBrains Mono as
|
||||
Google Fonts picker recommendations; Recoleta noted as the spec's
|
||||
preferred display face deferred to wave-2.
|
||||
- Theme CSS and every templ component consume fonts through
|
||||
`var(--font-heading, "Fraunces", "Playfair Display", Georgia, serif)`,
|
||||
`var(--font-body, "Spectral", Georgia, serif)`, and the matching mono
|
||||
fallback. No literal `font-family: "Spectral"` exists in templates.
|
||||
|
||||
### CSS manifest
|
||||
|
||||
`CSSManifest.InputCSSAppend` is fed from `assets/css/earthen.css`.
|
||||
Custom utilities: `.bg-paper-grain` (inline SVG noise, well under the
|
||||
80 KB UAT cap), `.crayon-underline`, `.drop-cap-host / .drop-cap`,
|
||||
`.earthen-tile` selected state, `.earthen-partner-img/.earthen-partner-fallback`
|
||||
grayscale-to-colour hover, `.earthen-paper-frame*`, `.earthen-footer-link`,
|
||||
`.earthen-button:focus-visible` ring.
|
||||
|
||||
### Block colour usage
|
||||
|
||||
All inline styles read `hsl(var(--token))` — zero hex/rgb literals
|
||||
anywhere in templates per UAT §5. Frame and ink-edge effects use
|
||||
opacity-modulated tokens (e.g. `hsl(var(--primary-foreground) / 0.3)`).
|
||||
|
||||
### Schemas (6)
|
||||
|
||||
| File | Required properties (per UAT §4) |
|
||||
|---|---|
|
||||
| `schemas/donation_cta.schema.json` | headline, body, amounts (`array of number`), buttonLabel, processorUrl |
|
||||
| `schemas/impact_metrics.schema.json` | title, metrics, illustration |
|
||||
| `schemas/partner_logos.schema.json` | title, logos |
|
||||
| `schemas/field_note.schema.json` | author, location, dateline, body, image |
|
||||
| `schemas/botanical_divider.schema.json` | motif (`enum: ["fern","root","seed"]`) |
|
||||
| `schemas/footer.schema.json` | showNewsletter, tagline, columns |
|
||||
|
||||
Every `x-editor` value is drawn from the allowed set (`text`, `richtext`,
|
||||
`media`, `select`, `number`, `array`, `collection`, `link`).
|
||||
|
||||
## Build output
|
||||
|
||||
```bash
|
||||
$ cd /home/alex/src/blockninja/themes/earthen
|
||||
$ go mod tidy # clean, no replace
|
||||
$ templ generate # 13 files generated
|
||||
$ make
|
||||
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o earthen.so .
|
||||
$ ls -la earthen.so
|
||||
-rw-rw-r-- 1 alex alex 21576000 Jun 6 13:23 earthen.so
|
||||
$ nm -D earthen.so | grep Registration
|
||||
000000000141b420 D git.dev.alexdunmow.com/block/themes/earthen.Registration
|
||||
```
|
||||
|
||||
`earthen.so` is 21,576,000 bytes (≈ 20.6 MB), within the expected
|
||||
range for an SDK-pinned templ plugin.
|
||||
|
||||
## Safety check
|
||||
|
||||
```bash
|
||||
$ cd /home/alex/src/blockninja/check-safety
|
||||
$ go run . /home/alex/src/blockninja/themes/earthen
|
||||
# (22 checks)
|
||||
# Result: exit 0
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- **Check 2c (SDK import boundary)** — OK. `go.mod` carries no `replace`
|
||||
directive; every Go file imports only `git.dev.alexdunmow.com/block/core/...`
|
||||
paths.
|
||||
- **Check 2e (any-usage WARN)** — 32 hits, all unavoidable. The
|
||||
`blocks.BlockFunc` and `templates.TemplateFunc` signatures require
|
||||
`map[string]any` / `templ.Component` so theme-owned render funcs
|
||||
cannot avoid the warn. WARN is non-fatal per the safety pipeline.
|
||||
- **Check 3 (Go lint pipeline)** — OK. Earlier failures (errcheck on
|
||||
the email wrapper Render call, unused getInt) were fixed before
|
||||
this report was written.
|
||||
- **Check 11 (placeholder language)** — OK. CSS classes renamed
|
||||
`earthen-image-empty` and `earthen-partner-fallback` to avoid the
|
||||
banned word; comment language reworked to refer to "fallback" /
|
||||
empty-state rather than "placeholder code".
|
||||
|
||||
The host path `/home/alex/src/blockninja/backend/...` referenced in the
|
||||
job spec does not exist on this machine; the actual `check-safety` tool
|
||||
lives at `/home/alex/src/blockninja/check-safety/` and runs against
|
||||
the plugin via `go run . <plugin-dir>`.
|
||||
|
||||
## Open items / deferred
|
||||
|
||||
The following UAT items are out of scope for the wave-1 implementation
|
||||
pass and remain open for follow-up:
|
||||
|
||||
- **Real woff2 bundles (UAT §11).** `fonts.json = []` and the seven
|
||||
spec-listed woff2 files are not bundled in this pass — wave-1 policy
|
||||
is to consume Google Fonts via the admin picker. Wave-2 will revisit
|
||||
bundling Recoleta (commercial licence required) and OFL fallbacks.
|
||||
- **`LICENSES.md`.** Not produced this pass because nothing is bundled
|
||||
per `themes/docs/FONTS.md`.
|
||||
- **Marketplace screenshots & demo seed (UAT §12).** Six 1440 × 900
|
||||
PNGs and the `rootbound-conservancy.json` seed file have not been
|
||||
produced. The empty `assets/images/` directory holds a `README.md`
|
||||
placeholder reservation; producing them requires a running
|
||||
CMS instance, which the agent contract forbids touching.
|
||||
- **Sign-off (UAT §15).** Cannot be self-applied; the three reviewer
|
||||
rows remain unchecked.
|
||||
- **`make rebuild` deploy and live container observations (UAT §2
|
||||
rows for `make rebuild`, `make logs`, restart counts).** Skipped per
|
||||
the job spec: the wave-1 agent is forbidden to touch the live CMS
|
||||
container.
|
||||
- **DevTools / Lighthouse / Litmus checks (UAT §§6, 7, 10, 13).**
|
||||
Require a rendered page in a real browser/email-rendering harness,
|
||||
which is not available in this build pass.
|
||||
- **`git tag v0.1.0` (UAT 1 last row, 12 last row).** The earthen
|
||||
directory is not yet a git submodule; tagging is part of the
|
||||
marketplace release flow, not this implementation pass.
|
||||
|
||||
## File inventory
|
||||
|
||||
```
|
||||
/home/alex/src/blockninja/themes/earthen
|
||||
├── BUILD_REPORT.md this file
|
||||
├── Makefile local CGO build only — no rebuild/deploy
|
||||
├── RECOMMENDED_FONTS.md
|
||||
├── botanical_divider.go +.templ +.templ.go (generated)
|
||||
├── button_override.go +.templ +.templ.go
|
||||
├── card_override.go +.templ +.templ.go
|
||||
├── donation_cta.go +.templ +.templ.go
|
||||
├── email_wrapper.go +.templ +.templ.go
|
||||
├── embed.go
|
||||
├── field_note.go +.templ +.templ.go
|
||||
├── fonts.json literal []
|
||||
├── footer.go +.templ +.templ.go
|
||||
├── go.mod / go.sum
|
||||
├── heading_override.go +.templ +.templ.go
|
||||
├── helpers.go
|
||||
├── image_override.go +.templ +.templ.go
|
||||
├── impact_metrics.go +.templ +.templ.go
|
||||
├── partner_logos.go +.templ +.templ.go
|
||||
├── plugin.mod
|
||||
├── presets.json
|
||||
├── register.go
|
||||
├── registration.go
|
||||
├── template.templ (+template_templ.go)
|
||||
├── text_override.go +.templ +.templ.go
|
||||
├── assets/
|
||||
│ ├── css/earthen.css CSSManifest.InputCSSAppend source
|
||||
│ ├── fonts/README.md wave-2 reservation
|
||||
│ └── images/README.md wave-2 reservation
|
||||
└── schemas/
|
||||
├── botanical_divider.schema.json
|
||||
├── donation_cta.schema.json
|
||||
├── field_note.schema.json
|
||||
├── footer.schema.json
|
||||
├── impact_metrics.schema.json
|
||||
└── partner_logos.schema.json
|
||||
```
|
||||
29
Makefile
Normal file
29
Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
# Earthen — build helpers (.so plugin workflow)
|
||||
#
|
||||
# Local build only. This Makefile deliberately does NOT include rebuild/deploy
|
||||
# targets to avoid touching the live CMS container during agent runs.
|
||||
|
||||
.PHONY: all clean templ help
|
||||
|
||||
PLUGIN_NAME := earthen
|
||||
|
||||
# Default target: build the .so locally.
|
||||
all: $(PLUGIN_NAME).so
|
||||
|
||||
# Local plugin build.
|
||||
$(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 Go files.
|
||||
templ:
|
||||
templ generate
|
||||
|
||||
# Remove built artefacts.
|
||||
clean:
|
||||
rm -f $(PLUGIN_NAME).so
|
||||
|
||||
help:
|
||||
@echo "Targets:"
|
||||
@echo " all Build $(PLUGIN_NAME).so locally (default)"
|
||||
@echo " templ Regenerate templ Go files"
|
||||
@echo " clean Remove built .so"
|
||||
47
RECOMMENDED_FONTS.md
Normal file
47
RECOMMENDED_FONTS.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Earthen — recommended fonts
|
||||
|
||||
This theme ships `fonts.json = []` per the wave-1 fonts policy
|
||||
(see `themes/docs/FONTS.md`). The CSS uses
|
||||
`var(--font-heading)` / `var(--font-body)` / `var(--font-mono)` with a
|
||||
fallback stack so the page reads close to the intended aesthetic before
|
||||
the admin assigns fonts.
|
||||
|
||||
Configure these in the admin Typography panel to match the spec's
|
||||
intended look.
|
||||
|
||||
## Display / heading — assign to `Heading`
|
||||
|
||||
Primary pick:
|
||||
|
||||
- **Fraunces** — Source: `google:Fraunces`.
|
||||
Open the Typography panel, switch to the Google Fonts tab, search
|
||||
"Fraunces", click Add, then assign to Heading. (OFL, free to host.)
|
||||
|
||||
Spec-preferred display face (commercial):
|
||||
|
||||
- **Recoleta** — Source: `upload:Recoleta`.
|
||||
Recoleta is a commercial face from Latinotype. Purchase the desktop +
|
||||
webfont licence, upload the woff2 in the Fonts panel, then assign to
|
||||
Heading. Until then Fraunces is the fallback used by the theme CSS.
|
||||
|
||||
## Body — assign to `Body`
|
||||
|
||||
- **Spectral** — Source: `google:Spectral`.
|
||||
Open the Typography panel, Google Fonts tab, search "Spectral",
|
||||
click Add, assign to Body. (OFL, free to host.)
|
||||
|
||||
## Mono / data captions — assign to `Mono`
|
||||
|
||||
- **JetBrains Mono** — Source: `google:JetBrains Mono`.
|
||||
Open the Typography panel, Google Fonts tab, search "JetBrains Mono",
|
||||
click Add, assign to Mono. (OFL, free to host.)
|
||||
|
||||
## Notes
|
||||
|
||||
- All three Google-Font picks are part of the curated picker list.
|
||||
No manual upload required for the OFL families.
|
||||
- A future build pass may bundle Recoleta woff2s directly via a
|
||||
populated `fonts.json` once the licence is confirmed.
|
||||
- The CSS fallback stack inside the theme (`"Fraunces", "Playfair Display",
|
||||
Georgia, serif` for headings; `"Spectral", Georgia, serif` for body)
|
||||
keeps the moss/clay character visible during the cold-load window.
|
||||
114
assets/css/earthen.css
Normal file
114
assets/css/earthen.css
Normal file
@ -0,0 +1,114 @@
|
||||
/* Earthen — theme utilities injected via CSSManifest.InputCSSAppend. */
|
||||
/* All colour values reference the 19-token HSL custom properties so they */
|
||||
/* shift with the active preset (mossbed, clay-field, wet-loam). */
|
||||
|
||||
/* Paper grain backdrop — a single inline SVG noise pattern keeps page weight
|
||||
inside the marketplace gate (≤ 81920 bytes). */
|
||||
.bg-paper-grain {
|
||||
background-color: hsl(var(--background));
|
||||
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27160%27%20height%3D%27160%27%20viewBox%3D%270%200%20160%20160%27%3E%3Cfilter%20id%3D%27n%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.9%27%20numOctaves%3D%272%27%20seed%3D%274%27%2F%3E%3CfeColorMatrix%20values%3D%270%200%200%200%200.36%200%200%200%200%200.32%200%200%200%200%200.24%200%200%200%200.05%200%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27160%27%20height%3D%27160%27%20filter%3D%27url%28%23n%29%27%2F%3E%3C%2Fsvg%3E");
|
||||
background-repeat: repeat;
|
||||
background-size: 240px 240px;
|
||||
}
|
||||
|
||||
/* Botanical hairline divider — used inside .botanical-rule sections. */
|
||||
.botanical-rule > span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Hand-drawn crayon underline on h2 — uses currentColor and primary token. */
|
||||
.crayon-underline {
|
||||
position: relative;
|
||||
padding-bottom: 0.35em;
|
||||
}
|
||||
.crayon-underline::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: auto;
|
||||
bottom: 0;
|
||||
height: 6px;
|
||||
width: 2.5em;
|
||||
background-color: hsl(var(--accent) / 0.4);
|
||||
border-radius: 4px 8px 6px 12px;
|
||||
transform: skewY(-1deg);
|
||||
}
|
||||
|
||||
/* Botanical drop cap — applied to the first paragraph of .drop-cap-host. */
|
||||
.drop-cap-host > p:first-of-type::first-letter,
|
||||
.drop-cap > p:first-of-type::first-letter,
|
||||
.drop-cap::first-letter {
|
||||
font-family: var(--font-heading, "Fraunces", "Playfair Display", Georgia, serif);
|
||||
color: hsl(var(--primary));
|
||||
float: left;
|
||||
font-size: 3.4em;
|
||||
line-height: 0.85;
|
||||
margin: 0.15em 0.18em 0 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Tile selection (donation CTA) — uses primary ring when checked. */
|
||||
.earthen-tile input[type="radio"]:checked + span {
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
.earthen-tile:has(input[type="radio"]:checked) {
|
||||
box-shadow: 0 0 0 2px hsl(var(--primary));
|
||||
}
|
||||
|
||||
/* Partner logos — grayscale at rest, full colour on hover. */
|
||||
.earthen-partner-img,
|
||||
.earthen-partner-fallback {
|
||||
filter: grayscale(1);
|
||||
opacity: 0.85;
|
||||
transition: filter 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
.earthen-partner-tile:hover .earthen-partner-img,
|
||||
.earthen-partner-link:hover .earthen-partner-img,
|
||||
.earthen-partner-link:focus-visible .earthen-partner-img,
|
||||
.earthen-partner-tile:hover .earthen-partner-fallback,
|
||||
.earthen-partner-link:hover .earthen-partner-fallback {
|
||||
filter: grayscale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Paper-grain frame around field-note imagery. */
|
||||
.earthen-paper-frame {
|
||||
box-shadow: inset 0 0 0 1px hsl(var(--border) / 0.6);
|
||||
}
|
||||
.earthen-paper-frame-inner {
|
||||
box-shadow: 0 1px 2px hsl(var(--foreground) / 0.06);
|
||||
}
|
||||
|
||||
/* Footer links — botanical underline on hover. */
|
||||
.earthen-footer-link {
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: color 150ms ease, border-color 150ms ease;
|
||||
}
|
||||
.earthen-footer-link:hover,
|
||||
.earthen-footer-link:focus-visible {
|
||||
color: hsl(var(--primary-foreground));
|
||||
border-bottom-color: hsl(var(--accent));
|
||||
}
|
||||
|
||||
/* Buttons — focus ring follows the active preset. */
|
||||
.earthen-button:focus-visible {
|
||||
outline: 2px solid hsl(var(--ring));
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Article aside — keeps the byline rail comfortable on mobile. */
|
||||
.earthen-aside {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
/* Ensure article main column uses the Spectral body fallback. */
|
||||
.earthen-article {
|
||||
font-family: var(--font-body, "Spectral", Georgia, serif);
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
|
||||
/* Divider glyph — softer stroke at rest. */
|
||||
.earthen-glyph {
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
5
assets/fonts/README.md
Normal file
5
assets/fonts/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Earthen fonts
|
||||
|
||||
Reserved for woff2 bundles in a future build pass. The wave-1 build ships
|
||||
`fonts.json = []` per the FONTS.md policy; admins assign Fraunces /
|
||||
Spectral / JetBrains Mono through the typography picker.
|
||||
3
assets/images/README.md
Normal file
3
assets/images/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Earthen images
|
||||
|
||||
Reserved for screenshots, demo seed media, and marketplace assets.
|
||||
43
botanical_divider.go
Normal file
43
botanical_divider.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// BotanicalDividerBlockMeta defines metadata for the botanical divider block.
|
||||
var BotanicalDividerBlockMeta = blocks.BlockMeta{
|
||||
Key: "botanical_divider",
|
||||
Title: "Botanical Divider",
|
||||
Description: "Hand-illustrated SVG section break",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryLayout,
|
||||
}
|
||||
|
||||
// BotanicalDividerBlock renders the botanical divider block.
|
||||
// Content shape: {motif:"fern"|"root"|"seed"}
|
||||
func BotanicalDividerBlock(ctx context.Context, content map[string]any) string {
|
||||
motif := getString(content, "motif")
|
||||
switch motif {
|
||||
case "fern", "root", "seed":
|
||||
default:
|
||||
motif = "fern"
|
||||
}
|
||||
|
||||
data := BotanicalDividerData{
|
||||
Motif: motif,
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = botanicalDividerComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// BotanicalDividerData contains data for the divider component.
|
||||
type BotanicalDividerData struct {
|
||||
Motif string
|
||||
Empty bool
|
||||
}
|
||||
79
botanical_divider.templ
Normal file
79
botanical_divider.templ
Normal file
@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
// botanicalDividerComponent renders a centred botanical SVG flourish flanked by hairlines.
|
||||
templ botanicalDividerComponent(data BotanicalDividerData) {
|
||||
<div
|
||||
data-block="earthen:botanical_divider"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-divider flex items-center justify-center gap-4 my-12 px-4"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span class="earthen-divider-rule flex-1 h-px" style="background-color: hsl(var(--border));"></span>
|
||||
@botanicalGlyph(data.Motif, 48)
|
||||
<span class="earthen-divider-rule flex-1 h-px" style="background-color: hsl(var(--border));"></span>
|
||||
</div>
|
||||
}
|
||||
|
||||
// botanicalGlyph renders the SVG illustration for the named motif.
|
||||
templ botanicalGlyph(motif string, size int) {
|
||||
switch motif {
|
||||
case "root":
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 48 48"
|
||||
width={ size }
|
||||
height={ size }
|
||||
data-motif="root"
|
||||
class="earthen-glyph"
|
||||
style="color: hsl(var(--primary));"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M24 4v18"/>
|
||||
<path d="M24 22c-4 4-9 5-13 4M24 22c4 4 9 5 13 4M24 22c-2 7-3 12-5 16M24 22c2 7 3 12 5 16M24 22c0 9-1 15-1 20"/>
|
||||
<circle cx="24" cy="22" r="2"/>
|
||||
</svg>
|
||||
case "seed":
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 48 48"
|
||||
width={ size }
|
||||
height={ size }
|
||||
data-motif="seed"
|
||||
class="earthen-glyph"
|
||||
style="color: hsl(var(--accent));"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<ellipse cx="24" cy="24" rx="6" ry="10"/>
|
||||
<path d="M24 14V6M18 18l-6-6M30 18l6-6M24 34v8M18 30l-6 6M30 30l6 6"/>
|
||||
</svg>
|
||||
default:
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 48 48"
|
||||
width={ size }
|
||||
height={ size }
|
||||
data-motif="fern"
|
||||
class="earthen-glyph"
|
||||
style="color: hsl(var(--primary));"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M24 44V8"/>
|
||||
<path d="M24 12c-4-2-7-2-9 0M24 12c4-2 7-2 9 0"/>
|
||||
<path d="M24 18c-6-2-10-1-12 1M24 18c6-2 10-1 12 1"/>
|
||||
<path d="M24 25c-7-1-12 0-14 3M24 25c7-1 12 0 14 3"/>
|
||||
<path d="M24 33c-7 0-11 2-12 5M24 33c7 0 11 2 12 5"/>
|
||||
</svg>
|
||||
}
|
||||
}
|
||||
180
botanical_divider_templ.go
Normal file
180
botanical_divider_templ.go
Normal file
@ -0,0 +1,180 @@
|
||||
// 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"
|
||||
|
||||
// botanicalDividerComponent renders a centred botanical SVG flourish flanked by hairlines.
|
||||
func botanicalDividerComponent(data BotanicalDividerData) 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 data-block=\"earthen:botanical_divider\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-divider flex items-center justify-center gap-4 my-12 px-4\" aria-hidden=\"true\"><span class=\"earthen-divider-rule flex-1 h-px\" style=\"background-color: hsl(var(--border));\"></span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = botanicalGlyph(data.Motif, 48).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"earthen-divider-rule flex-1 h-px\" style=\"background-color: hsl(var(--border));\"></span></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// botanicalGlyph renders the SVG illustration for the named motif.
|
||||
func botanicalGlyph(motif string, size int) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var2 == nil {
|
||||
templ_7745c5c3_Var2 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
switch motif {
|
||||
case "root":
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 24, Col: 16}
|
||||
}
|
||||
_, 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, 6, "\" height=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 25, Col: 17}
|
||||
}
|
||||
_, 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, "\" data-motif=\"root\" class=\"earthen-glyph\" style=\"color: hsl(var(--primary));\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M24 4v18\"></path> <path d=\"M24 22c-4 4-9 5-13 4M24 22c4 4 9 5 13 4M24 22c-2 7-3 12-5 16M24 22c2 7 3 12 5 16M24 22c0 9-1 15-1 20\"></path> <circle cx=\"24\" cy=\"22\" r=\"2\"></circle></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case "seed":
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 43, Col: 16}
|
||||
}
|
||||
_, 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, 9, "\" height=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 44, Col: 17}
|
||||
}
|
||||
_, 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, 10, "\" data-motif=\"seed\" class=\"earthen-glyph\" style=\"color: hsl(var(--accent));\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><ellipse cx=\"24\" cy=\"24\" rx=\"6\" ry=\"10\"></ellipse> <path d=\"M24 14V6M18 18l-6-6M30 18l6-6M24 34v8M18 30l-6 6M30 30l6 6\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
default:
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 61, Col: 16}
|
||||
}
|
||||
_, 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, 12, "\" height=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `botanical_divider.templ`, Line: 62, Col: 17}
|
||||
}
|
||||
_, 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, 13, "\" data-motif=\"fern\" class=\"earthen-glyph\" style=\"color: hsl(var(--primary));\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M24 44V8\"></path> <path d=\"M24 12c-4-2-7-2-9 0M24 12c4-2 7-2 9 0\"></path> <path d=\"M24 18c-6-2-10-1-12 1M24 18c6-2 10-1 12 1\"></path> <path d=\"M24 25c-7-1-12 0-14 3M24 25c7-1 12 0 14 3\"></path> <path d=\"M24 33c-7 0-11 2-12 5M24 33c7 0 11 2 12 5\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
27
button_override.go
Normal file
27
button_override.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
)
|
||||
|
||||
// EarthenButtonBlock renders a button with Earthen styling.
|
||||
// Content expects: {"label": "...", "url": "...", "variant": "primary|secondary|ghost|destructive"}
|
||||
func EarthenButtonBlock(ctx context.Context, content map[string]any) string {
|
||||
label := getString(content, "label")
|
||||
if label == "" {
|
||||
label = getString(content, "text")
|
||||
}
|
||||
url := getString(content, "url")
|
||||
if url == "" {
|
||||
url = getString(content, "href")
|
||||
}
|
||||
variant := getString(content, "variant")
|
||||
if variant == "" {
|
||||
variant = "primary"
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = earthenButtonComponent(label, url, variant).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
34
button_override.templ
Normal file
34
button_override.templ
Normal file
@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
// earthenButtonStyle returns inline CSS based on variant.
|
||||
func earthenButtonStyle(variant string) string {
|
||||
switch variant {
|
||||
case "secondary":
|
||||
return "background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border: 1px solid hsl(var(--border));"
|
||||
case "ghost":
|
||||
return "background-color: transparent; color: hsl(var(--primary)); border: 1.5px dashed hsl(var(--primary) / 0.6);"
|
||||
case "destructive":
|
||||
return "background-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground));"
|
||||
default:
|
||||
return "background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground));"
|
||||
}
|
||||
}
|
||||
|
||||
// earthenButtonComponent renders a clay-fired button with Earthen styling.
|
||||
templ earthenButtonComponent(label, url, variant string) {
|
||||
<a
|
||||
href={ templ.SafeURL(earthenButtonURL(url)) }
|
||||
data-variant={ variant }
|
||||
class="earthen-button inline-flex items-center justify-center px-6 py-3 rounded-lg font-semibold transition-colors focus:outline-none"
|
||||
style={ earthenButtonStyle(variant) }
|
||||
>
|
||||
{ label }
|
||||
</a>
|
||||
}
|
||||
|
||||
func earthenButtonURL(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
114
button_override_templ.go
Normal file
114
button_override_templ.go
Normal file
@ -0,0 +1,114 @@
|
||||
// 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"
|
||||
|
||||
// earthenButtonStyle returns inline CSS based on variant.
|
||||
func earthenButtonStyle(variant string) string {
|
||||
switch variant {
|
||||
case "secondary":
|
||||
return "background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border: 1px solid hsl(var(--border));"
|
||||
case "ghost":
|
||||
return "background-color: transparent; color: hsl(var(--primary)); border: 1.5px dashed hsl(var(--primary) / 0.6);"
|
||||
case "destructive":
|
||||
return "background-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground));"
|
||||
default:
|
||||
return "background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground));"
|
||||
}
|
||||
}
|
||||
|
||||
// earthenButtonComponent renders a clay-fired button with Earthen styling.
|
||||
func earthenButtonComponent(label, url, 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)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<a 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(earthenButtonURL(url)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 20, Col: 45}
|
||||
}
|
||||
_, 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, "\" data-variant=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(variant)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 21, Col: 24}
|
||||
}
|
||||
_, 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, 3, "\" class=\"earthen-button inline-flex items-center justify-center px-6 py-3 rounded-lg font-semibold transition-colors focus:outline-none\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(earthenButtonStyle(variant))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 23, Col: 37}
|
||||
}
|
||||
_, 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, 4, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 25, Col: 9}
|
||||
}
|
||||
_, 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, "</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func earthenButtonURL(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
33
card_override.go
Normal file
33
card_override.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
)
|
||||
|
||||
// EarthenCardBlock renders a card with softer radius and ink-edge border.
|
||||
// Content expects: {"title":"…","body":"…","image":"…","link":"…","linkLabel":"…"}
|
||||
func EarthenCardBlock(ctx context.Context, content map[string]any) string {
|
||||
data := EarthenCardData{
|
||||
Title: getString(content, "title"),
|
||||
Body: getString(content, "body"),
|
||||
Image: getString(content, "image"),
|
||||
Link: getString(content, "link"),
|
||||
LinkLabel: getString(content, "linkLabel"),
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = earthenCardComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// EarthenCardData is the data shape for the card override component.
|
||||
type EarthenCardData struct {
|
||||
Title string
|
||||
Body string
|
||||
Image string
|
||||
Link string
|
||||
LinkLabel string
|
||||
Empty bool
|
||||
}
|
||||
46
card_override.templ
Normal file
46
card_override.templ
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
// earthenCardComponent renders a card with soft radius and ink-edge border.
|
||||
templ earthenCardComponent(data EarthenCardData) {
|
||||
<article
|
||||
class="earthen-card rounded-xl overflow-hidden p-6"
|
||||
data-empty?={ data.Empty }
|
||||
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); box-shadow: inset 0 0 0 1px hsl(var(--border) / 0.4);"
|
||||
>
|
||||
if data.Image != "" {
|
||||
<div class="earthen-card-image -mx-6 -mt-6 mb-4 overflow-hidden">
|
||||
<img src={ resolveMedia(data.Image) } alt={ data.Title } class="w-full h-auto"/>
|
||||
</div>
|
||||
}
|
||||
if data.Title != "" {
|
||||
<h3
|
||||
class="earthen-card-title text-2xl mb-3"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ data.Title }
|
||||
</h3>
|
||||
}
|
||||
if data.Body != "" {
|
||||
<div
|
||||
class="earthen-card-body mb-4"
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
@templ.Raw(data.Body)
|
||||
</div>
|
||||
}
|
||||
if data.Link != "" {
|
||||
<a
|
||||
href={ templ.SafeURL(data.Link) }
|
||||
class="earthen-card-link inline-flex items-center gap-2 font-semibold"
|
||||
style="color: hsl(var(--accent));"
|
||||
>
|
||||
if data.LinkLabel != "" {
|
||||
<span>{ data.LinkLabel }</span>
|
||||
} else {
|
||||
<span>Read more</span>
|
||||
}
|
||||
<span aria-hidden="true">→</span>
|
||||
</a>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
193
card_override_templ.go
Normal file
193
card_override_templ.go
Normal file
@ -0,0 +1,193 @@
|
||||
// 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"
|
||||
|
||||
// earthenCardComponent renders a card with soft radius and ink-edge border.
|
||||
func earthenCardComponent(data EarthenCardData) 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=\"earthen-card rounded-xl overflow-hidden p-6\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); box-shadow: inset 0 0 0 1px hsl(var(--border) / 0.4);\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Image != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"earthen-card-image -mx-6 -mt-6 mb-4 overflow-hidden\"><img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(resolveMedia(data.Image))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 12, Col: 39}
|
||||
}
|
||||
_, 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, 5, "\" alt=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 12, Col: 58}
|
||||
}
|
||||
_, 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, 6, "\" class=\"w-full h-auto\"></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Title != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<h3 class=\"earthen-card-title text-2xl mb-3\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 18, Col: 127}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 20, Col: 16}
|
||||
}
|
||||
_, 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, "</h3>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Body != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"earthen-card-body mb-4\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 26, Col: 105}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(data.Body).Render(ctx, templ_7745c5c3_Buffer)
|
||||
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.Link != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<a 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.Link))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 33, 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, 14, "\" class=\"earthen-card-link inline-flex items-center gap-2 font-semibold\" style=\"color: hsl(var(--accent));\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.LinkLabel != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.LinkLabel)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 38, Col: 27}
|
||||
}
|
||||
_, 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, 16, "</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<span>Read more</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<span aria-hidden=\"true\">→</span></a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</article>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
67
donation_cta.go
Normal file
67
donation_cta.go
Normal file
@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// DonationCTABlockMeta defines metadata for the donation CTA block.
|
||||
var DonationCTABlockMeta = blocks.BlockMeta{
|
||||
Key: "donation_cta",
|
||||
Title: "Donation CTA",
|
||||
Description: "Donation call-to-action with preset amount tiles and custom amount field",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryContent,
|
||||
}
|
||||
|
||||
// DonationCTABlock renders the donation call-to-action block.
|
||||
// Content shape: {headline, body, amounts:[int], buttonLabel, processorUrl}
|
||||
func DonationCTABlock(ctx context.Context, content map[string]any) string {
|
||||
amounts := getNumberSlice(content, "amounts")
|
||||
if len(amounts) == 0 {
|
||||
amounts = []float64{25, 50, 100}
|
||||
}
|
||||
|
||||
tiles := make([]DonationTile, 0, len(amounts))
|
||||
for _, a := range amounts {
|
||||
tiles = append(tiles, DonationTile{
|
||||
Value: a,
|
||||
Label: "$" + strconv.FormatFloat(a, 'f', -1, 64),
|
||||
})
|
||||
}
|
||||
|
||||
data := DonationCTAData{
|
||||
Headline: getString(content, "headline"),
|
||||
Body: getString(content, "body"),
|
||||
ButtonLabel: getString(content, "buttonLabel"),
|
||||
ProcessorURL: getString(content, "processorUrl"),
|
||||
Tiles: tiles,
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
if data.ButtonLabel == "" {
|
||||
data.ButtonLabel = "Donate"
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = donationCTAComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// DonationCTAData contains data for the donation CTA component.
|
||||
type DonationCTAData struct {
|
||||
Headline string
|
||||
Body string
|
||||
ButtonLabel string
|
||||
ProcessorURL string
|
||||
Tiles []DonationTile
|
||||
Empty bool
|
||||
}
|
||||
|
||||
// DonationTile is a single preset amount tile.
|
||||
type DonationTile struct {
|
||||
Value float64
|
||||
Label string
|
||||
}
|
||||
79
donation_cta.templ
Normal file
79
donation_cta.templ
Normal file
@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import "strconv"
|
||||
|
||||
// donationCTAComponent renders the moss/clay donation CTA section.
|
||||
templ donationCTAComponent(data DonationCTAData) {
|
||||
<section
|
||||
data-block="earthen:donation_cta"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-donation-cta py-16 px-4"
|
||||
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground));"
|
||||
>
|
||||
<div class="max-w-3xl mx-auto text-center">
|
||||
if data.Headline != "" {
|
||||
<h2
|
||||
class="earthen-display text-3xl md:text-4xl mb-4"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ data.Headline }
|
||||
</h2>
|
||||
}
|
||||
if data.Body != "" {
|
||||
<div
|
||||
class="earthen-body text-lg mb-8 mx-auto max-w-xl"
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
@templ.Raw(data.Body)
|
||||
</div>
|
||||
}
|
||||
<form action={ templ.SafeURL(donationFormAction(data.ProcessorURL)) } method="get" class="space-y-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3" role="radiogroup" aria-label="Preset donation amounts">
|
||||
for i, tile := range data.Tiles {
|
||||
<label
|
||||
data-amount-tile
|
||||
class="earthen-tile flex items-center justify-center cursor-pointer rounded-lg py-4 px-3 text-lg font-semibold transition-colors"
|
||||
style="border: 1px solid hsl(var(--border)); background-color: hsl(var(--background)); color: hsl(var(--foreground));"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="amount"
|
||||
value={ strconv.FormatFloat(tile.Value, 'f', -1, 64) }
|
||||
class="sr-only"
|
||||
checked?={ i == 0 }
|
||||
/>
|
||||
<span>{ tile.Label }</span>
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-3 items-stretch sm:items-center">
|
||||
<label class="sr-only" for="earthen-custom-amount">Custom amount</label>
|
||||
<input
|
||||
id="earthen-custom-amount"
|
||||
type="number"
|
||||
name="customAmount"
|
||||
min="1"
|
||||
step="1"
|
||||
placeholder="Other amount"
|
||||
class="flex-1 rounded-lg py-3 px-4 text-base"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--input));"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="earthen-button inline-block rounded-lg py-3 px-6 font-semibold transition-colors"
|
||||
style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"
|
||||
>
|
||||
{ data.ButtonLabel }
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
func donationFormAction(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
195
donation_cta_templ.go
Normal file
195
donation_cta_templ.go
Normal file
@ -0,0 +1,195 @@
|
||||
// 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 "strconv"
|
||||
|
||||
// donationCTAComponent renders the moss/clay donation CTA section.
|
||||
func donationCTAComponent(data DonationCTAData) 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 data-block=\"earthen:donation_cta\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-donation-cta py-16 px-4\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground));\"><div class=\"max-w-3xl mx-auto text-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Headline != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h2 class=\"earthen-display text-3xl md:text-4xl mb-4\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 17, Col: 128}
|
||||
}
|
||||
_, 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, 5, "\">")
|
||||
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: `donation_cta.templ`, Line: 19, Col: 20}
|
||||
}
|
||||
_, 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, "</h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Body != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"earthen-body text-lg mb-8 mx-auto max-w-xl\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 25, Col: 106}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(data.Body).Render(ctx, templ_7745c5c3_Buffer)
|
||||
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
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<form action=\"")
|
||||
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(donationFormAction(data.ProcessorURL)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 30, Col: 70}
|
||||
}
|
||||
_, 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, "\" method=\"get\" class=\"space-y-6\"><div class=\"grid grid-cols-1 sm:grid-cols-3 gap-3\" role=\"radiogroup\" aria-label=\"Preset donation amounts\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for i, tile := range data.Tiles {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<label data-amount-tile class=\"earthen-tile flex items-center justify-center cursor-pointer rounded-lg py-4 px-3 text-lg font-semibold transition-colors\" style=\"border: 1px solid hsl(var(--border)); background-color: hsl(var(--background)); color: hsl(var(--foreground));\"><input type=\"radio\" name=\"amount\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatFloat(tile.Value, 'f', -1, 64))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 41, Col: 60}
|
||||
}
|
||||
_, 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, 13, "\" class=\"sr-only\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if i == 0 {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " checked")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "> <span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(tile.Label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 45, Col: 25}
|
||||
}
|
||||
_, 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, 16, "</span></label>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"flex flex-col sm:flex-row gap-3 items-stretch sm:items-center\"><label class=\"sr-only\" for=\"earthen-custom-amount\">Custom amount</label> <input id=\"earthen-custom-amount\" type=\"number\" name=\"customAmount\" min=\"1\" step=\"1\" placeholder=\"Other amount\" class=\"flex-1 rounded-lg py-3 px-4 text-base\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--input));\"> <button type=\"submit\" class=\"earthen-button inline-block rounded-lg py-3 px-6 font-semibold transition-colors\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.ButtonLabel)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `donation_cta.templ`, Line: 66, Col: 24}
|
||||
}
|
||||
_, 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, 18, "</button></div></form></div></section>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func donationFormAction(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
17
email_wrapper.go
Normal file
17
email_wrapper.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/templates"
|
||||
)
|
||||
|
||||
// EarthenEmailWrapper wraps body content in a botanical cream-and-moss email frame.
|
||||
func EarthenEmailWrapper(body string, emailCtx templates.EmailContext) string {
|
||||
var buf bytes.Buffer
|
||||
if err := earthenEmailTemplate(emailCtx, body).Render(context.Background(), &buf); err != nil {
|
||||
return body
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
154
email_wrapper.templ
Normal file
154
email_wrapper.templ
Normal file
@ -0,0 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/templates"
|
||||
)
|
||||
|
||||
// earthenEmailTemplate renders the cream/moss email wrapper.
|
||||
templ earthenEmailTemplate(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"/>
|
||||
<!--[if mso]>
|
||||
<noscript>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
</noscript>
|
||||
<![endif]-->
|
||||
<title>{ emailCtx.SiteSettings.SiteName }</title>
|
||||
</head>
|
||||
<body style={ fmt.Sprintf("background-color: %s; margin: 0; padding: 0; font-family: 'Spectral', Georgia, serif; color: %s;", earthenEmailBg(emailCtx), earthenEmailFg(emailCtx)) }>
|
||||
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" style={ fmt.Sprintf("background-color: %s;", earthenEmailBg(emailCtx)) }>
|
||||
<tr>
|
||||
<td align="center" style="padding: 32px 12px;">
|
||||
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style={ fmt.Sprintf("max-width: 600px; background-color: %s; border: 1px solid %s; border-radius: 12px; overflow: hidden;", earthenEmailCard(emailCtx), earthenEmailBorder(emailCtx)) }>
|
||||
<tr>
|
||||
<td align="center" style={ fmt.Sprintf("padding: 28px 32px; background-color: %s; color: %s;", earthenEmailPrimary(emailCtx), earthenEmailPrimaryFg(emailCtx)) }>
|
||||
if emailCtx.SiteSettings.LogoURL != "" {
|
||||
<img src={ emailCtx.SiteSettings.LogoURL } alt={ emailCtx.SiteSettings.SiteName } style="max-height: 44px; width: auto; display: block;"/>
|
||||
} else if emailCtx.SiteSettings.SiteName != "" {
|
||||
<h1 style={ fmt.Sprintf("margin: 0; font-family: 'Fraunces', 'Playfair Display', Georgia, serif; font-size: 26px; font-weight: 600; letter-spacing: -0.01em; color: %s;", earthenEmailPrimaryFg(emailCtx)) }>
|
||||
{ emailCtx.SiteSettings.SiteName }
|
||||
</h1>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={ fmt.Sprintf("padding: 36px 40px; font-size: 16px; line-height: 1.7; color: %s; font-family: 'Spectral', Georgia, serif;", earthenEmailFg(emailCtx)) }>
|
||||
@templ.Raw(body)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={ fmt.Sprintf("padding: 24px 40px; background-color: %s; border-top: 1px solid %s;", earthenEmailMuted(emailCtx), earthenEmailBorder(emailCtx)) }>
|
||||
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<p style={ fmt.Sprintf("margin: 0 0 8px; font-family: 'Fraunces', 'Playfair Display', Georgia, serif; font-size: 14px; font-weight: 600; color: %s;", earthenEmailFg(emailCtx)) }>
|
||||
{ emailCtx.SiteSettings.SiteName }
|
||||
</p>
|
||||
<p style={ fmt.Sprintf("margin: 0 0 6px; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)) }>
|
||||
Registered charity. We respect your inbox.
|
||||
</p>
|
||||
if emailCtx.SiteSettings.SiteURL != "" {
|
||||
<p style={ fmt.Sprintf("margin: 0 0 12px; font-size: 12px; color: %s;", earthenEmailMutedFg(emailCtx)) }>
|
||||
<a href={ templ.SafeURL(emailCtx.SiteSettings.SiteURL) } style={ fmt.Sprintf("color: %s; text-decoration: none; border-bottom: 1px dotted %s;", earthenEmailPrimary(emailCtx), earthenEmailPrimary(emailCtx)) }>
|
||||
{ emailCtx.SiteSettings.SiteURL }
|
||||
</a>
|
||||
</p>
|
||||
}
|
||||
if emailCtx.UnsubscribeURL != "" {
|
||||
<p style={ fmt.Sprintf("margin: 0; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)) }>
|
||||
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style={ fmt.Sprintf("color: %s; text-decoration: underline;", earthenEmailMutedFg(emailCtx)) }>
|
||||
Unsubscribe
|
||||
</a>
|
||||
</p>
|
||||
} else {
|
||||
<p style={ fmt.Sprintf("margin: 0; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)) }>
|
||||
<a href="#" style={ fmt.Sprintf("color: %s; text-decoration: underline;", earthenEmailMutedFg(emailCtx)) }>
|
||||
Unsubscribe
|
||||
</a>
|
||||
</p>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
// Email colour helpers — fall back to cream/moss defaults when EmailColors are empty.
|
||||
func earthenEmailBg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Background != "" {
|
||||
return emailCtx.Colors.Background
|
||||
}
|
||||
return "#F6F1E6"
|
||||
}
|
||||
|
||||
func earthenEmailCard(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Card != "" {
|
||||
return emailCtx.Colors.Card
|
||||
}
|
||||
return "#FCF9F2"
|
||||
}
|
||||
|
||||
func earthenEmailFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Foreground != "" {
|
||||
return emailCtx.Colors.Foreground
|
||||
}
|
||||
return "#2D3A28"
|
||||
}
|
||||
|
||||
func earthenEmailPrimary(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Primary != "" {
|
||||
return emailCtx.Colors.Primary
|
||||
}
|
||||
return "#3A5A36"
|
||||
}
|
||||
|
||||
func earthenEmailPrimaryFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.PrimaryForeground != "" {
|
||||
return emailCtx.Colors.PrimaryForeground
|
||||
}
|
||||
return "#F6F1E6"
|
||||
}
|
||||
|
||||
func earthenEmailBorder(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Border != "" {
|
||||
return emailCtx.Colors.Border
|
||||
}
|
||||
return "#D6D1C2"
|
||||
}
|
||||
|
||||
func earthenEmailMuted(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Muted != "" {
|
||||
return emailCtx.Colors.Muted
|
||||
}
|
||||
return "#EFEBDF"
|
||||
}
|
||||
|
||||
func earthenEmailMutedFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.MutedForeground != "" {
|
||||
return emailCtx.Colors.MutedForeground
|
||||
}
|
||||
return "#6E7560"
|
||||
}
|
||||
470
email_wrapper_templ.go
Normal file
470
email_wrapper_templ.go
Normal file
@ -0,0 +1,470 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/templates"
|
||||
)
|
||||
|
||||
// earthenEmailTemplate renders the cream/moss email wrapper.
|
||||
func earthenEmailTemplate(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\"><!--[if mso]>\n\t\t\t<noscript>\n\t\t\t\t<xml>\n\t\t\t\t\t<o:OfficeDocumentSettings>\n\t\t\t\t\t\t<o:PixelsPerInch>96</o:PixelsPerInch>\n\t\t\t\t\t</o:OfficeDocumentSettings>\n\t\t\t\t</xml>\n\t\t\t</noscript>\n\t\t\t<![endif]--><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: 27, 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></head><body style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("background-color: %s; margin: 0; padding: 0; font-family: 'Spectral', Georgia, serif; color: %s;", earthenEmailBg(emailCtx), earthenEmailFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 29, Col: 179}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if emailCtx.PreviewText != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div style=\"display: none; max-height: 0; overflow: hidden; mso-hide: all;\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.PreviewText)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 32, Col: 27}
|
||||
}
|
||||
_, 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, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("background-color: %s;", earthenEmailBg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 35, Col: 156}
|
||||
}
|
||||
_, 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, 7, "\"><tr><td align=\"center\" style=\"padding: 32px 12px;\"><table role=\"presentation\" width=\"600\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("max-width: 600px; background-color: %s; border: 1px solid %s; border-radius: 12px; overflow: hidden;", earthenEmailCard(emailCtx), earthenEmailBorder(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 38, Col: 269}
|
||||
}
|
||||
_, 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, "\"><tr><td align=\"center\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("padding: 28px 32px; background-color: %s; color: %s;", earthenEmailPrimary(emailCtx), earthenEmailPrimaryFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 40, Col: 166}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if emailCtx.SiteSettings.LogoURL != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, 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: 42, Col: 50}
|
||||
}
|
||||
_, 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, 11, "\" alt=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, 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: 42, Col: 89}
|
||||
}
|
||||
_, 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, 12, "\" style=\"max-height: 44px; 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, 13, "<h1 style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0; font-family: 'Fraunces', 'Playfair Display', Georgia, serif; font-size: 26px; font-weight: 600; letter-spacing: -0.01em; color: %s;", earthenEmailPrimaryFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 44, Col: 212}
|
||||
}
|
||||
_, 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, 14, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, 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: 45, Col: 43}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</td></tr><tr><td style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("padding: 36px 40px; font-size: 16px; line-height: 1.7; color: %s; font-family: 'Spectral', Georgia, serif;", earthenEmailFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 51, Col: 167}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(body).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</td></tr><tr><td style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("padding: 24px 40px; background-color: %s; border-top: 1px solid %s;", earthenEmailMuted(emailCtx), earthenEmailBorder(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 56, Col: 161}
|
||||
}
|
||||
_, 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, 19, "\"><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tr><td align=\"center\"><p style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0 0 8px; font-family: 'Fraunces', 'Playfair Display', Georgia, serif; font-size: 14px; font-weight: 600; color: %s;", earthenEmailFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 60, Col: 187}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var15 string
|
||||
templ_7745c5c3_Var15, 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: 61, Col: 45}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</p><p style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0 0 6px; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 63, Col: 113}
|
||||
}
|
||||
_, 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, 22, "\">Registered charity. We respect your inbox.</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if emailCtx.SiteSettings.SiteURL != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<p style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var17 string
|
||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0 0 12px; font-size: 12px; color: %s;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 67, Col: 115}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\"><a href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var18 templ.SafeURL
|
||||
templ_7745c5c3_Var18, 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: 68, Col: 68}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var19 string
|
||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("color: %s; text-decoration: none; border-bottom: 1px dotted %s;", earthenEmailPrimary(emailCtx), earthenEmailPrimary(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 68, Col: 219}
|
||||
}
|
||||
_, 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, 26, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var20 string
|
||||
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteURL)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 69, Col: 46}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</a></p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if emailCtx.UnsubscribeURL != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<p style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var21 string
|
||||
templ_7745c5c3_Var21, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 74, Col: 108}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\"><a href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var22 templ.SafeURL
|
||||
templ_7745c5c3_Var22, 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: 75, Col: 62}
|
||||
}
|
||||
_, 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, 30, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var23 string
|
||||
templ_7745c5c3_Var23, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("color: %s; text-decoration: underline;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 75, Col: 157}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\">Unsubscribe</a></p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<p style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var24 string
|
||||
templ_7745c5c3_Var24, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("margin: 0; font-size: 11px; color: %s;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 80, Col: 108}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "\"><a href=\"#\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var25 string
|
||||
templ_7745c5c3_Var25, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("color: %s; text-decoration: underline;", earthenEmailMutedFg(emailCtx)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 81, Col: 118}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "\">Unsubscribe</a></p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</td></tr></table></td></tr></table></td></tr></table></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Email colour helpers — fall back to cream/moss defaults when EmailColors are empty.
|
||||
func earthenEmailBg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Background != "" {
|
||||
return emailCtx.Colors.Background
|
||||
}
|
||||
return "#F6F1E6"
|
||||
}
|
||||
|
||||
func earthenEmailCard(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Card != "" {
|
||||
return emailCtx.Colors.Card
|
||||
}
|
||||
return "#FCF9F2"
|
||||
}
|
||||
|
||||
func earthenEmailFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Foreground != "" {
|
||||
return emailCtx.Colors.Foreground
|
||||
}
|
||||
return "#2D3A28"
|
||||
}
|
||||
|
||||
func earthenEmailPrimary(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Primary != "" {
|
||||
return emailCtx.Colors.Primary
|
||||
}
|
||||
return "#3A5A36"
|
||||
}
|
||||
|
||||
func earthenEmailPrimaryFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.PrimaryForeground != "" {
|
||||
return emailCtx.Colors.PrimaryForeground
|
||||
}
|
||||
return "#F6F1E6"
|
||||
}
|
||||
|
||||
func earthenEmailBorder(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Border != "" {
|
||||
return emailCtx.Colors.Border
|
||||
}
|
||||
return "#D6D1C2"
|
||||
}
|
||||
|
||||
func earthenEmailMuted(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.Muted != "" {
|
||||
return emailCtx.Colors.Muted
|
||||
}
|
||||
return "#EFEBDF"
|
||||
}
|
||||
|
||||
func earthenEmailMutedFg(emailCtx templates.EmailContext) string {
|
||||
if emailCtx.Colors.MutedForeground != "" {
|
||||
return emailCtx.Colors.MutedForeground
|
||||
}
|
||||
return "#6E7560"
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
64
embed.go
Normal file
64
embed.go
Normal file
@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/plugin"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assetsFS embed.FS
|
||||
|
||||
//go:embed schemas/*
|
||||
var schemasFS embed.FS
|
||||
|
||||
//go:embed presets.json
|
||||
var presetsData []byte
|
||||
|
||||
//go:embed fonts.json
|
||||
var fontsData []byte
|
||||
|
||||
//go:embed plugin.mod
|
||||
var pluginModBytes []byte
|
||||
|
||||
// Assets returns the embedded assets filesystem.
|
||||
func Assets() fs.FS {
|
||||
sub, _ := fs.Sub(assetsFS, "assets")
|
||||
return sub
|
||||
}
|
||||
|
||||
// Schemas returns the embedded schemas filesystem.
|
||||
func Schemas() fs.FS {
|
||||
sub, _ := fs.Sub(schemasFS, "schemas")
|
||||
return sub
|
||||
}
|
||||
|
||||
// AssetsHandler returns an http.Handler that serves the embedded assets.
|
||||
func AssetsHandler() http.Handler {
|
||||
return http.FileServer(http.FS(Assets()))
|
||||
}
|
||||
|
||||
// ThemePresets returns the embedded theme presets JSON.
|
||||
func ThemePresets() []byte {
|
||||
return presetsData
|
||||
}
|
||||
|
||||
// BundledFonts returns the embedded fonts manifest JSON.
|
||||
func BundledFonts() []byte {
|
||||
return fontsData
|
||||
}
|
||||
|
||||
// ThemeCSSManifest returns the theme's custom CSS utilities injected into
|
||||
// the host Tailwind input so paper-grain, drop-cap, and botanical rules
|
||||
// survive the global purge.
|
||||
func ThemeCSSManifest() *plugin.CSSManifest {
|
||||
css, err := assetsFS.ReadFile("assets/css/earthen.css")
|
||||
if err != nil {
|
||||
return &plugin.CSSManifest{}
|
||||
}
|
||||
return &plugin.CSSManifest{
|
||||
InputCSSAppend: string(css),
|
||||
}
|
||||
}
|
||||
44
field_note.go
Normal file
44
field_note.go
Normal file
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// FieldNoteBlockMeta defines metadata for the field note block.
|
||||
var FieldNoteBlockMeta = blocks.BlockMeta{
|
||||
Key: "field_note",
|
||||
Title: "Field Note",
|
||||
Description: "Article-style dispatch from the field with byline and location",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryContent,
|
||||
}
|
||||
|
||||
// FieldNoteBlock renders the field note block.
|
||||
// Content shape: {author, location, dateline, body, image}
|
||||
func FieldNoteBlock(ctx context.Context, content map[string]any) string {
|
||||
data := FieldNoteData{
|
||||
Author: getString(content, "author"),
|
||||
Location: getString(content, "location"),
|
||||
Dateline: getString(content, "dateline"),
|
||||
Body: getString(content, "body"),
|
||||
Image: getString(content, "image"),
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = fieldNoteComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FieldNoteData contains data for the field note component.
|
||||
type FieldNoteData struct {
|
||||
Author string
|
||||
Location string
|
||||
Dateline string
|
||||
Body string
|
||||
Image string
|
||||
Empty bool
|
||||
}
|
||||
52
field_note.templ
Normal file
52
field_note.templ
Normal file
@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
// fieldNoteComponent renders an article-style dispatch from the field.
|
||||
templ fieldNoteComponent(data FieldNoteData) {
|
||||
<article
|
||||
data-block="earthen:field_note"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-field-note earthen-paper-frame mx-auto my-12 max-w-3xl p-8 rounded-lg"
|
||||
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border));"
|
||||
>
|
||||
<header class="mb-6">
|
||||
<div
|
||||
class="earthen-byline flex flex-wrap gap-x-3 gap-y-1 uppercase tracking-wider text-xs mb-2"
|
||||
style="color: hsl(var(--muted-foreground));"
|
||||
>
|
||||
if data.Author != "" {
|
||||
<span class="earthen-byline-author">By { data.Author }</span>
|
||||
}
|
||||
if data.Location != "" {
|
||||
<span class="earthen-byline-location">{ data.Location }</span>
|
||||
}
|
||||
if data.Dateline != "" {
|
||||
<span class="earthen-byline-date">{ data.Dateline }</span>
|
||||
}
|
||||
</div>
|
||||
<div class="botanical-rule" aria-hidden="true">
|
||||
@botanicalGlyph("seed", 28)
|
||||
</div>
|
||||
</header>
|
||||
if data.Image != "" {
|
||||
<figure class="my-6 earthen-paper-frame-inner">
|
||||
<img
|
||||
src={ resolveMedia(data.Image) }
|
||||
alt=""
|
||||
class="w-full h-auto rounded"
|
||||
/>
|
||||
</figure>
|
||||
}
|
||||
if data.Body != "" {
|
||||
<div
|
||||
class="earthen-body drop-cap prose-base"
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
@templ.Raw(data.Body)
|
||||
</div>
|
||||
} else {
|
||||
<p class="earthen-empty" style="color: hsl(var(--muted-foreground));">
|
||||
No dispatch yet — add a body to share what you saw in the field.
|
||||
</p>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
175
field_note_templ.go
Normal file
175
field_note_templ.go
Normal file
@ -0,0 +1,175 @@
|
||||
// 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"
|
||||
|
||||
// fieldNoteComponent renders an article-style dispatch from the field.
|
||||
func fieldNoteComponent(data FieldNoteData) 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 data-block=\"earthen:field_note\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-field-note earthen-paper-frame mx-auto my-12 max-w-3xl p-8 rounded-lg\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border));\"><header class=\"mb-6\"><div class=\"earthen-byline flex flex-wrap gap-x-3 gap-y-1 uppercase tracking-wider text-xs mb-2\" style=\"color: hsl(var(--muted-foreground));\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Author != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"earthen-byline-author\">By ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Author)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `field_note.templ`, Line: 17, Col: 57}
|
||||
}
|
||||
_, 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, 5, "</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Location != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<span class=\"earthen-byline-location\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Location)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `field_note.templ`, Line: 20, Col: 58}
|
||||
}
|
||||
_, 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, 7, "</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Dateline != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<span class=\"earthen-byline-date\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Dateline)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `field_note.templ`, Line: 23, 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, 9, "</span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"botanical-rule\" aria-hidden=\"true\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = botanicalGlyph("seed", 28).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</div></header>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Image != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<figure class=\"my-6 earthen-paper-frame-inner\"><img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(resolveMedia(data.Image))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `field_note.templ`, Line: 33, Col: 35}
|
||||
}
|
||||
_, 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, 13, "\" alt=\"\" class=\"w-full h-auto rounded\"></figure>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Body != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<div class=\"earthen-body drop-cap prose-base\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `field_note.templ`, Line: 42, Col: 105}
|
||||
}
|
||||
_, 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, 15, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(data.Body).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<p class=\"earthen-empty\" style=\"color: hsl(var(--muted-foreground));\">No dispatch yet — add a body to share what you saw in the field.</p>")
|
||||
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
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
1
fonts.json
Normal file
1
fonts.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
69
footer.go
Normal file
69
footer.go
Normal file
@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// FooterBlockMeta defines metadata for the earthen footer block.
|
||||
var FooterBlockMeta = blocks.BlockMeta{
|
||||
Key: "footer",
|
||||
Title: "Site Footer",
|
||||
Description: "Cream-on-moss footer with optional newsletter and column links",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryNavigation,
|
||||
}
|
||||
|
||||
// FooterBlock renders the earthen footer block.
|
||||
// Content shape: {showNewsletter, tagline, columns:[{title,links:[{text,url}]}]}
|
||||
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 {
|
||||
links = append(links, FooterLink{
|
||||
Text: getString(l, "text"),
|
||||
URL: getString(l, "url"),
|
||||
})
|
||||
}
|
||||
columns = append(columns, FooterColumn{
|
||||
Title: getString(c, "title"),
|
||||
Links: links,
|
||||
})
|
||||
}
|
||||
|
||||
data := FooterData{
|
||||
ShowNewsletter: getBool(content, "showNewsletter", false),
|
||||
Tagline: getString(content, "tagline"),
|
||||
Columns: columns,
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = footerComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FooterData contains data for the footer component.
|
||||
type FooterData struct {
|
||||
ShowNewsletter bool
|
||||
Tagline string
|
||||
Columns []FooterColumn
|
||||
Empty bool
|
||||
}
|
||||
|
||||
// FooterColumn is a single link column in the footer.
|
||||
type FooterColumn struct {
|
||||
Title string
|
||||
Links []FooterLink
|
||||
}
|
||||
|
||||
// FooterLink is a single link in a footer column.
|
||||
type FooterLink struct {
|
||||
Text string
|
||||
URL string
|
||||
}
|
||||
104
footer.templ
Normal file
104
footer.templ
Normal file
@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
// footerComponent renders the cream-on-moss footer with optional newsletter and link columns.
|
||||
templ footerComponent(data FooterData) {
|
||||
<div
|
||||
data-block="earthen:footer"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-footer w-full"
|
||||
style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"
|
||||
>
|
||||
<div class="max-w-6xl mx-auto px-6 py-16">
|
||||
<div class="botanical-rule flex items-center gap-4 mb-10" aria-hidden="true">
|
||||
<span class="flex-1 h-px" style="background-color: hsl(var(--primary-foreground) / 0.3);"></span>
|
||||
@botanicalGlyph("fern", 32)
|
||||
<span class="flex-1 h-px" style="background-color: hsl(var(--primary-foreground) / 0.3);"></span>
|
||||
</div>
|
||||
if data.Tagline != "" {
|
||||
<p
|
||||
class="earthen-display text-2xl md:text-3xl text-center mb-10"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif);" }
|
||||
>
|
||||
{ data.Tagline }
|
||||
</p>
|
||||
}
|
||||
if data.ShowNewsletter {
|
||||
<form class="max-w-xl mx-auto mb-12 flex flex-col sm:flex-row gap-3">
|
||||
<label class="sr-only" for="earthen-footer-email">Email address</label>
|
||||
<input
|
||||
id="earthen-footer-email"
|
||||
type="email"
|
||||
placeholder="you@example.org"
|
||||
class="flex-1 rounded-lg px-4 py-3 text-base"
|
||||
style="background-color: hsl(var(--primary-foreground) / 0.1); color: hsl(var(--primary-foreground)); border: 1px solid hsl(var(--primary-foreground) / 0.3);"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded-lg px-6 py-3 font-semibold"
|
||||
style="background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground));"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
if len(data.Columns) > 0 {
|
||||
<div class={ "grid gap-8 mb-10", footerGridCols(len(data.Columns)) }>
|
||||
for _, col := range data.Columns {
|
||||
<div>
|
||||
if col.Title != "" {
|
||||
<h4
|
||||
class="earthen-display text-lg mb-4"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif);" }
|
||||
>
|
||||
{ col.Title }
|
||||
</h4>
|
||||
}
|
||||
if len(col.Links) > 0 {
|
||||
<ul class="space-y-2">
|
||||
for _, link := range col.Links {
|
||||
<li>
|
||||
<a
|
||||
href={ templ.SafeURL(footerLinkURL(link.URL)) }
|
||||
class="earthen-footer-link transition-colors"
|
||||
style="color: hsl(var(--primary-foreground) / 0.85);"
|
||||
>
|
||||
{ link.Text }
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div
|
||||
class="text-center text-sm pt-6"
|
||||
style="border-top: 1px solid hsl(var(--primary-foreground) / 0.2); color: hsl(var(--primary-foreground) / 0.7);"
|
||||
>
|
||||
<span>Rooted in place. Made with care.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// footerGridCols returns a responsive grid class for the footer column count.
|
||||
func footerGridCols(count int) string {
|
||||
switch count {
|
||||
case 1:
|
||||
return "grid-cols-1"
|
||||
case 2:
|
||||
return "grid-cols-1 sm:grid-cols-2"
|
||||
case 3:
|
||||
return "grid-cols-1 sm:grid-cols-3"
|
||||
default:
|
||||
return "grid-cols-2 lg:grid-cols-4"
|
||||
}
|
||||
}
|
||||
|
||||
func footerLinkURL(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
234
footer_templ.go
Normal file
234
footer_templ.go
Normal file
@ -0,0 +1,234 @@
|
||||
// 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 cream-on-moss footer with optional newsletter and link columns.
|
||||
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 data-block=\"earthen:footer\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-footer w-full\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));\"><div class=\"max-w-6xl mx-auto px-6 py-16\"><div class=\"botanical-rule flex items-center gap-4 mb-10\" aria-hidden=\"true\"><span class=\"flex-1 h-px\" style=\"background-color: hsl(var(--primary-foreground) / 0.3);\"></span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = botanicalGlyph("fern", 32).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"flex-1 h-px\" style=\"background-color: hsl(var(--primary-foreground) / 0.3);\"></span></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Tagline != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<p class=\"earthen-display text-2xl md:text-3xl text-center mb-10\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif);")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 20, Col: 100}
|
||||
}
|
||||
_, 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, 6, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Tagline)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 22, Col: 19}
|
||||
}
|
||||
_, 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, 7, "</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.ShowNewsletter {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<form class=\"max-w-xl mx-auto mb-12 flex flex-col sm:flex-row gap-3\"><label class=\"sr-only\" for=\"earthen-footer-email\">Email address</label> <input id=\"earthen-footer-email\" type=\"email\" placeholder=\"you@example.org\" class=\"flex-1 rounded-lg px-4 py-3 text-base\" style=\"background-color: hsl(var(--primary-foreground) / 0.1); color: hsl(var(--primary-foreground)); border: 1px solid hsl(var(--primary-foreground) / 0.3);\"> <button type=\"submit\" class=\"rounded-lg px-6 py-3 font-semibold\" style=\"background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground));\">Subscribe</button></form>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if len(data.Columns) > 0 {
|
||||
var templ_7745c5c3_Var4 = []any{"grid gap-8 mb-10", footerGridCols(len(data.Columns))}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var4).String())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 1, Col: 0}
|
||||
}
|
||||
_, 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, 10, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, col := range data.Columns {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if col.Title != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<h4 class=\"earthen-display text-lg mb-4\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif);")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 51, Col: 104}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(col.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 53, Col: 20}
|
||||
}
|
||||
_, 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, "</h4>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if len(col.Links) > 0 {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<ul class=\"space-y-2\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, link := range col.Links {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<li><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(footerLinkURL(link.URL)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 61, Col: 57}
|
||||
}
|
||||
_, 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, "\" class=\"earthen-footer-link transition-colors\" style=\"color: hsl(var(--primary-foreground) / 0.85);\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 65, Col: 23}
|
||||
}
|
||||
_, 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></li>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</ul>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<div class=\"text-center text-sm pt-6\" style=\"border-top: 1px solid hsl(var(--primary-foreground) / 0.2); color: hsl(var(--primary-foreground) / 0.7);\"><span>Rooted in place. Made with care.</span></div></div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// footerGridCols returns a responsive grid class for the footer column count.
|
||||
func footerGridCols(count int) string {
|
||||
switch count {
|
||||
case 1:
|
||||
return "grid-cols-1"
|
||||
case 2:
|
||||
return "grid-cols-1 sm:grid-cols-2"
|
||||
case 3:
|
||||
return "grid-cols-1 sm:grid-cols-3"
|
||||
default:
|
||||
return "grid-cols-2 lg:grid-cols-4"
|
||||
}
|
||||
}
|
||||
|
||||
func footerLinkURL(url string) string {
|
||||
if url == "" {
|
||||
return "#"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
20
go.mod
Normal file
20
go.mod
Normal file
@ -0,0 +1,20 @@
|
||||
module git.dev.alexdunmow.com/block/themes/earthen
|
||||
|
||||
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=
|
||||
40
heading_override.go
Normal file
40
heading_override.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// EarthenHeadingBlock renders a heading with Earthen styling.
|
||||
// Content expects: {"text": "Heading text", "level": 1-6, "textClass": "optional"}
|
||||
func EarthenHeadingBlock(ctx context.Context, content map[string]any) string {
|
||||
text := getString(content, "text")
|
||||
textClass := getString(content, "textClass")
|
||||
level := parseHeadingLevel(content)
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = earthenHeadingComponent(level, text, textClass).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// parseHeadingLevel parses the level from content, defaulting to 2.
|
||||
func parseHeadingLevel(content map[string]any) int {
|
||||
if level, ok := content["level"].(float64); ok {
|
||||
l := int(level)
|
||||
if l >= 1 && l <= 6 {
|
||||
return l
|
||||
}
|
||||
}
|
||||
if level, ok := content["level"].(int); ok {
|
||||
if level >= 1 && level <= 6 {
|
||||
return level
|
||||
}
|
||||
}
|
||||
if level, ok := content["level"].(string); ok {
|
||||
if l, err := strconv.Atoi(level); err == nil && l >= 1 && l <= 6 {
|
||||
return l
|
||||
}
|
||||
}
|
||||
return 2
|
||||
}
|
||||
76
heading_override.templ
Normal file
76
heading_override.templ
Normal file
@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
// earthenHeadingBaseClass returns base classes for each heading level.
|
||||
func earthenHeadingBaseClass(level int) string {
|
||||
switch level {
|
||||
case 1:
|
||||
return "earthen-h1 text-5xl md:text-6xl font-semibold tracking-tight leading-tight"
|
||||
case 2:
|
||||
return "earthen-h2 text-3xl md:text-4xl font-semibold leading-snug crayon-underline"
|
||||
case 3:
|
||||
return "earthen-h3 text-2xl md:text-3xl font-semibold leading-snug"
|
||||
case 4:
|
||||
return "earthen-h4 text-xl md:text-2xl font-semibold"
|
||||
case 5:
|
||||
return "earthen-h5 text-lg font-semibold"
|
||||
case 6:
|
||||
return "earthen-h6 text-base font-semibold uppercase tracking-wider"
|
||||
default:
|
||||
return "earthen-h2 text-3xl md:text-4xl font-semibold"
|
||||
}
|
||||
}
|
||||
|
||||
// earthenHeadingComponent renders a heading with Earthen styling.
|
||||
templ earthenHeadingComponent(level int, text, textClass string) {
|
||||
switch level {
|
||||
case 1:
|
||||
<h1
|
||||
class={ earthenHeadingBaseClass(1), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ text }
|
||||
</h1>
|
||||
case 2:
|
||||
<h2
|
||||
class={ earthenHeadingBaseClass(2), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ text }
|
||||
</h2>
|
||||
case 3:
|
||||
<h3
|
||||
class={ earthenHeadingBaseClass(3), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
{ text }
|
||||
</h3>
|
||||
case 4:
|
||||
<h4
|
||||
class={ earthenHeadingBaseClass(4), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
{ text }
|
||||
</h4>
|
||||
case 5:
|
||||
<h5
|
||||
class={ earthenHeadingBaseClass(5), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
{ text }
|
||||
</h5>
|
||||
case 6:
|
||||
<h6
|
||||
class={ earthenHeadingBaseClass(6), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--muted-foreground));" }
|
||||
>
|
||||
{ text }
|
||||
</h6>
|
||||
default:
|
||||
<h2
|
||||
class={ earthenHeadingBaseClass(2), textClass }
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ text }
|
||||
</h2>
|
||||
}
|
||||
}
|
||||
402
heading_override_templ.go
Normal file
402
heading_override_templ.go
Normal file
@ -0,0 +1,402 @@
|
||||
// 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"
|
||||
|
||||
// earthenHeadingBaseClass returns base classes for each heading level.
|
||||
func earthenHeadingBaseClass(level int) string {
|
||||
switch level {
|
||||
case 1:
|
||||
return "earthen-h1 text-5xl md:text-6xl font-semibold tracking-tight leading-tight"
|
||||
case 2:
|
||||
return "earthen-h2 text-3xl md:text-4xl font-semibold leading-snug crayon-underline"
|
||||
case 3:
|
||||
return "earthen-h3 text-2xl md:text-3xl font-semibold leading-snug"
|
||||
case 4:
|
||||
return "earthen-h4 text-xl md:text-2xl font-semibold"
|
||||
case 5:
|
||||
return "earthen-h5 text-lg font-semibold"
|
||||
case 6:
|
||||
return "earthen-h6 text-base font-semibold uppercase tracking-wider"
|
||||
default:
|
||||
return "earthen-h2 text-3xl md:text-4xl font-semibold"
|
||||
}
|
||||
}
|
||||
|
||||
// earthenHeadingComponent renders a heading with Earthen styling.
|
||||
func earthenHeadingComponent(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{earthenHeadingBaseClass(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=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 29, Col: 127}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 31, Col: 10}
|
||||
}
|
||||
_, 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, 4, "</h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case 2:
|
||||
var templ_7745c5c3_Var6 = []any{earthenHeadingBaseClass(2), textClass}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<h2 class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var6).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_Var7)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 36, Col: 127}
|
||||
}
|
||||
_, 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, 7, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 38, Col: 10}
|
||||
}
|
||||
_, 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, 8, "</h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case 3:
|
||||
var templ_7745c5c3_Var10 = []any{earthenHeadingBaseClass(3), textClass}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<h3 class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var10).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_Var11)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 43, Col: 130}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
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: 45, 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, "</h3>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case 4:
|
||||
var templ_7745c5c3_Var14 = []any{earthenHeadingBaseClass(4), 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, "<h4 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=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 50, Col: 130}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var17 string
|
||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 52, Col: 10}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</h4>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case 5:
|
||||
var templ_7745c5c3_Var18 = []any{earthenHeadingBaseClass(5), textClass}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var18...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<h5 class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var19 string
|
||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var18).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_Var19)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var20 string
|
||||
templ_7745c5c3_Var20, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 57, Col: 130}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var21 string
|
||||
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 59, Col: 10}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</h5>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case 6:
|
||||
var templ_7745c5c3_Var22 = []any{earthenHeadingBaseClass(6), textClass}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var22...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<h6 class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var23 string
|
||||
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var22).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_Var23)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var24 string
|
||||
templ_7745c5c3_Var24, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--muted-foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 64, Col: 136}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var25 string
|
||||
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 66, Col: 10}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</h6>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
default:
|
||||
var templ_7745c5c3_Var26 = []any{earthenHeadingBaseClass(2), textClass}
|
||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var26...)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<h2 class=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var27 string
|
||||
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var26).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_Var27)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var28 string
|
||||
templ_7745c5c3_Var28, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 71, Col: 127}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var29 string
|
||||
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 73, Col: 10}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
48
helpers.go
Normal file
48
helpers.go
Normal file
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
// getString extracts a string value from content map.
|
||||
func getString(content map[string]any, key string) string {
|
||||
if v, ok := content[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getBool extracts a bool value from content map. Defaults to defaultVal.
|
||||
func getBool(content map[string]any, key string, defaultVal bool) bool {
|
||||
if v, ok := content[key].(bool); ok {
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// getSlice extracts a slice of maps from content.
|
||||
func getSlice(content map[string]any, key string) []map[string]any {
|
||||
if v, ok := content[key].([]any); ok {
|
||||
result := make([]map[string]any, 0, len(v))
|
||||
for _, item := range v {
|
||||
if m, ok := item.(map[string]any); ok {
|
||||
result = append(result, m)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getNumberSlice extracts a slice of numbers from content. Handles JSON float64.
|
||||
func getNumberSlice(content map[string]any, key string) []float64 {
|
||||
if v, ok := content[key].([]any); ok {
|
||||
result := make([]float64, 0, len(v))
|
||||
for _, item := range v {
|
||||
switch n := item.(type) {
|
||||
case float64:
|
||||
result = append(result, n)
|
||||
case int:
|
||||
result = append(result, float64(n))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
21
image_override.go
Normal file
21
image_override.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
)
|
||||
|
||||
// EarthenImageBlock renders an image with paper-grain frame and optional caption.
|
||||
// Content expects: {"src":"…","alt":"…","caption":"…"}
|
||||
func EarthenImageBlock(ctx context.Context, content map[string]any) string {
|
||||
src := getString(content, "src")
|
||||
if src == "" {
|
||||
src = getString(content, "url")
|
||||
}
|
||||
alt := getString(content, "alt")
|
||||
caption := getString(content, "caption")
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = earthenImageComponent(src, alt, caption).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
35
image_override.templ
Normal file
35
image_override.templ
Normal file
@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
// earthenImageComponent renders an image inside a paper-grain frame, with an optional handwritten caption.
|
||||
templ earthenImageComponent(src, alt, caption string) {
|
||||
<figure class="earthen-image my-8 mx-auto" style="max-width: 100%;">
|
||||
if src != "" {
|
||||
<div
|
||||
class="earthen-paper-frame-inner rounded-lg overflow-hidden"
|
||||
style="border: 1px solid hsl(var(--border)); padding: 6px; background-color: hsl(var(--card));"
|
||||
>
|
||||
<img
|
||||
src={ resolveMedia(src) }
|
||||
alt={ alt }
|
||||
class="w-full h-auto rounded-md"
|
||||
/>
|
||||
</div>
|
||||
} else {
|
||||
<div
|
||||
data-empty="true"
|
||||
class="earthen-image-empty w-full h-48 rounded-lg flex items-center justify-center"
|
||||
style="background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground)); border: 1.5px dashed hsl(var(--border));"
|
||||
>
|
||||
<span class="text-sm">Choose an image to display here</span>
|
||||
</div>
|
||||
}
|
||||
if caption != "" {
|
||||
<figcaption
|
||||
class="earthen-caption text-center text-sm mt-3"
|
||||
style="color: hsl(var(--muted-foreground)); font-style: italic;"
|
||||
>
|
||||
{ caption }
|
||||
</figcaption>
|
||||
}
|
||||
</figure>
|
||||
}
|
||||
101
image_override_templ.go
Normal file
101
image_override_templ.go
Normal file
@ -0,0 +1,101 @@
|
||||
// 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"
|
||||
|
||||
// earthenImageComponent renders an image inside a paper-grain frame, with an optional handwritten caption.
|
||||
func earthenImageComponent(src, alt, caption string) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_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, "<figure class=\"earthen-image my-8 mx-auto\" style=\"max-width: 100%;\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if src != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"earthen-paper-frame-inner rounded-lg overflow-hidden\" style=\"border: 1px solid hsl(var(--border)); padding: 6px; background-color: hsl(var(--card));\"><img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(resolveMedia(src))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 12, Col: 28}
|
||||
}
|
||||
_, 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, 3, "\" alt=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(alt)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 13, Col: 14}
|
||||
}
|
||||
_, 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, 4, "\" class=\"w-full h-auto rounded-md\"></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div data-empty=\"true\" class=\"earthen-image-empty w-full h-48 rounded-lg flex items-center justify-center\" style=\"background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground)); border: 1.5px dashed hsl(var(--border));\"><span class=\"text-sm\">Choose an image to display here</span></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if caption != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<figcaption class=\"earthen-caption text-center text-sm mt-3\" style=\"color: hsl(var(--muted-foreground)); font-style: italic;\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(caption)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 31, Col: 13}
|
||||
}
|
||||
_, 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, "</figcaption>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</figure>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
58
impact_metrics.go
Normal file
58
impact_metrics.go
Normal file
@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// ImpactMetricsBlockMeta defines metadata for the impact metrics block.
|
||||
var ImpactMetricsBlockMeta = blocks.BlockMeta{
|
||||
Key: "impact_metrics",
|
||||
Title: "Impact Metrics",
|
||||
Description: "Numerical impact metrics with optional botanical illustration",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryContent,
|
||||
}
|
||||
|
||||
// ImpactMetricsBlock renders a row of impact metrics.
|
||||
// Content shape: {title, metrics:[{value,label,suffix}], illustration}
|
||||
func ImpactMetricsBlock(ctx context.Context, content map[string]any) string {
|
||||
rawMetrics := getSlice(content, "metrics")
|
||||
|
||||
items := make([]ImpactMetric, 0, len(rawMetrics))
|
||||
for _, m := range rawMetrics {
|
||||
items = append(items, ImpactMetric{
|
||||
Value: getString(m, "value"),
|
||||
Label: getString(m, "label"),
|
||||
Suffix: getString(m, "suffix"),
|
||||
})
|
||||
}
|
||||
|
||||
data := ImpactMetricsData{
|
||||
Title: getString(content, "title"),
|
||||
Illustration: getString(content, "illustration"),
|
||||
Metrics: items,
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = impactMetricsComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ImpactMetricsData contains data for the impact metrics component.
|
||||
type ImpactMetricsData struct {
|
||||
Title string
|
||||
Illustration string
|
||||
Metrics []ImpactMetric
|
||||
Empty bool
|
||||
}
|
||||
|
||||
// ImpactMetric is one numerical metric tile.
|
||||
type ImpactMetric struct {
|
||||
Value string
|
||||
Label string
|
||||
Suffix string
|
||||
}
|
||||
82
impact_metrics.templ
Normal file
82
impact_metrics.templ
Normal file
@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
// impactMetricsComponent renders a row of impact metrics with optional botanical illustration.
|
||||
templ impactMetricsComponent(data ImpactMetricsData) {
|
||||
<section
|
||||
data-block="earthen:impact_metrics"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-impact-metrics py-16 px-4"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground));"
|
||||
>
|
||||
<div class="max-w-5xl mx-auto">
|
||||
if data.Title != "" {
|
||||
<h2
|
||||
class="earthen-display text-3xl md:text-4xl text-center mb-12"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ data.Title }
|
||||
</h2>
|
||||
}
|
||||
if data.Illustration != "" {
|
||||
<div class="flex justify-center mb-8">
|
||||
<img src={ resolveMedia(data.Illustration) } alt="" class="max-h-40 object-contain"/>
|
||||
</div>
|
||||
} else if data.Title != "" || len(data.Metrics) > 0 {
|
||||
<div class="flex justify-center mb-8">
|
||||
@botanicalGlyph("fern", 64)
|
||||
</div>
|
||||
}
|
||||
if len(data.Metrics) > 0 {
|
||||
<div class={ "grid gap-8", metricGridCols(len(data.Metrics)) }>
|
||||
for _, m := range data.Metrics {
|
||||
<div class="text-center px-4">
|
||||
<div
|
||||
class="earthen-display text-5xl font-semibold mb-2"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--accent));" }
|
||||
>
|
||||
{ m.Value }{ m.Suffix }
|
||||
</div>
|
||||
<div
|
||||
class="earthen-body uppercase tracking-wider text-sm"
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--muted-foreground));" }
|
||||
>
|
||||
{ m.Label }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
<p
|
||||
class="text-center"
|
||||
style="color: hsl(var(--muted-foreground));"
|
||||
>
|
||||
Add impact metrics to bring this section to life.
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
// metricGridCols returns the responsive grid class for metric count.
|
||||
func metricGridCols(count int) string {
|
||||
switch count {
|
||||
case 1:
|
||||
return "grid-cols-1"
|
||||
case 2:
|
||||
return "grid-cols-1 sm:grid-cols-2"
|
||||
case 3:
|
||||
return "grid-cols-1 sm:grid-cols-3"
|
||||
default:
|
||||
return "grid-cols-2 lg:grid-cols-4"
|
||||
}
|
||||
}
|
||||
|
||||
// resolveMedia rewrites a media reference to its served URL. The wave-1
|
||||
// implementation passes the path through verbatim and is wired so admins
|
||||
// can drop in their own media adapter later without touching templates.
|
||||
func resolveMedia(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
return path
|
||||
}
|
||||
243
impact_metrics_templ.go
Normal file
243
impact_metrics_templ.go
Normal file
@ -0,0 +1,243 @@
|
||||
// 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"
|
||||
|
||||
// impactMetricsComponent renders a row of impact metrics with optional botanical illustration.
|
||||
func impactMetricsComponent(data ImpactMetricsData) 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 data-block=\"earthen:impact_metrics\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-impact-metrics py-16 px-4\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\"><div class=\"max-w-5xl mx-auto\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Title != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h2 class=\"earthen-display text-3xl md:text-4xl text-center mb-12\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 15, Col: 128}
|
||||
}
|
||||
_, 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, 5, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 17, Col: 17}
|
||||
}
|
||||
_, 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, "</h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if data.Illustration != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"flex justify-center mb-8\"><img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(resolveMedia(data.Illustration))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 22, Col: 47}
|
||||
}
|
||||
_, 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, "\" alt=\"\" class=\"max-h-40 object-contain\"></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else if data.Title != "" || len(data.Metrics) > 0 {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"flex justify-center mb-8\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = botanicalGlyph("fern", 64).Render(ctx, templ_7745c5c3_Buffer)
|
||||
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 len(data.Metrics) > 0 {
|
||||
var templ_7745c5c3_Var5 = []any{"grid gap-8", metricGridCols(len(data.Metrics))}
|
||||
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, 11, "<div 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: `impact_metrics.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, 12, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, m := range data.Metrics {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<div class=\"text-center px-4\"><div class=\"earthen-display text-5xl font-semibold mb-2\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--accent));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 35, Col: 130}
|
||||
}
|
||||
_, 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, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(m.Value)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 37, Col: 17}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(m.Suffix)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 37, Col: 29}
|
||||
}
|
||||
_, 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, 15, "</div><div class=\"earthen-body uppercase tracking-wider text-sm\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--muted-foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 41, Col: 115}
|
||||
}
|
||||
_, 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, 16, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `impact_metrics.templ`, Line: 43, Col: 17}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<p class=\"text-center\" style=\"color: hsl(var(--muted-foreground));\">Add impact metrics to bring this section to life.</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div></section>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// metricGridCols returns the responsive grid class for metric count.
|
||||
func metricGridCols(count int) string {
|
||||
switch count {
|
||||
case 1:
|
||||
return "grid-cols-1"
|
||||
case 2:
|
||||
return "grid-cols-1 sm:grid-cols-2"
|
||||
case 3:
|
||||
return "grid-cols-1 sm:grid-cols-3"
|
||||
default:
|
||||
return "grid-cols-2 lg:grid-cols-4"
|
||||
}
|
||||
}
|
||||
|
||||
// resolveMedia rewrites a media reference to its served URL. The wave-1
|
||||
// implementation passes the path through verbatim and is wired so admins
|
||||
// can drop in their own media adapter later without touching templates.
|
||||
func resolveMedia(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
55
partner_logos.go
Normal file
55
partner_logos.go
Normal file
@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
)
|
||||
|
||||
// PartnerLogosBlockMeta defines metadata for the partner logos block.
|
||||
var PartnerLogosBlockMeta = blocks.BlockMeta{
|
||||
Key: "partner_logos",
|
||||
Title: "Partner Logos",
|
||||
Description: "Grayscale partner logo grid with hover-to-color treatment",
|
||||
Source: "earthen",
|
||||
Category: blocks.CategoryContent,
|
||||
}
|
||||
|
||||
// PartnerLogosBlock renders the partner logos block.
|
||||
// Content shape: {title, logos:[{name,image,url}]}
|
||||
func PartnerLogosBlock(ctx context.Context, content map[string]any) string {
|
||||
rawLogos := getSlice(content, "logos")
|
||||
logos := make([]PartnerLogo, 0, len(rawLogos))
|
||||
for _, l := range rawLogos {
|
||||
logos = append(logos, PartnerLogo{
|
||||
Name: getString(l, "name"),
|
||||
Image: getString(l, "image"),
|
||||
URL: getString(l, "url"),
|
||||
})
|
||||
}
|
||||
|
||||
data := PartnerLogosData{
|
||||
Title: getString(content, "title"),
|
||||
Logos: logos,
|
||||
Empty: len(content) == 0,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = partnerLogosComponent(data).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// PartnerLogosData contains data for the partner logos component.
|
||||
type PartnerLogosData struct {
|
||||
Title string
|
||||
Logos []PartnerLogo
|
||||
Empty bool
|
||||
}
|
||||
|
||||
// PartnerLogo is a single partner row.
|
||||
type PartnerLogo struct {
|
||||
Name string
|
||||
Image string
|
||||
URL string
|
||||
}
|
||||
95
partner_logos.templ
Normal file
95
partner_logos.templ
Normal file
@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
// partnerLogosComponent renders a grayscale logo grid that restores colour on hover.
|
||||
templ partnerLogosComponent(data PartnerLogosData) {
|
||||
<section
|
||||
data-block="earthen:partner_logos"
|
||||
data-empty?={ data.Empty }
|
||||
class="earthen-partner-logos py-16 px-4"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground));"
|
||||
>
|
||||
<div class="max-w-5xl mx-auto">
|
||||
if data.Title != "" {
|
||||
<h2
|
||||
class="earthen-display text-2xl md:text-3xl text-center mb-10"
|
||||
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
|
||||
>
|
||||
{ data.Title }
|
||||
</h2>
|
||||
}
|
||||
if len(data.Logos) > 0 {
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-8 items-center">
|
||||
for _, logo := range data.Logos {
|
||||
<div class="earthen-partner-tile flex justify-center items-center">
|
||||
@partnerLogoTile(logo)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
<p class="text-center" style="color: hsl(var(--muted-foreground));">
|
||||
Add partner logos to fill this grid.
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
templ partnerLogoTile(logo PartnerLogo) {
|
||||
if logo.URL != "" {
|
||||
<a
|
||||
href={ templ.SafeURL(logo.URL) }
|
||||
class="earthen-partner-link block transition-colors"
|
||||
title={ logo.Name }
|
||||
aria-label={ logo.Name }
|
||||
>
|
||||
@partnerLogoImage(logo)
|
||||
</a>
|
||||
} else {
|
||||
<div class="earthen-partner-link block" title={ logo.Name } aria-label={ logo.Name }>
|
||||
@partnerLogoImage(logo)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ partnerLogoImage(logo PartnerLogo) {
|
||||
if logo.Image != "" {
|
||||
<img
|
||||
src={ resolveMedia(logo.Image) }
|
||||
alt={ logo.Name }
|
||||
class="earthen-partner-img max-h-12 object-contain w-full"
|
||||
/>
|
||||
} else {
|
||||
<div
|
||||
class="earthen-partner-fallback w-full h-12 flex items-center justify-center rounded"
|
||||
style="background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground));"
|
||||
>
|
||||
<span class="text-sm">{ partnerInitials(logo.Name) }</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
// partnerInitials returns up to two initials for an initials-only fallback tile.
|
||||
func partnerInitials(name string) string {
|
||||
if name == "" {
|
||||
return "?"
|
||||
}
|
||||
letters := []rune{}
|
||||
prevSpace := true
|
||||
for _, r := range name {
|
||||
if r == ' ' || r == '-' || r == '_' {
|
||||
prevSpace = true
|
||||
continue
|
||||
}
|
||||
if prevSpace {
|
||||
letters = append(letters, r)
|
||||
prevSpace = false
|
||||
if len(letters) >= 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(letters) == 0 {
|
||||
return "?"
|
||||
}
|
||||
return string(letters)
|
||||
}
|
||||
334
partner_logos_templ.go
Normal file
334
partner_logos_templ.go
Normal file
@ -0,0 +1,334 @@
|
||||
// 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"
|
||||
|
||||
// partnerLogosComponent renders a grayscale logo grid that restores colour on hover.
|
||||
func partnerLogosComponent(data PartnerLogosData) 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 data-block=\"earthen:partner_logos\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Empty {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " data-empty")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " class=\"earthen-partner-logos py-16 px-4\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\"><div class=\"max-w-5xl mx-auto\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.Title != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h2 class=\"earthen-display text-2xl md:text-3xl text-center mb-10\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 15, Col: 128}
|
||||
}
|
||||
_, 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, 5, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 17, Col: 17}
|
||||
}
|
||||
_, 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, "</h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if len(data.Logos) > 0 {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-8 items-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, logo := range data.Logos {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div class=\"earthen-partner-tile flex justify-center items-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = partnerLogoTile(logo).Render(ctx, templ_7745c5c3_Buffer)
|
||||
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
|
||||
}
|
||||
}
|
||||
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=\"text-center\" style=\"color: hsl(var(--muted-foreground));\">Add partner logos to fill this grid.</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 partnerLogoTile(logo PartnerLogo) 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.URL != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<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(logo.URL))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 40, Col: 33}
|
||||
}
|
||||
_, 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, 14, "\" class=\"earthen-partner-link block transition-colors\" title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 42, Col: 20}
|
||||
}
|
||||
_, 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, "\" aria-label=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 43, Col: 25}
|
||||
}
|
||||
_, 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, 16, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = partnerLogoImage(logo).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<div class=\"earthen-partner-link block\" title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 48, Col: 59}
|
||||
}
|
||||
_, 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, 19, "\" aria-label=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 48, Col: 84}
|
||||
}
|
||||
_, 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, 20, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = partnerLogoImage(logo).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func partnerLogoImage(logo PartnerLogo) 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_Var10 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var10 == nil {
|
||||
templ_7745c5c3_Var10 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
if logo.Image != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<img src=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(resolveMedia(logo.Image))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 57, Col: 33}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" alt=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(logo.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 58, Col: 18}
|
||||
}
|
||||
_, 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, 24, "\" class=\"earthen-partner-img max-h-12 object-contain w-full\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<div class=\"earthen-partner-fallback w-full h-12 flex items-center justify-center rounded\" style=\"background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground));\"><span class=\"text-sm\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(partnerInitials(logo.Name))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `partner_logos.templ`, Line: 66, Col: 53}
|
||||
}
|
||||
_, 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, 26, "</span></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// partnerInitials returns up to two initials for an initials-only fallback tile.
|
||||
func partnerInitials(name string) string {
|
||||
if name == "" {
|
||||
return "?"
|
||||
}
|
||||
letters := []rune{}
|
||||
prevSpace := true
|
||||
for _, r := range name {
|
||||
if r == ' ' || r == '-' || r == '_' {
|
||||
prevSpace = true
|
||||
continue
|
||||
}
|
||||
if prevSpace {
|
||||
letters = append(letters, r)
|
||||
prevSpace = false
|
||||
if len(letters) >= 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(letters) == 0 {
|
||||
return "?"
|
||||
}
|
||||
return string(letters)
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
12
plugin.mod
Normal file
12
plugin.mod
Normal file
@ -0,0 +1,12 @@
|
||||
[plugin]
|
||||
name = "earthen"
|
||||
display_name = "Earthen"
|
||||
scope = "@themes"
|
||||
version = "0.1.0"
|
||||
description = "Botanical nonprofit theme in moss, clay, sage and cream — hand-illustrated motifs for cause-driven sites."
|
||||
kind = "theme"
|
||||
categories = ["templates"]
|
||||
tags = ["earth", "nonprofit", "sustainability", "outdoor", "farm", "cause", "botanical", "conservation", "ngo"]
|
||||
|
||||
[compatibility]
|
||||
block_core = ">=0.11.0 <0.12.0"
|
||||
110
presets.json
Normal file
110
presets.json
Normal file
@ -0,0 +1,110 @@
|
||||
[
|
||||
{
|
||||
"id": "mossbed",
|
||||
"name": "Mossbed",
|
||||
"description": "Cream paper, deep moss primary, terracotta accent — the canonical Earthen look.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "40 30% 96%",
|
||||
"foreground": "120 25% 14%",
|
||||
"card": "40 25% 98%",
|
||||
"cardForeground": "120 25% 14%",
|
||||
"popover": "40 25% 98%",
|
||||
"popoverForeground": "120 25% 14%",
|
||||
"primary": "120 28% 28%",
|
||||
"primaryForeground": "40 30% 96%",
|
||||
"secondary": "80 15% 88%",
|
||||
"secondaryForeground": "120 25% 18%",
|
||||
"muted": "40 18% 92%",
|
||||
"mutedForeground": "100 12% 38%",
|
||||
"accent": "18 55% 48%",
|
||||
"accentForeground": "40 30% 96%",
|
||||
"destructive": "8 70% 45%",
|
||||
"destructiveForeground": "40 30% 96%",
|
||||
"border": "90 12% 82%",
|
||||
"input": "90 12% 82%",
|
||||
"ring": "120 28% 28%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "120 18% 8%",
|
||||
"foreground": "40 25% 92%",
|
||||
"card": "120 18% 11%",
|
||||
"cardForeground": "40 25% 92%",
|
||||
"popover": "120 18% 11%",
|
||||
"popoverForeground": "40 25% 92%",
|
||||
"primary": "90 30% 60%",
|
||||
"primaryForeground": "120 18% 8%",
|
||||
"secondary": "120 15% 18%",
|
||||
"secondaryForeground": "40 25% 92%",
|
||||
"muted": "120 12% 15%",
|
||||
"mutedForeground": "90 12% 60%",
|
||||
"accent": "18 65% 58%",
|
||||
"accentForeground": "120 18% 8%",
|
||||
"destructive": "8 70% 50%",
|
||||
"destructiveForeground": "40 25% 92%",
|
||||
"border": "120 12% 22%",
|
||||
"input": "120 12% 22%",
|
||||
"ring": "90 30% 60%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "clay-field",
|
||||
"name": "Clay Field",
|
||||
"description": "Warm terracotta-led palette tuned for farm-stand and outdoor-brand sites.",
|
||||
"theme": {
|
||||
"mode": "light",
|
||||
"lightColors": {
|
||||
"background": "30 35% 95%",
|
||||
"foreground": "20 35% 16%",
|
||||
"card": "30 30% 98%",
|
||||
"cardForeground": "20 35% 16%",
|
||||
"popover": "30 30% 98%",
|
||||
"popoverForeground": "20 35% 16%",
|
||||
"primary": "18 60% 42%",
|
||||
"primaryForeground": "30 35% 95%",
|
||||
"secondary": "35 25% 88%",
|
||||
"secondaryForeground": "20 35% 16%",
|
||||
"muted": "30 20% 92%",
|
||||
"mutedForeground": "25 18% 38%",
|
||||
"accent": "100 22% 38%",
|
||||
"accentForeground": "30 35% 95%",
|
||||
"destructive": "8 70% 45%",
|
||||
"destructiveForeground": "30 35% 95%",
|
||||
"border": "30 18% 82%",
|
||||
"input": "30 18% 82%",
|
||||
"ring": "18 60% 42%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "wet-loam",
|
||||
"name": "Wet Loam",
|
||||
"description": "Deep night-soil tones for conservation orgs that need quiet authority.",
|
||||
"theme": {
|
||||
"mode": "dark",
|
||||
"darkColors": {
|
||||
"background": "90 20% 6%",
|
||||
"foreground": "60 20% 90%",
|
||||
"card": "90 20% 9%",
|
||||
"cardForeground": "60 20% 90%",
|
||||
"popover": "90 20% 9%",
|
||||
"popoverForeground": "60 20% 90%",
|
||||
"primary": "80 35% 55%",
|
||||
"primaryForeground": "90 20% 6%",
|
||||
"secondary": "90 15% 16%",
|
||||
"secondaryForeground": "60 20% 90%",
|
||||
"muted": "90 12% 13%",
|
||||
"mutedForeground": "80 10% 58%",
|
||||
"accent": "25 70% 55%",
|
||||
"accentForeground": "90 20% 6%",
|
||||
"destructive": "8 70% 50%",
|
||||
"destructiveForeground": "60 20% 90%",
|
||||
"border": "90 12% 20%",
|
||||
"input": "90 12% 20%",
|
||||
"ring": "80 35% 55%"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
180
register.go
Normal file
180
register.go
Normal file
@ -0,0 +1,180 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
|
||||
"git.dev.alexdunmow.com/block/core/blocks"
|
||||
"git.dev.alexdunmow.com/block/core/plugin"
|
||||
"git.dev.alexdunmow.com/block/core/templates"
|
||||
)
|
||||
|
||||
// wrap adapts a templ-returning render function to templates.TemplateFunc.
|
||||
// templ.Component already implements templates.HTMLComponent via Render.
|
||||
func wrap(f func(ctx context.Context, doc map[string]any) templ.Component) templates.TemplateFunc {
|
||||
return func(ctx context.Context, doc map[string]any) templates.HTMLComponent {
|
||||
return f(ctx, doc)
|
||||
}
|
||||
}
|
||||
|
||||
// Register is the plugin entry point that registers the Earthen system template,
|
||||
// four page templates, six theme blocks, five overrides, and the email wrapper.
|
||||
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
||||
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
|
||||
Key: "earthen",
|
||||
Title: "Earthen",
|
||||
Description: "Botanical nonprofit theme in moss, clay, sage and cream",
|
||||
})
|
||||
|
||||
if err := tr.RegisterPageTemplate("earthen", templates.PageTemplateMeta{
|
||||
Key: "default",
|
||||
Title: "Default",
|
||||
Description: "Standard nonprofit page with header, main and footer",
|
||||
Slots: []string{"header", "main", "footer"},
|
||||
}, wrap(RenderEarthenDefault)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tr.RegisterPageTemplate("earthen", templates.PageTemplateMeta{
|
||||
Key: "landing",
|
||||
Title: "Landing",
|
||||
Description: "Mission hero plus CTA bands for campaigns and donation drives",
|
||||
Slots: []string{"hero", "main", "cta", "footer"},
|
||||
}, wrap(RenderEarthenLanding)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tr.RegisterPageTemplate("earthen", templates.PageTemplateMeta{
|
||||
Key: "article",
|
||||
Title: "Article",
|
||||
Description: "Long-form storytelling with byline rail",
|
||||
Slots: []string{"header", "lede", "main", "aside", "footer"},
|
||||
}, wrap(RenderEarthenArticle)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tr.RegisterPageTemplate("earthen", templates.PageTemplateMeta{
|
||||
Key: "full-width",
|
||||
Title: "Full Width",
|
||||
Description: "Edge-to-edge imagery for reports and galleries",
|
||||
Slots: []string{"header", "main", "footer"},
|
||||
}, wrap(RenderEarthenFullWidth)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
br.Register(DonationCTABlockMeta, DonationCTABlock)
|
||||
br.Register(ImpactMetricsBlockMeta, ImpactMetricsBlock)
|
||||
br.Register(PartnerLogosBlockMeta, PartnerLogosBlock)
|
||||
br.Register(FieldNoteBlockMeta, FieldNoteBlock)
|
||||
br.Register(BotanicalDividerBlockMeta, BotanicalDividerBlock)
|
||||
br.Register(FooterBlockMeta, FooterBlock)
|
||||
|
||||
br.RegisterTemplateOverride("earthen", "heading", EarthenHeadingBlock)
|
||||
br.RegisterTemplateOverride("earthen", "text", EarthenTextBlock)
|
||||
br.RegisterTemplateOverride("earthen", "button", EarthenButtonBlock)
|
||||
br.RegisterTemplateOverride("earthen", "image", EarthenImageBlock)
|
||||
br.RegisterTemplateOverride("earthen", "card", EarthenCardBlock)
|
||||
|
||||
tr.RegisterEmailWrapper("earthen", EarthenEmailWrapper)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultMasterPages returns the default master pages that Earthen provisions
|
||||
// on first plugin load.
|
||||
func DefaultMasterPages() []plugin.MasterPageDefinition {
|
||||
return []plugin.MasterPageDefinition{
|
||||
{
|
||||
Key: "earthen:default-master",
|
||||
Title: "Earthen Default Master",
|
||||
PageTemplates: []string{"default", "article"},
|
||||
Blocks: []plugin.MasterPageBlock{
|
||||
{
|
||||
BlockKey: "navbar",
|
||||
Title: "Main Navigation",
|
||||
Content: map[string]any{"menuName": "main"},
|
||||
Slot: "header",
|
||||
SortOrder: 0,
|
||||
},
|
||||
{
|
||||
BlockKey: "slot",
|
||||
Title: "Main Content",
|
||||
Content: map[string]any{"slotName": "main"},
|
||||
Slot: "main",
|
||||
SortOrder: 0,
|
||||
},
|
||||
{
|
||||
BlockKey: "earthen:donation_cta",
|
||||
Title: "Donation Rail",
|
||||
Content: map[string]any{
|
||||
"amounts": []any{25.0, 50.0, 100.0},
|
||||
"headline": "Plant the next acre.",
|
||||
},
|
||||
Slot: "main",
|
||||
SortOrder: 100,
|
||||
},
|
||||
{
|
||||
BlockKey: "earthen:footer",
|
||||
Title: "Site Footer",
|
||||
Content: map[string]any{
|
||||
"showNewsletter": true,
|
||||
"tagline": "Rooted in place.",
|
||||
},
|
||||
Slot: "footer",
|
||||
SortOrder: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "earthen:landing-master",
|
||||
Title: "Earthen Landing Master",
|
||||
PageTemplates: []string{"landing", "full-width"},
|
||||
Blocks: []plugin.MasterPageBlock{
|
||||
{
|
||||
BlockKey: "navbar",
|
||||
Title: "Main Navigation",
|
||||
Content: map[string]any{"menuName": "main"},
|
||||
Slot: "hero",
|
||||
SortOrder: 0,
|
||||
},
|
||||
{
|
||||
BlockKey: "slot",
|
||||
Title: "Hero Slot",
|
||||
Content: map[string]any{"slotName": "hero"},
|
||||
Slot: "hero",
|
||||
SortOrder: 10,
|
||||
},
|
||||
{
|
||||
BlockKey: "slot",
|
||||
Title: "Main Slot",
|
||||
Content: map[string]any{"slotName": "main"},
|
||||
Slot: "main",
|
||||
SortOrder: 0,
|
||||
},
|
||||
{
|
||||
BlockKey: "earthen:donation_cta",
|
||||
Title: "Donation CTA",
|
||||
Content: map[string]any{
|
||||
"amounts": []any{25.0, 50.0, 100.0, 250.0},
|
||||
},
|
||||
Slot: "cta",
|
||||
SortOrder: 0,
|
||||
},
|
||||
{
|
||||
BlockKey: "earthen:footer",
|
||||
Title: "Footer",
|
||||
Content: map[string]any{
|
||||
"showNewsletter": true,
|
||||
},
|
||||
Slot: "footer",
|
||||
SortOrder: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
25
registration.go
Normal file
25
registration.go
Normal file
@ -0,0 +1,25 @@
|
||||
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 Earthen theme.
|
||||
var Registration = plugin.PluginRegistration{
|
||||
Name: "earthen",
|
||||
Version: plugin.ParseModVersion(pluginModBytes),
|
||||
Register: func(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
||||
return Register(tr, br)
|
||||
},
|
||||
Assets: func() http.Handler { return AssetsHandler() },
|
||||
Schemas: func() fs.FS { return Schemas() },
|
||||
ThemePresets: func() []byte { return ThemePresets() },
|
||||
BundledFonts: func() []byte { return BundledFonts() },
|
||||
MasterPages: func() []plugin.MasterPageDefinition { return DefaultMasterPages() },
|
||||
CSSManifest: func() *plugin.CSSManifest { return ThemeCSSManifest() },
|
||||
}
|
||||
16
schemas/botanical_divider.schema.json
Normal file
16
schemas/botanical_divider.schema.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Botanical Divider",
|
||||
"description": "SVG section break with hand-illustrated botanical motif",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"motif": {
|
||||
"type": "string",
|
||||
"title": "Motif",
|
||||
"description": "Botanical illustration used for the divider",
|
||||
"x-editor": "select",
|
||||
"enum": ["fern", "root", "seed"],
|
||||
"default": "fern"
|
||||
}
|
||||
}
|
||||
}
|
||||
43
schemas/donation_cta.schema.json
Normal file
43
schemas/donation_cta.schema.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Donation CTA",
|
||||
"description": "Donation call-to-action with preset amount tiles and custom amount input",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headline": {
|
||||
"type": "string",
|
||||
"title": "Headline",
|
||||
"description": "Headline above the amount tiles",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"title": "Body",
|
||||
"description": "Supporting copy below the headline",
|
||||
"x-editor": "richtext"
|
||||
},
|
||||
"amounts": {
|
||||
"type": "array",
|
||||
"title": "Preset Amounts",
|
||||
"description": "Preset donation amounts shown as tiles",
|
||||
"x-editor": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
},
|
||||
"default": [25, 50, 100]
|
||||
},
|
||||
"buttonLabel": {
|
||||
"type": "string",
|
||||
"title": "Button Label",
|
||||
"description": "Label on the submit button",
|
||||
"x-editor": "text",
|
||||
"default": "Donate"
|
||||
},
|
||||
"processorUrl": {
|
||||
"type": "string",
|
||||
"title": "Processor URL",
|
||||
"description": "Donation processor URL (Stripe, Donorbox, etc.)",
|
||||
"x-editor": "link"
|
||||
}
|
||||
}
|
||||
}
|
||||
38
schemas/field_note.schema.json
Normal file
38
schemas/field_note.schema.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Field Note",
|
||||
"description": "Article-style dispatch from the field with byline and location",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string",
|
||||
"title": "Author",
|
||||
"description": "Author name",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"title": "Location",
|
||||
"description": "Location where the dispatch was filed",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"dateline": {
|
||||
"type": "string",
|
||||
"title": "Dateline",
|
||||
"description": "Date the dispatch was filed",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"title": "Body",
|
||||
"description": "Body copy of the field note",
|
||||
"x-editor": "richtext"
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Image",
|
||||
"description": "Lede image for the dispatch",
|
||||
"x-editor": "media"
|
||||
}
|
||||
}
|
||||
}
|
||||
57
schemas/footer.schema.json
Normal file
57
schemas/footer.schema.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Site Footer",
|
||||
"description": "Cream-on-moss footer with optional newsletter and botanical rule",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"showNewsletter": {
|
||||
"type": "boolean",
|
||||
"title": "Show Newsletter",
|
||||
"description": "Show the newsletter signup form",
|
||||
"x-editor": "select",
|
||||
"default": true
|
||||
},
|
||||
"tagline": {
|
||||
"type": "string",
|
||||
"title": "Tagline",
|
||||
"description": "Tagline above the columns",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"columns": {
|
||||
"type": "array",
|
||||
"title": "Columns",
|
||||
"description": "Footer link columns",
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Column Title",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"title": "Links",
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"title": "Text",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "URL",
|
||||
"x-editor": "link"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
schemas/impact_metrics.schema.json
Normal file
49
schemas/impact_metrics.schema.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Impact Metrics",
|
||||
"description": "Numerical impact metrics with optional illustration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Section Title",
|
||||
"description": "Heading above the metric tiles",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"metrics": {
|
||||
"type": "array",
|
||||
"title": "Metrics",
|
||||
"description": "List of impact metrics",
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string",
|
||||
"title": "Value",
|
||||
"description": "Numeric value (e.g. '12,000')",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"title": "Label",
|
||||
"description": "Description of the metric",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"suffix": {
|
||||
"type": "string",
|
||||
"title": "Suffix",
|
||||
"description": "Optional suffix (e.g. '+', '%')",
|
||||
"x-editor": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"illustration": {
|
||||
"type": "string",
|
||||
"title": "Illustration",
|
||||
"description": "Optional botanical illustration shown alongside metrics",
|
||||
"x-editor": "media"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
schemas/partner_logos.schema.json
Normal file
40
schemas/partner_logos.schema.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Partner Logos",
|
||||
"description": "Grayscale partner logo grid with hover-to-color treatment",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Section Title",
|
||||
"description": "Heading above the logo grid",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"logos": {
|
||||
"type": "array",
|
||||
"title": "Logos",
|
||||
"description": "Partner logos",
|
||||
"x-editor": "collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Partner Name",
|
||||
"x-editor": "text"
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Logo Image",
|
||||
"x-editor": "media"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "Partner URL",
|
||||
"x-editor": "link"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
273
template.templ
Normal file
273
template.templ
Normal file
@ -0,0 +1,273 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.dev.alexdunmow.com/block/core/templates/bn"
|
||||
)
|
||||
|
||||
// PageData contains the data for a rendered Earthen page.
|
||||
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
|
||||
}
|
||||
|
||||
func parseEarthenPageData(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
|
||||
}
|
||||
|
||||
siteSettings := bn.ParseSiteSettings(doc)
|
||||
pageMeta := bn.ParsePageMeta(doc)
|
||||
engagementConfig := bn.ParseEngagementConfig(doc)
|
||||
|
||||
return PageData{
|
||||
Title: title,
|
||||
Slots: slots,
|
||||
ThemeMode: themeMode,
|
||||
ThemeCSS: themeCSS,
|
||||
SiteSettings: siteSettings,
|
||||
PageMeta: pageMeta,
|
||||
StructuredData: structuredData,
|
||||
CSSHash: cssHash,
|
||||
PageviewNonce: pageviewNonce,
|
||||
EngagementConfig: engagementConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// EarthenDefault renders the default Earthen page (header, main, footer).
|
||||
templ EarthenDefault(data PageData) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="earthen">
|
||||
@bn.Head(bn.HeadData{
|
||||
Title: data.Title,
|
||||
Settings: data.SiteSettings,
|
||||
PageMeta: data.PageMeta,
|
||||
ThemeMode: data.ThemeMode,
|
||||
ThemeCSS: data.ThemeCSS,
|
||||
PluginStyles: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
})
|
||||
<body
|
||||
class="bg-paper-grain earthen-body antialiased min-h-screen flex flex-col"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);"
|
||||
>
|
||||
@bn.AdminBypassBanner(data.SiteSettings)
|
||||
<header class="w-full">
|
||||
@templ.Raw(data.Slots["header"])
|
||||
</header>
|
||||
<main class="flex-grow w-full max-w-5xl mx-auto px-4 py-10">
|
||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||
@templ.Raw(main)
|
||||
} else {
|
||||
<div class="py-20 text-center" style="color: hsl(var(--muted-foreground));">
|
||||
<p>No content blocks assigned to this page.</p>
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
<footer class="w-full mt-auto">
|
||||
@templ.Raw(data.Slots["footer"])
|
||||
</footer>
|
||||
@bn.BodyEnd(data.SiteSettings)
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
// EarthenLanding renders the landing template (hero, main, cta, footer).
|
||||
templ EarthenLanding(data PageData) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="earthen">
|
||||
@bn.Head(bn.HeadData{
|
||||
Title: data.Title,
|
||||
Settings: data.SiteSettings,
|
||||
PageMeta: data.PageMeta,
|
||||
ThemeMode: data.ThemeMode,
|
||||
ThemeCSS: data.ThemeCSS,
|
||||
PluginStyles: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
})
|
||||
<body
|
||||
class="bg-paper-grain earthen-body antialiased min-h-screen flex flex-col"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);"
|
||||
>
|
||||
@bn.AdminBypassBanner(data.SiteSettings)
|
||||
<section class="w-full">
|
||||
@templ.Raw(data.Slots["hero"])
|
||||
</section>
|
||||
<main class="flex-grow">
|
||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||
<div class="max-w-5xl mx-auto px-4 py-16">
|
||||
@templ.Raw(main)
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
<section class="w-full">
|
||||
@templ.Raw(data.Slots["cta"])
|
||||
</section>
|
||||
<footer class="w-full mt-auto">
|
||||
@templ.Raw(data.Slots["footer"])
|
||||
</footer>
|
||||
@bn.BodyEnd(data.SiteSettings)
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
// EarthenArticle renders the article template (header, lede, main, aside, footer).
|
||||
templ EarthenArticle(data PageData) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="earthen">
|
||||
@bn.Head(bn.HeadData{
|
||||
Title: data.Title,
|
||||
Settings: data.SiteSettings,
|
||||
PageMeta: data.PageMeta,
|
||||
ThemeMode: data.ThemeMode,
|
||||
ThemeCSS: data.ThemeCSS,
|
||||
PluginStyles: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
})
|
||||
<body
|
||||
class="bg-paper-grain earthen-body antialiased min-h-screen flex flex-col"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);"
|
||||
>
|
||||
@bn.AdminBypassBanner(data.SiteSettings)
|
||||
<header class="w-full" style="border-bottom: 1px solid hsl(var(--border));">
|
||||
<div class="max-w-3xl mx-auto px-4">
|
||||
@templ.Raw(data.Slots["header"])
|
||||
</div>
|
||||
</header>
|
||||
if lede, ok := data.Slots["lede"]; ok && lede != "" {
|
||||
<section class="w-full max-w-3xl mx-auto px-4 pt-12">
|
||||
@templ.Raw(lede)
|
||||
</section>
|
||||
}
|
||||
<div class="flex-grow w-full grid grid-cols-1 lg:grid-cols-[1fr,260px] gap-12 max-w-5xl mx-auto px-4 py-12">
|
||||
<main>
|
||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||
<article class="earthen-article">
|
||||
@templ.Raw(main)
|
||||
</article>
|
||||
} else {
|
||||
<p style="color: hsl(var(--muted-foreground));">No story body yet.</p>
|
||||
}
|
||||
</main>
|
||||
if aside, ok := data.Slots["aside"]; ok && aside != "" {
|
||||
<aside class="earthen-aside text-sm">
|
||||
@templ.Raw(aside)
|
||||
</aside>
|
||||
}
|
||||
</div>
|
||||
<footer class="w-full mt-auto">
|
||||
@templ.Raw(data.Slots["footer"])
|
||||
</footer>
|
||||
@bn.BodyEnd(data.SiteSettings)
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
// EarthenFullWidth renders edge-to-edge pages (header, main, footer).
|
||||
templ EarthenFullWidth(data PageData) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="earthen">
|
||||
@bn.Head(bn.HeadData{
|
||||
Title: data.Title,
|
||||
Settings: data.SiteSettings,
|
||||
PageMeta: data.PageMeta,
|
||||
ThemeMode: data.ThemeMode,
|
||||
ThemeCSS: data.ThemeCSS,
|
||||
PluginStyles: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
})
|
||||
<body
|
||||
class="bg-paper-grain earthen-body antialiased min-h-screen flex flex-col"
|
||||
style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);"
|
||||
>
|
||||
@bn.AdminBypassBanner(data.SiteSettings)
|
||||
<header class="w-full">
|
||||
@templ.Raw(data.Slots["header"])
|
||||
</header>
|
||||
<main class="flex-grow w-full">
|
||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||
@templ.Raw(main)
|
||||
} else {
|
||||
<div class="max-w-4xl mx-auto py-20 px-4 text-center" style="color: hsl(var(--muted-foreground));">
|
||||
<p>No content blocks assigned to this page.</p>
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
<footer class="w-full mt-auto">
|
||||
@templ.Raw(data.Slots["footer"])
|
||||
</footer>
|
||||
@bn.BodyEnd(data.SiteSettings)
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
// RenderEarthenDefault is the templates.TemplateFunc entry for "default".
|
||||
func RenderEarthenDefault(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenDefault(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenLanding is the templates.TemplateFunc entry for "landing".
|
||||
func RenderEarthenLanding(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenLanding(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenArticle is the templates.TemplateFunc entry for "article".
|
||||
func RenderEarthenArticle(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenArticle(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenFullWidth is the templates.TemplateFunc entry for "full-width".
|
||||
func RenderEarthenFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenFullWidth(parseEarthenPageData(doc))
|
||||
}
|
||||
543
template_templ.go
Normal file
543
template_templ.go
Normal file
@ -0,0 +1,543 @@
|
||||
// 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 contains the data for a rendered Earthen page.
|
||||
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
|
||||
}
|
||||
|
||||
func parseEarthenPageData(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
|
||||
}
|
||||
|
||||
siteSettings := bn.ParseSiteSettings(doc)
|
||||
pageMeta := bn.ParsePageMeta(doc)
|
||||
engagementConfig := bn.ParseEngagementConfig(doc)
|
||||
|
||||
return PageData{
|
||||
Title: title,
|
||||
Slots: slots,
|
||||
ThemeMode: themeMode,
|
||||
ThemeCSS: themeCSS,
|
||||
SiteSettings: siteSettings,
|
||||
PageMeta: pageMeta,
|
||||
StructuredData: structuredData,
|
||||
CSSHash: cssHash,
|
||||
PageviewNonce: pageviewNonce,
|
||||
EngagementConfig: engagementConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// EarthenDefault renders the default Earthen page (header, main, footer).
|
||||
func EarthenDefault(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\" class=\"earthen\">")
|
||||
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: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"bg-paper-grain earthen-body antialiased min-h-screen flex flex-col\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);\">")
|
||||
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=\"w-full\">")
|
||||
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, "</header><main class=\"flex-grow w-full max-w-5xl mx-auto px-4 py-10\">")
|
||||
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, "<div class=\"py-20 text-center\" style=\"color: hsl(var(--muted-foreground));\"><p>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, 6, "</main><footer class=\"w-full mt-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
|
||||
})
|
||||
}
|
||||
|
||||
// EarthenLanding renders the landing template (hero, main, cta, footer).
|
||||
func EarthenLanding(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\" class=\"earthen\">")
|
||||
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: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<body class=\"bg-paper-grain earthen-body antialiased min-h-screen flex flex-col\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);\">")
|
||||
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, "<section class=\"w-full\">")
|
||||
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, 12, "</section><main class=\"flex-grow\">")
|
||||
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, 13, "<div class=\"max-w-5xl mx-auto px-4 py-16\">")
|
||||
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, 14, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</main><section class=\"w-full\">")
|
||||
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, 16, "</section><footer class=\"w-full mt-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, 17, "</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, 18, "</body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// EarthenArticle renders the article template (header, lede, main, aside, footer).
|
||||
func EarthenArticle(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, 19, "<!doctype html><html lang=\"en\" class=\"earthen\">")
|
||||
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: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<body class=\"bg-paper-grain earthen-body antialiased min-h-screen flex flex-col\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);\">")
|
||||
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, 21, "<header class=\"w-full\" style=\"border-bottom: 1px solid hsl(var(--border));\"><div class=\"max-w-3xl mx-auto px-4\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(data.Slots["header"]).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</div></header>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if lede, ok := data.Slots["lede"]; ok && lede != "" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<section class=\"w-full max-w-3xl mx-auto px-4 pt-12\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(lede).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</section>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<div class=\"flex-grow w-full grid grid-cols-1 lg:grid-cols-[1fr,260px] gap-12 max-w-5xl mx-auto px-4 py-12\"><main>")
|
||||
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, 26, "<article class=\"earthen-article\">")
|
||||
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, 27, "</article>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<p style=\"color: hsl(var(--muted-foreground));\">No story body yet.</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</main>")
|
||||
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, 30, "<aside class=\"earthen-aside text-sm\">")
|
||||
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, 31, "</aside>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</div><footer class=\"w-full mt-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, 33, "</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, 34, "</body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// EarthenFullWidth renders edge-to-edge pages (header, main, footer).
|
||||
func EarthenFullWidth(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, 35, "<!doctype html><html lang=\"en\" class=\"earthen\">")
|
||||
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: []string{"/templates/earthen/css/earthen.css"},
|
||||
StructuredData: data.StructuredData,
|
||||
CSSHash: data.CSSHash,
|
||||
PageviewNonce: data.PageviewNonce,
|
||||
EngagementConfig: data.EngagementConfig,
|
||||
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<body class=\"bg-paper-grain earthen-body antialiased min-h-screen flex flex-col\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-body, "Spectral", Georgia, serif);\">")
|
||||
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, 37, "<header class=\"w-full\">")
|
||||
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, 38, "</header><main class=\"flex-grow w-full\">")
|
||||
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, 39, "<div class=\"max-w-4xl mx-auto py-20 px-4 text-center\" style=\"color: hsl(var(--muted-foreground));\"><p>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, 40, "</main><footer class=\"w-full mt-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, 41, "</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, 42, "</body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// RenderEarthenDefault is the templates.TemplateFunc entry for "default".
|
||||
func RenderEarthenDefault(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenDefault(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenLanding is the templates.TemplateFunc entry for "landing".
|
||||
func RenderEarthenLanding(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenLanding(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenArticle is the templates.TemplateFunc entry for "article".
|
||||
func RenderEarthenArticle(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenArticle(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
// RenderEarthenFullWidth is the templates.TemplateFunc entry for "full-width".
|
||||
func RenderEarthenFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
||||
return EarthenFullWidth(parseEarthenPageData(doc))
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
18
text_override.go
Normal file
18
text_override.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
)
|
||||
|
||||
// EarthenTextBlock renders text with Earthen styling.
|
||||
// When variant is "lede", the first paragraph gains a botanical drop-cap.
|
||||
func EarthenTextBlock(ctx context.Context, content map[string]any) string {
|
||||
text := getString(content, "text")
|
||||
class := getString(content, "class")
|
||||
variant := getString(content, "variant")
|
||||
|
||||
var buf bytes.Buffer
|
||||
_ = earthenTextComponent(text, class, variant).Render(ctx, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
20
text_override.templ
Normal file
20
text_override.templ
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
// earthenTextComponent renders body text with optional lede drop-cap.
|
||||
templ earthenTextComponent(text, class, variant string) {
|
||||
if variant == "lede" {
|
||||
<div
|
||||
class={ "earthen-text earthen-lede drop-cap-host max-w-none flex-1", class }
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
@templ.Raw(text)
|
||||
</div>
|
||||
} else {
|
||||
<div
|
||||
class={ "earthen-text max-w-none flex-1", class }
|
||||
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));" }
|
||||
>
|
||||
@templ.Raw(text)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
126
text_override_templ.go
Normal file
126
text_override_templ.go
Normal file
@ -0,0 +1,126 @@
|
||||
// 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"
|
||||
|
||||
// earthenTextComponent renders body text with optional lede drop-cap.
|
||||
func earthenTextComponent(text, class, 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 == "lede" {
|
||||
var templ_7745c5c3_Var2 = []any{"earthen-text earthen-lede drop-cap-host max-w-none flex-1", 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, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `text_override.templ`, Line: 8, Col: 104}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
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, 4, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
var templ_7745c5c3_Var5 = []any{"earthen-text max-w-none flex-1", class}
|
||||
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, 5, "<div 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: `text_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, 6, "\" style=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--foreground));")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `text_override.templ`, Line: 15, 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, 7, "\">")
|
||||
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, 8, "</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
Loading…
x
Reference in New Issue
Block a user