Compare commits
No commits in common. "a7141e39ae4436b9479fc6ca56d1f6500b8ad0a2" and "57e16e8ec79d32577b7d94d72d3737bfb1bcb68a" have entirely different histories.
a7141e39ae
...
57e16e8ec7
40
Makefile
40
Makefile
@ -1,27 +1,26 @@
|
|||||||
# art-deco — build & publish helpers (CODELESS .bnp workflow, WO-WZ-021)
|
# art-deco — build & publish helpers (wasm .bnp workflow)
|
||||||
#
|
#
|
||||||
# This theme is a CODELESS .bnp: pure declaration the host runs — blocks
|
# The theme compiles to a wasip1 reactor-mode wasm module packed into a .bnp
|
||||||
# (blocks/blocks.yaml + .ninjatpl), page/system templates, template overrides,
|
# artifact (`ninja plugin build`). The legacy .so path is retired (WO-WZ-015):
|
||||||
# an email wrapper, master pages, presets, fonts and CSS in manifest.yaml. No
|
# the CMS is wasm-native and can no longer load .so plugins. Distribution is
|
||||||
# Go, no templ, no plugin.wasm, no block/core dependency. `ninja plugin build`
|
# publish-to-registry -> InstallFromRegistry (hot-load, no restart).
|
||||||
# classifies the repo as codeless (no Go at the root) and packs the artifact
|
|
||||||
# with manifest.pb (codeless: true) and NO plugin.wasm.
|
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# make build # pack art-deco-<version>.bnp (codeless — no wasm)
|
# make build # compile wasm + pack art-deco-<version>.bnp
|
||||||
# make verify # validate the built .bnp (loader-identical checks)
|
# make verify # validate the built .bnp (layout/abi/name/size)
|
||||||
# make archive-check # prove a clean `git archive HEAD` still builds codeless
|
# make archive-check # prove a clean `git archive HEAD` compiles to wasm
|
||||||
# make publish # ninja plugin publish --bnp (to the active registry)
|
# make publish # ninja plugin publish --bnp (to the active registry)
|
||||||
|
# make templ # regenerate templ Go files
|
||||||
# make clean # remove build artefacts
|
# make clean # remove build artefacts
|
||||||
|
|
||||||
.PHONY: build verify archive-check publish clean help
|
.PHONY: build verify archive-check publish templ clean help
|
||||||
|
|
||||||
PLUGIN_NAME := art-deco
|
PLUGIN_NAME := art-deco
|
||||||
NINJA := ninja
|
NINJA := ninja
|
||||||
BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp
|
BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp
|
||||||
|
|
||||||
# Pack the codeless .bnp (manifest.pb synthesized from plugin.mod + manifest.yaml
|
# Compile to wasm and pack the .bnp (GOOS=wasip1 GOARCH=wasm, DESCRIBE probe,
|
||||||
# + blocks/ + templates/; no wasm compile, no DESCRIBE probe).
|
# tar.zst of plugin.wasm + plugin.mod + manifest.pb + schemas/ + assets/).
|
||||||
build:
|
build:
|
||||||
$(NINJA) plugin build --dir .
|
$(NINJA) plugin build --dir .
|
||||||
|
|
||||||
@ -29,12 +28,12 @@ build:
|
|||||||
verify:
|
verify:
|
||||||
$(NINJA) plugin verify $(BNP)
|
$(NINJA) plugin verify $(BNP)
|
||||||
|
|
||||||
# Prove a clean `git archive HEAD` (what publish ships) still packs codeless.
|
# Prove a clean `git archive HEAD` (what publish ships) compiles to wasm.
|
||||||
archive-check:
|
archive-check:
|
||||||
@T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \
|
@T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \
|
||||||
trap 'rm -rf "$$T"' EXIT && \
|
trap 'rm -rf "$$T"' EXIT && \
|
||||||
git archive HEAD | tar -x -C "$$T" && \
|
git archive HEAD | tar -x -C "$$T" && \
|
||||||
cd "$$T" && $(NINJA) plugin build --dir . && \
|
cd "$$T" && GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o "$$T/check.wasm" . && \
|
||||||
echo "archive-check OK"
|
echo "archive-check OK"
|
||||||
|
|
||||||
# Publish the prebuilt .bnp to the active registry.
|
# Publish the prebuilt .bnp to the active registry.
|
||||||
@ -42,14 +41,19 @@ archive-check:
|
|||||||
publish: build
|
publish: build
|
||||||
$(NINJA) plugin publish --bnp $(BNP)
|
$(NINJA) plugin publish --bnp $(BNP)
|
||||||
|
|
||||||
|
# Regenerate templ Go files locally.
|
||||||
|
templ:
|
||||||
|
templ generate
|
||||||
|
|
||||||
# Remove build artefacts.
|
# Remove build artefacts.
|
||||||
clean:
|
clean:
|
||||||
rm -f $(PLUGIN_NAME)-*.bnp plugin.wasm
|
rm -f $(PLUGIN_NAME)-*.bnp $(PLUGIN_NAME).so plugin.wasm
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Targets:"
|
@echo "Targets:"
|
||||||
@echo " build Pack the codeless .bnp (no wasm)"
|
@echo " build Compile wasm + pack the .bnp"
|
||||||
@echo " verify Validate the built .bnp (loader-identical checks)"
|
@echo " verify Validate the built .bnp (loader-identical checks)"
|
||||||
@echo " archive-check Prove a clean git archive HEAD packs codeless"
|
@echo " archive-check Prove a clean git archive HEAD compiles to wasm"
|
||||||
@echo " publish Publish the .bnp to the active registry"
|
@echo " publish Publish the .bnp to the active registry"
|
||||||
|
@echo " templ Regenerate templ Go files"
|
||||||
@echo " clean Remove build artefacts"
|
@echo " clean Remove build artefacts"
|
||||||
|
|||||||
@ -1,48 +0,0 @@
|
|||||||
# Art Deco theme block definitions (codeless .bnp, WO-WZ-021).
|
|
||||||
# Keys are fully qualified (art-deco:<key>) because the codeless loader
|
|
||||||
# registers definitions verbatim — there is no PluginBlockRegistry prefixing
|
|
||||||
# in the codeless path (unlike the wasm/templ path). The qualified keys match
|
|
||||||
# the hardcoded data-block attributes and the master_pages.json references.
|
|
||||||
blocks:
|
|
||||||
- key: art-deco:reservation
|
|
||||||
title: Reservation Strip
|
|
||||||
description: Sticky gold-on-black reservation strip with phone, OpenTable CTA and trading hours.
|
|
||||||
category: navigation
|
|
||||||
schema: reservation.schema.json
|
|
||||||
template: reservation.ninjatpl
|
|
||||||
- key: art-deco:menu
|
|
||||||
title: Tasting Menu
|
|
||||||
description: Symmetric two-column menu card listing courses with description and price.
|
|
||||||
category: content
|
|
||||||
schema: menu.schema.json
|
|
||||||
template: menu.ninjatpl
|
|
||||||
- key: art-deco:gallery_fan
|
|
||||||
title: Fan Gallery
|
|
||||||
description: Mirrored gallery framed by sunburst — collapses to single column under 640px.
|
|
||||||
category: content
|
|
||||||
schema: gallery_fan.schema.json
|
|
||||||
template: gallery_fan.ninjatpl
|
|
||||||
- key: art-deco:divider_fan
|
|
||||||
title: Fan Divider
|
|
||||||
description: Pure-CSS gold geometric divider — sunburst, scallop or ziggurat.
|
|
||||||
category: layout
|
|
||||||
schema: divider_fan.schema.json
|
|
||||||
template: divider_fan.ninjatpl
|
|
||||||
- key: art-deco:footer
|
|
||||||
title: Footer
|
|
||||||
description: Centered Art Deco footer with gold rule, address, reservations email and optional social row.
|
|
||||||
category: layout
|
|
||||||
schema: footer.schema.json
|
|
||||||
template: footer.ninjatpl
|
|
||||||
- key: art-deco:marquee_hero
|
|
||||||
title: Marquee Hero
|
|
||||||
description: Wide hero with stepped ziggurat frame and sunburst overlay.
|
|
||||||
category: content
|
|
||||||
schema: marquee_hero.schema.json
|
|
||||||
template: marquee_hero.ninjatpl
|
|
||||||
- key: art-deco:press_quote
|
|
||||||
title: Press Quote
|
|
||||||
description: Italic Cormorant pull-quote between fan dividers, optional star rating.
|
|
||||||
category: content
|
|
||||||
schema: press_quote.schema.json
|
|
||||||
template: press_quote.ninjatpl
|
|
||||||
@ -1 +0,0 @@
|
|||||||
{% if variant == "scallop" %}<div data-block="art-deco:divider_fan" data-variant="scallop" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-scallop"></div></div>{% elif variant == "ziggurat" %}<div data-block="art-deco:divider_fan" data-variant="ziggurat" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-ziggurat"></div></div>{% else %}<div data-block="art-deco:divider_fan" data-variant="sunburst" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-sunburst"></div></div>{% endif %}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<section data-block="art-deco:footer" class="py-12 deco-grain">
|
|
||||||
<div class="max-w-3xl mx-auto px-4 text-center">
|
|
||||||
<hr class="deco-rule mb-8">
|
|
||||||
{% if address %}<address class="not-italic mb-4" style="color: hsl(var(--muted-foreground));">{% for line in address|lines %}<div>{{ line }}</div>{% endfor %}</address>{% endif %}
|
|
||||||
{% if reservationsEmail %}<p class="mb-4"><a href="mailto:{{ reservationsEmail }}" class="deco-link">{{ reservationsEmail }}</a></p>{% endif %}
|
|
||||||
{% if menuName %}<nav aria-label="Footer" class="deco-caps text-xs mb-4" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"><span>{{ menuName }}</span></nav>{% endif %}
|
|
||||||
{% if showSocial != "false" %}<div class="flex justify-center gap-4 mb-4" style="color: hsl(var(--primary));"><span class="deco-caps text-xs" aria-hidden="true">Instagram</span><span aria-hidden="true">·</span><span class="deco-caps text-xs" aria-hidden="true">Facebook</span><span aria-hidden="true">·</span><span class="deco-caps text-xs" aria-hidden="true">LinkedIn</span></div>{% endif %}
|
|
||||||
<hr class="deco-rule mt-8">
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<section data-block="art-deco:gallery_fan" class="py-16">
|
|
||||||
<div class="max-w-6xl mx-auto px-4">
|
|
||||||
<div class="relative deco-grain">
|
|
||||||
<div class="absolute inset-x-0 -top-2 h-12 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
|
||||||
<div class="grid gap-4 pt-12 {% if columns|integer == 2 %}grid-cols-1 sm:grid-cols-2{% elif columns|integer == 4 %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-4{% else %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-3{% endif %}">
|
|
||||||
{% if not images %}<div class="col-span-full text-center text-sm py-12" style="color: hsl(var(--muted-foreground));">Add images to populate the fan gallery.</div>{% endif %}
|
|
||||||
{% for img in images %}<figure class="deco-step">{% if img.src %}<img src="{{ img.src }}" alt="{{ img.caption }}" class="block w-full h-auto object-cover" style="background-color: hsl(var(--muted));">{% else %}<img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E" alt="" class="block w-full h-auto" style="background-color: hsl(var(--muted));">{% endif %}{% if img.caption %}<figcaption class="mt-2 text-center italic text-sm" style="color: hsl(var(--muted-foreground));">{{ img.caption }}</figcaption>{% endif %}</figure>{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="absolute inset-x-0 -bottom-2 h-12 pointer-events-none deco-sunburst rotate-180" aria-hidden="true"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<section data-block="art-deco:marquee_hero" class="relative w-full overflow-hidden deco-grain" style="background-color: hsl(var(--foreground)); color: hsl(var(--background));">
|
|
||||||
{% if image %}<div class="absolute inset-0 z-0" aria-hidden="true"><img src="{{ image }}" alt="" class="w-full h-full object-cover" style="opacity: 0.5;"><div class="absolute inset-0" style="background-color: hsl(var(--foreground) / 0.55);"></div></div>{% endif %}
|
|
||||||
<div class="absolute inset-x-0 top-0 h-24 z-10 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
|
||||||
<div class="relative z-20 max-w-4xl mx-auto px-4 py-32 text-center">
|
|
||||||
<div class="deco-frame inline-block px-12 py-10" style="background-color: hsl(var(--foreground) / 0.6); border-color: hsl(var(--primary));">
|
|
||||||
{% if eyebrow %}<p class="deco-caps mb-4 text-xs" style="color: hsl(var(--primary));">{{ eyebrow }}</p>{% endif %}
|
|
||||||
{% if title %}<h1 class="deco-caps deco-underline mb-6 text-5xl md:text-6xl lg:text-7xl" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--background));">{{ title }}</h1>{% endif %}
|
|
||||||
{% if subtitle %}<div class="text-lg md:text-xl mb-8 max-w-2xl mx-auto" style="color: hsl(var(--background) / 0.9);">{{ subtitle|safe }}</div>{% endif %}
|
|
||||||
{% if ctaLabel and ctaHref %}<a href="{{ ctaHref }}" class="deco-pill" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));">{{ ctaLabel }}</a>{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<section data-block="art-deco:menu" class="py-16">
|
|
||||||
<div class="max-w-3xl mx-auto px-4">
|
|
||||||
<div class="deco-frame text-center" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground));">
|
|
||||||
{% if title %}<h2 class="deco-caps deco-underline mb-8 text-3xl md:text-4xl" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ title }}</h2>{% endif %}
|
|
||||||
{% if courses %}<ul class="space-y-6 text-left">{% for course in courses %}<li class="flex items-start justify-between gap-6 border-b" style="border-color: hsl(var(--border));"><div class="flex-1"><h3 class="deco-caps text-lg" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ course.name }}</h3>{% if course.description %}<div class="mt-1 italic" style="color: hsl(var(--muted-foreground));">{{ course.description|safe }}</div>{% endif %}</div>{% if course.price %}<span class="deco-caps text-base" style="font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); color: hsl(var(--primary));">{{ course.price }}</span>{% endif %}</li>{% endfor %}</ul>{% else %}<p class="text-muted-foreground" style="color: hsl(var(--muted-foreground));">Add courses to start composing this menu.</p>{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
<section data-block="art-deco:press_quote" class="py-16">
|
|
||||||
<div class="max-w-3xl mx-auto px-4 text-center">
|
|
||||||
<div class="h-6 mb-6 deco-sunburst" aria-hidden="true"></div>
|
|
||||||
<blockquote class="italic text-2xl md:text-3xl leading-snug" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); font-style: italic; color: hsl(var(--foreground));">{% if quote %}{{ quote|safe }}{% else %}<span style="color: hsl(var(--muted-foreground));">Add a press quote to populate this block.</span>{% endif %}</blockquote>
|
|
||||||
{% if stars|integer > 0 %}<div class="mt-4 flex justify-center gap-1" aria-label="Star rating" data-stars="{{ stars|integer }}">{% if stars|integer >= 1 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 2 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 3 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 4 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 5 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}</div>{% endif %}
|
|
||||||
{% if source %}<p class="mt-6 deco-caps text-xs" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--muted-foreground));">{{ source }}</p>{% endif %}
|
|
||||||
<div class="h-6 mt-6 deco-scallop" aria-hidden="true"></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<div data-block="art-deco:reservation" class="sticky top-0 z-30 w-full deco-grain" style="background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-bottom: 1px solid hsl(var(--primary));">
|
|
||||||
<div class="max-w-5xl mx-auto px-4 py-2 flex flex-wrap items-center justify-between gap-2 text-sm">
|
|
||||||
<div class="flex items-center gap-3 deco-caps" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--primary));">
|
|
||||||
<span>Reservations</span>
|
|
||||||
{% if phone %}<span aria-hidden="true" style="color: hsl(var(--primary) / 0.5);">·</span><a href="tel:{{ phone }}" class="deco-link" style="border-bottom-color: hsl(var(--primary));">{{ phone }}</a>{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if hours %}<div class="flex flex-wrap items-center gap-3" style="color: hsl(var(--background));">{% for line in hours %}{% if not forloop.First %}<span aria-hidden="true" style="color: hsl(var(--primary) / 0.5);">·</span>{% endif %}<span>{{ line }}</span>{% endfor %}</div>{% endif %}
|
|
||||||
{% if openTable %}<a href="{{ openTable }}" class="deco-pill" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));">Book a Table</a>{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
41
button_override.go
Normal file
41
button_override.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ButtonOverrideData is the typed view for the button override component.
|
||||||
|
type ButtonOverrideData struct {
|
||||||
|
Label string
|
||||||
|
URL string
|
||||||
|
Variant string
|
||||||
|
}
|
||||||
|
|
||||||
|
// normaliseButtonVariant returns a known variant or "primary" as default.
|
||||||
|
func normaliseButtonVariant(v string) string {
|
||||||
|
switch v {
|
||||||
|
case "primary", "secondary", "ghost":
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return "primary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoButtonBlock overrides the built-in "button" block when the Art Deco theme is active.
|
||||||
|
// Content: {"label": "...", "url": "...", "variant": "primary|secondary|ghost"}
|
||||||
|
func ArtDecoButtonBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := ButtonOverrideData{
|
||||||
|
Label: getString(content, "label"),
|
||||||
|
URL: getString(content, "url"),
|
||||||
|
Variant: normaliseButtonVariant(getString(content, "variant")),
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Label == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoButtonComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
36
button_override.templ
Normal file
36
button_override.templ
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// buttonVariantStyle returns inline style overrides per variant.
|
||||||
|
func buttonVariantStyle(variant string) string {
|
||||||
|
switch variant {
|
||||||
|
case "secondary":
|
||||||
|
return "background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));"
|
||||||
|
case "ghost":
|
||||||
|
return "background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));"
|
||||||
|
default:
|
||||||
|
return "background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoButtonComponent renders the black-pill button with stamped hover state.
|
||||||
|
templ artDecoButtonComponent(data ButtonOverrideData) {
|
||||||
|
if data.URL != "" {
|
||||||
|
<a
|
||||||
|
data-block-override="art-deco:button"
|
||||||
|
href={ templ.SafeURL(data.URL) }
|
||||||
|
class="deco-pill inline-block"
|
||||||
|
style={ buttonVariantStyle(data.Variant) }
|
||||||
|
>
|
||||||
|
{ data.Label }
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-block-override="art-deco:button"
|
||||||
|
class="deco-pill"
|
||||||
|
style={ buttonVariantStyle(data.Variant) }
|
||||||
|
>
|
||||||
|
{ data.Label }
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
125
button_override_templ.go
Normal file
125
button_override_templ.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// buttonVariantStyle returns inline style overrides per variant.
|
||||||
|
func buttonVariantStyle(variant string) string {
|
||||||
|
switch variant {
|
||||||
|
case "secondary":
|
||||||
|
return "background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));"
|
||||||
|
case "ghost":
|
||||||
|
return "background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));"
|
||||||
|
default:
|
||||||
|
return "background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoButtonComponent renders the black-pill button with stamped hover state.
|
||||||
|
func artDecoButtonComponent(data ButtonOverrideData) 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 data.URL != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<a data-block-override=\"art-deco:button\" 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(data.URL))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 20, Col: 33}
|
||||||
|
}
|
||||||
|
_, 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, "\" class=\"deco-pill inline-block\" style=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(buttonVariantStyle(data.Variant))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 22, Col: 43}
|
||||||
|
}
|
||||||
|
_, 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
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 24, Col: 15}
|
||||||
|
}
|
||||||
|
_, 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, "</a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<button type=\"button\" data-block-override=\"art-deco:button\" class=\"deco-pill\" style=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(buttonVariantStyle(data.Variant))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 31, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 33, Col: 15}
|
||||||
|
}
|
||||||
|
_, 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, 7, "</button>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
43
divider_fan.go
Normal file
43
divider_fan.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DividerFanBlockMeta defines the fan divider block.
|
||||||
|
var DividerFanBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "divider_fan",
|
||||||
|
Title: "Fan Divider",
|
||||||
|
Description: "Pure-CSS gold geometric divider — sunburst, scallop or ziggurat.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// DividerFanData carries the variant for the divider component.
|
||||||
|
type DividerFanData struct {
|
||||||
|
Variant string
|
||||||
|
}
|
||||||
|
|
||||||
|
// normaliseVariant clamps to the supported set; unknown values fall back to sunburst.
|
||||||
|
func normaliseVariant(v string) string {
|
||||||
|
switch v {
|
||||||
|
case "scallop", "ziggurat":
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return "sunburst"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DividerFanBlock renders a CSS-only geometric divider.
|
||||||
|
// Content: {"variant": "sunburst" | "scallop" | "ziggurat"}
|
||||||
|
func DividerFanBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := DividerFanData{
|
||||||
|
Variant: normaliseVariant(getString(content, "variant")),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = dividerFanComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
26
divider_fan.templ
Normal file
26
divider_fan.templ
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// dividerVariantClass maps the variant to the corresponding utility class.
|
||||||
|
func dividerVariantClass(variant string) string {
|
||||||
|
switch variant {
|
||||||
|
case "scallop":
|
||||||
|
return "deco-scallop"
|
||||||
|
case "ziggurat":
|
||||||
|
return "deco-ziggurat"
|
||||||
|
default:
|
||||||
|
return "deco-sunburst"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dividerFanComponent renders a pure-CSS gold geometric divider.
|
||||||
|
templ dividerFanComponent(data DividerFanData) {
|
||||||
|
<div
|
||||||
|
data-block="art-deco:divider_fan"
|
||||||
|
data-variant={ data.Variant }
|
||||||
|
class="w-full py-6 flex justify-center"
|
||||||
|
role="presentation"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<div class={ "h-10 w-full max-w-xl", dividerVariantClass(data.Variant) }></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
88
divider_fan_templ.go
Normal file
88
divider_fan_templ.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// dividerVariantClass maps the variant to the corresponding utility class.
|
||||||
|
func dividerVariantClass(variant string) string {
|
||||||
|
switch variant {
|
||||||
|
case "scallop":
|
||||||
|
return "deco-scallop"
|
||||||
|
case "ziggurat":
|
||||||
|
return "deco-ziggurat"
|
||||||
|
default:
|
||||||
|
return "deco-sunburst"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dividerFanComponent renders a pure-CSS gold geometric divider.
|
||||||
|
func dividerFanComponent(data DividerFanData) 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=\"art-deco:divider_fan\" data-variant=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Variant)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `divider_fan.templ`, Line: 19, Col: 29}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" class=\"w-full py-6 flex justify-center\" role=\"presentation\" aria-hidden=\"true\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 = []any{"h-10 w-full max-w-xl", dividerVariantClass(data.Variant)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var3).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `divider_fan.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, 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, 4, "\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
178
email_wrapper.templ
Normal file
178
email_wrapper.templ
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArtDecoEmailWrapper wraps body content in the Art Deco email layout:
|
||||||
|
// ivory background, 600px column, jet-black masthead with flat-gold PNG sunburst,
|
||||||
|
// Cormorant body, gold hairline above footer, reservation phone postscript.
|
||||||
|
func ArtDecoEmailWrapper(body string, emailCtx templates.EmailContext) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// edColor returns a color from the email context or a hex fallback for the named token.
|
||||||
|
func edColor(value, fallback string) string {
|
||||||
|
if value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// edBg ivory background.
|
||||||
|
func edBg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Background, "#f6efe2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edCard jet-black masthead surface (uses Foreground as the dark masthead colour).
|
||||||
|
func edCardDark(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edFg foreground text on the ivory body.
|
||||||
|
func edFg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edPrimary champagne-gold accent (used for the hairline and links).
|
||||||
|
func edPrimary(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Primary, "#c9a14a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edMutedFg muted footer text.
|
||||||
|
func edMutedFg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.MutedForeground, "#6c5b35")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edBorder hairline gold border colour.
|
||||||
|
func edBorder(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Border, "#c9a14a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatGoldSunburstSVG is the inlined data: URI for the flat-gold sunburst image
|
||||||
|
// used as a fallback for the Outlook masthead (CSS conic-gradient is flattened by Outlook).
|
||||||
|
// We render via string concatenation so the URL-encoded %xx tokens are not misread as fmt verbs.
|
||||||
|
func flatGoldSunburstSVG(gold string) string {
|
||||||
|
g := stripHash(gold)
|
||||||
|
prefix := "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%2080%22%3E%3Crect%20width%3D%22600%22%20height%3D%2280%22%20fill%3D%22%23191510%22%2F%3E%3Cg%20stroke%3D%22%23"
|
||||||
|
rays := "%22%20stroke-width%3D%221%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M300%2080%20L%20100%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20180%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20260%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20340%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20420%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20500%2010%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"
|
||||||
|
return prefix + g + rays
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripHash removes a leading '#' if present (defensive for the data URI).
|
||||||
|
func stripHash(s string) string {
|
||||||
|
if len(s) > 0 && s[0] == '#' {
|
||||||
|
return s[1:]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoEmailTemplate renders the Art Deco email wrapper.
|
||||||
|
templ artDecoEmailTemplate(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>
|
||||||
|
<style type="text/css">
|
||||||
|
body, table, td, p, a, li, blockquote {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
||||||
|
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
|
||||||
|
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
|
||||||
|
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
|
||||||
|
@media only screen and (max-width: 620px) {
|
||||||
|
.email-container { width: 100% !important; max-width: 100% !important; }
|
||||||
|
.content-padding { padding-left: 24px !important; padding-right: 24px !important; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style={ fmt.Sprintf("background-color: %s; margin: 0; padding: 0; font-family: 'Cormorant Garamond', 'Cormorant', Georgia, serif;", edBg(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">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style={ fmt.Sprintf("padding: 32px 10px; background-color: %s;", edBg(emailCtx)) }>
|
||||||
|
<table role="presentation" class="email-container" width="600" cellspacing="0" cellpadding="0" border="0" style={ fmt.Sprintf("max-width: 600px; background-color: %s; border: 1px solid %s;", edBg(emailCtx), edBorder(emailCtx)) }>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style={ fmt.Sprintf("padding: 0; background-color: %s;", edCardDark(emailCtx)) }>
|
||||||
|
<img
|
||||||
|
src={ flatGoldSunburstSVG(edPrimary(emailCtx)) }
|
||||||
|
alt=""
|
||||||
|
width="600"
|
||||||
|
height="80"
|
||||||
|
style={ fmt.Sprintf("display: block; width: 100%%; max-width: 600px; height: 80px; background-color: %s;", edCardDark(emailCtx)) }
|
||||||
|
/>
|
||||||
|
if emailCtx.SiteSettings.SiteName != "" {
|
||||||
|
<h1 style={ fmt.Sprintf("margin: 0; padding: 24px 16px; font-family: 'Italiana', 'Cinzel', Georgia, serif; font-size: 28px; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edPrimary(emailCtx)) }>
|
||||||
|
{ emailCtx.SiteSettings.SiteName }
|
||||||
|
</h1>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="content-padding" style={ fmt.Sprintf("padding: 40px 48px; color: %s; font-size: 16px; line-height: 1.7;", edFg(emailCtx)) }>
|
||||||
|
@templ.Raw(body)
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style={ fmt.Sprintf("padding: 0 48px;") }>
|
||||||
|
<hr style={ fmt.Sprintf("border: none; border-top: 1px solid %s; margin: 0;", edPrimary(emailCtx)) }/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style={ fmt.Sprintf("padding: 24px 48px; color: %s; font-size: 13px;", edMutedFg(emailCtx)) }>
|
||||||
|
<p style={ fmt.Sprintf("margin: 0 0 8px; font-family: 'Italiana', 'Cinzel', Georgia, serif; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edFg(emailCtx)) }>
|
||||||
|
{ emailCtx.SiteSettings.SiteName }
|
||||||
|
</p>
|
||||||
|
if emailCtx.SiteSettings.SiteURL != "" {
|
||||||
|
<p style="margin: 0 0 8px;">
|
||||||
|
<a href={ templ.SafeURL(emailCtx.SiteSettings.SiteURL) } style={ fmt.Sprintf("color: %s; text-decoration: none; border-bottom: 1px solid %s;", edPrimary(emailCtx), edPrimary(emailCtx)) }>
|
||||||
|
{ emailCtx.SiteSettings.SiteURL }
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
if emailCtx.SiteSettings.SupportEmail != "" {
|
||||||
|
<p style={ fmt.Sprintf("margin: 12px 0 0; font-style: italic; color: %s;", edMutedFg(emailCtx)) }>
|
||||||
|
P.S. Reservations & enquiries: { emailCtx.SiteSettings.SupportEmail }
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
if emailCtx.UnsubscribeURL != "" {
|
||||||
|
<p style="margin: 16px 0 0; font-size: 11px;">
|
||||||
|
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style={ fmt.Sprintf("color: %s; text-decoration: none;", edMutedFg(emailCtx)) }>
|
||||||
|
Unsubscribe
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
463
email_wrapper_templ.go
Normal file
463
email_wrapper_templ.go
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.1020
|
||||||
|
package main
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArtDecoEmailWrapper wraps body content in the Art Deco email layout:
|
||||||
|
// ivory background, 600px column, jet-black masthead with flat-gold PNG sunburst,
|
||||||
|
// Cormorant body, gold hairline above footer, reservation phone postscript.
|
||||||
|
func ArtDecoEmailWrapper(body string, emailCtx templates.EmailContext) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// edColor returns a color from the email context or a hex fallback for the named token.
|
||||||
|
func edColor(value, fallback string) string {
|
||||||
|
if value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// edBg ivory background.
|
||||||
|
func edBg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Background, "#f6efe2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edCard jet-black masthead surface (uses Foreground as the dark masthead colour).
|
||||||
|
func edCardDark(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edFg foreground text on the ivory body.
|
||||||
|
func edFg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edPrimary champagne-gold accent (used for the hairline and links).
|
||||||
|
func edPrimary(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Primary, "#c9a14a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edMutedFg muted footer text.
|
||||||
|
func edMutedFg(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.MutedForeground, "#6c5b35")
|
||||||
|
}
|
||||||
|
|
||||||
|
// edBorder hairline gold border colour.
|
||||||
|
func edBorder(emailCtx templates.EmailContext) string {
|
||||||
|
return edColor(emailCtx.Colors.Border, "#c9a14a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatGoldSunburstSVG is the inlined data: URI for the flat-gold sunburst image
|
||||||
|
// used as a fallback for the Outlook masthead (CSS conic-gradient is flattened by Outlook).
|
||||||
|
// We render via string concatenation so the URL-encoded %xx tokens are not misread as fmt verbs.
|
||||||
|
func flatGoldSunburstSVG(gold string) string {
|
||||||
|
g := stripHash(gold)
|
||||||
|
prefix := "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%2080%22%3E%3Crect%20width%3D%22600%22%20height%3D%2280%22%20fill%3D%22%23191510%22%2F%3E%3Cg%20stroke%3D%22%23"
|
||||||
|
rays := "%22%20stroke-width%3D%221%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M300%2080%20L%20100%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20180%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20260%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20340%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20420%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20500%2010%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"
|
||||||
|
return prefix + g + rays
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripHash removes a leading '#' if present (defensive for the data URI).
|
||||||
|
func stripHash(s string) string {
|
||||||
|
if len(s) > 0 && s[0] == '#' {
|
||||||
|
return s[1:]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoEmailTemplate renders the Art Deco email wrapper.
|
||||||
|
func artDecoEmailTemplate(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: 94, Col: 42}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><style type=\"text/css\">\n\t\t\t\tbody, table, td, p, a, li, blockquote {\n\t\t\t\t\t-webkit-text-size-adjust: 100%;\n\t\t\t\t\t-ms-text-size-adjust: 100%;\n\t\t\t\t}\n\t\t\t\ttable, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }\n\t\t\t\timg { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }\n\t\t\t\tbody { margin: 0 !important; padding: 0 !important; width: 100% !important; }\n\t\t\t\ta[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }\n\t\t\t\t@media only screen and (max-width: 620px) {\n\t\t\t\t\t.email-container { width: 100% !important; max-width: 100% !important; }\n\t\t\t\t\t.content-padding { padding-left: 24px !important; padding-right: 24px !important; }\n\t\t\t\t}\n\t\t\t</style></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: 'Cormorant Garamond', 'Cormorant', Georgia, serif;", edBg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 110, Col: 155}
|
||||||
|
}
|
||||||
|
_, 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: 113, 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\"><tr><td align=\"center\" 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("padding: 32px 10px; background-color: %s;", edBg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 118, Col: 104}
|
||||||
|
}
|
||||||
|
_, 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, "\"><table role=\"presentation\" class=\"email-container\" 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;", edBg(emailCtx), edBorder(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 119, Col: 232}
|
||||||
|
}
|
||||||
|
_, 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: 0; background-color: %s;", edCardDark(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 121, Col: 105}
|
||||||
|
}
|
||||||
|
_, 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, "\"><img src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(flatGoldSunburstSVG(edPrimary(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 123, Col: 56}
|
||||||
|
}
|
||||||
|
_, 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, 10, "\" alt=\"\" width=\"600\" height=\"80\" style=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("display: block; width: 100%%; max-width: 600px; height: 80px; background-color: %s;", edCardDark(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 127, Col: 138}
|
||||||
|
}
|
||||||
|
_, 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, 11, "\"> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if emailCtx.SiteSettings.SiteName != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<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; padding: 24px 16px; font-family: 'Italiana', 'Cinzel', Georgia, serif; font-size: 28px; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edPrimary(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 130, Col: 218}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
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: 131, 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, 14, "</h1>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</td></tr><tr><td class=\"content-padding\" 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: 40px 48px; color: %s; font-size: 16px; line-height: 1.7;", edFg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 137, Col: 140}
|
||||||
|
}
|
||||||
|
_, 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, 16, "\">")
|
||||||
|
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, 17, "</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: 0 48px;"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 142, Col: 51}
|
||||||
|
}
|
||||||
|
_, 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, 18, "\"><hr 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("border: none; border-top: 1px solid %s; margin: 0;", edPrimary(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 143, Col: 107}
|
||||||
|
}
|
||||||
|
_, 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, 19, "\"></td></tr><tr><td align=\"center\" style=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var15 string
|
||||||
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("padding: 24px 48px; color: %s; font-size: 13px;", edMutedFg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 147, Col: 118}
|
||||||
|
}
|
||||||
|
_, 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, 20, "\"><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 8px; font-family: 'Italiana', 'Cinzel', Georgia, serif; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edFg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 148, Col: 180}
|
||||||
|
}
|
||||||
|
_, 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, 21, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var17 string
|
||||||
|
templ_7745c5c3_Var17, 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: 149, Col: 42}
|
||||||
|
}
|
||||||
|
_, 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, 22, "</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=\"margin: 0 0 8px;\"><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: 153, Col: 65}
|
||||||
|
}
|
||||||
|
_, 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, 24, "\" 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 solid %s;", edPrimary(emailCtx), edPrimary(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 153, Col: 195}
|
||||||
|
}
|
||||||
|
_, 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, 25, "\">")
|
||||||
|
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: 154, Col: 43}
|
||||||
|
}
|
||||||
|
_, 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, 26, "</a></p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if emailCtx.SiteSettings.SupportEmail != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<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: 12px 0 0; font-style: italic; color: %s;", edMutedFg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 159, Col: 105}
|
||||||
|
}
|
||||||
|
_, 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, 28, "\">P.S. Reservations & enquiries: ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var22 string
|
||||||
|
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SupportEmail)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 160, Col: 82}
|
||||||
|
}
|
||||||
|
_, 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, 29, "</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if emailCtx.UnsubscribeURL != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<p style=\"margin: 16px 0 0; font-size: 11px;\"><a href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var23 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var23, 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: 165, Col: 59}
|
||||||
|
}
|
||||||
|
_, 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, "\" 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("color: %s; text-decoration: none;", edMutedFg(emailCtx)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 165, Col: 139}
|
||||||
|
}
|
||||||
|
_, 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, 32, "\">Unsubscribe</a></p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</td></tr></table></td></tr></table></body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
58
embed.go
Normal file
58
embed.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
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 rooted at assets/.
|
||||||
|
func Assets() fs.FS {
|
||||||
|
sub, _ := fs.Sub(assetsFS, "assets")
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schemas returns the embedded schemas filesystem rooted at schemas/.
|
||||||
|
func Schemas() fs.FS {
|
||||||
|
sub, _ := fs.Sub(schemasFS, "schemas")
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetsHandler returns an http.Handler that serves the embedded assets.
|
||||||
|
func AssetsHandler() http.Handler {
|
||||||
|
return http.FileServer(http.FS(Assets()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThemePresets returns the embedded theme presets JSON.
|
||||||
|
func ThemePresets() []byte { return presetsData }
|
||||||
|
|
||||||
|
// BundledFonts returns the embedded fonts manifest JSON ([] in this pass).
|
||||||
|
func BundledFonts() []byte { return fontsData }
|
||||||
|
|
||||||
|
// ThemeCSSManifest exposes the Art Deco utility CSS to the host Tailwind input.
|
||||||
|
func ThemeCSSManifest() *plugin.CSSManifest {
|
||||||
|
css, err := assetsFS.ReadFile("assets/style.css")
|
||||||
|
if err != nil {
|
||||||
|
return &plugin.CSSManifest{}
|
||||||
|
}
|
||||||
|
return &plugin.CSSManifest{
|
||||||
|
InputCSSAppend: string(css),
|
||||||
|
}
|
||||||
|
}
|
||||||
47
footer.go
Normal file
47
footer.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FooterBlockMeta defines the Art Deco footer block.
|
||||||
|
var FooterBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "footer",
|
||||||
|
Title: "Footer",
|
||||||
|
Description: "Centered Art Deco footer with gold rule, address, reservations email and optional social row.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// FooterData is the typed view for the footer component.
|
||||||
|
type FooterData struct {
|
||||||
|
Address string
|
||||||
|
ReservationsEmail string
|
||||||
|
ShowSocial bool
|
||||||
|
MenuName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FooterBlock renders the centered Art Deco footer.
|
||||||
|
// Content: {"address": "...", "reservationsEmail": "...", "showSocial": "true|false", "menuName": "..."}
|
||||||
|
func FooterBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
// showSocial is stored as a string select ("true"/"false"); also accept bool for flexibility.
|
||||||
|
showSocial := true
|
||||||
|
if b, ok := content["showSocial"].(bool); ok {
|
||||||
|
showSocial = b
|
||||||
|
} else if s := getString(content, "showSocial"); s != "" {
|
||||||
|
showSocial = s != "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
data := FooterData{
|
||||||
|
Address: getString(content, "address"),
|
||||||
|
ReservationsEmail: getString(content, "reservationsEmail"),
|
||||||
|
ShowSocial: showSocial,
|
||||||
|
MenuName: getString(content, "menuName"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = footerComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
59
footer.templ
Normal file
59
footer.templ
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// addressLines splits a multi-line address into individual lines for centered rendering.
|
||||||
|
func addressLines(addr string) []string {
|
||||||
|
if addr == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
lines := strings.Split(addr, "\n")
|
||||||
|
out := make([]string, 0, len(lines))
|
||||||
|
for _, line := range lines {
|
||||||
|
l := strings.TrimSpace(line)
|
||||||
|
if l != "" {
|
||||||
|
out = append(out, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// footerComponent renders the centered Art Deco footer.
|
||||||
|
templ footerComponent(data FooterData) {
|
||||||
|
<section data-block="art-deco:footer" class="py-12 deco-grain">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 text-center">
|
||||||
|
<hr class="deco-rule mb-8"/>
|
||||||
|
if len(addressLines(data.Address)) > 0 {
|
||||||
|
<address class="not-italic mb-4" style="color: hsl(var(--muted-foreground));">
|
||||||
|
for _, line := range addressLines(data.Address) {
|
||||||
|
<div>{ line }</div>
|
||||||
|
}
|
||||||
|
</address>
|
||||||
|
}
|
||||||
|
if data.ReservationsEmail != "" {
|
||||||
|
<p class="mb-4">
|
||||||
|
<a href={ templ.SafeURL("mailto:" + data.ReservationsEmail) } class="deco-link">{ data.ReservationsEmail }</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
if data.MenuName != "" {
|
||||||
|
<nav
|
||||||
|
aria-label="Footer"
|
||||||
|
class="deco-caps text-xs mb-4"
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>
|
||||||
|
<span>{ data.MenuName }</span>
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
if data.ShowSocial {
|
||||||
|
<div class="flex justify-center gap-4 mb-4" style="color: hsl(var(--primary));">
|
||||||
|
<span class="deco-caps text-xs" aria-hidden="true">Instagram</span>
|
||||||
|
<span aria-hidden="true">·</span>
|
||||||
|
<span class="deco-caps text-xs" aria-hidden="true">Facebook</span>
|
||||||
|
<span aria-hidden="true">·</span>
|
||||||
|
<span class="deco-caps text-xs" aria-hidden="true">LinkedIn</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<hr class="deco-rule mt-8"/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
149
footer_templ.go
Normal file
149
footer_templ.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// 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 "strings"
|
||||||
|
|
||||||
|
// addressLines splits a multi-line address into individual lines for centered rendering.
|
||||||
|
func addressLines(addr string) []string {
|
||||||
|
if addr == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
lines := strings.Split(addr, "\n")
|
||||||
|
out := make([]string, 0, len(lines))
|
||||||
|
for _, line := range lines {
|
||||||
|
l := strings.TrimSpace(line)
|
||||||
|
if l != "" {
|
||||||
|
out = append(out, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// footerComponent renders the centered Art Deco footer.
|
||||||
|
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, "<section data-block=\"art-deco:footer\" class=\"py-12 deco-grain\"><div class=\"max-w-3xl mx-auto px-4 text-center\"><hr class=\"deco-rule mb-8\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(addressLines(data.Address)) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<address class=\"not-italic mb-4\" style=\"color: hsl(var(--muted-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, line := range addressLines(data.Address) {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(line)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 29, Col: 17}
|
||||||
|
}
|
||||||
|
_, 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, 4, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</address>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.ReservationsEmail != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<p class=\"mb-4\"><a href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("mailto:" + data.ReservationsEmail))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 35, Col: 64}
|
||||||
|
}
|
||||||
|
_, 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, "\" class=\"deco-link\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.ReservationsEmail)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 35, Col: 109}
|
||||||
|
}
|
||||||
|
_, 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, "</a></p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.MenuName != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<nav aria-label=\"Footer\" class=\"deco-caps text-xs mb-4\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\"><span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.MenuName)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 44, Col: 26}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</span></nav>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.ShowSocial {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"flex justify-center gap-4 mb-4\" style=\"color: hsl(var(--primary));\"><span class=\"deco-caps text-xs\" aria-hidden=\"true\">Instagram</span> <span aria-hidden=\"true\">·</span> <span class=\"deco-caps text-xs\" aria-hidden=\"true\">Facebook</span> <span aria-hidden=\"true\">·</span> <span class=\"deco-caps text-xs\" aria-hidden=\"true\">LinkedIn</span></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<hr class=\"deco-rule mt-8\"></div></section>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
48
gallery_fan.go
Normal file
48
gallery_fan.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GalleryFanBlockMeta defines the mirrored fan gallery block.
|
||||||
|
var GalleryFanBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "gallery_fan",
|
||||||
|
Title: "Fan Gallery",
|
||||||
|
Description: "Mirrored gallery framed by sunburst — collapses to single column under 640px.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// GalleryImage is a single image in the gallery.
|
||||||
|
type GalleryImage struct {
|
||||||
|
Src string
|
||||||
|
Caption string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GalleryFanData is the typed view for the gallery component.
|
||||||
|
type GalleryFanData struct {
|
||||||
|
Images []GalleryImage
|
||||||
|
Columns int
|
||||||
|
}
|
||||||
|
|
||||||
|
// GalleryFanBlock renders a mirrored fan gallery.
|
||||||
|
// Content: {"images": [{"src": "...", "caption": "..."}], "columns": 3}
|
||||||
|
func GalleryFanBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
items := getSlice(content, "images")
|
||||||
|
images := make([]GalleryImage, 0, len(items))
|
||||||
|
for _, item := range items {
|
||||||
|
images = append(images, GalleryImage{
|
||||||
|
Src: getString(item, "src"),
|
||||||
|
Caption: getString(item, "caption"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
cols := getInt(content, "columns", 3)
|
||||||
|
cols = clampInt(cols, 2, 4)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = galleryFanComponent(GalleryFanData{Images: images, Columns: cols}).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
54
gallery_fan.templ
Normal file
54
gallery_fan.templ
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// galleryFanGridCols maps the column count to a tailwind grid class with single-column collapse below 640px.
|
||||||
|
func galleryFanGridCols(cols int) string {
|
||||||
|
switch cols {
|
||||||
|
case 2:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2"
|
||||||
|
case 4:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
|
||||||
|
default:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallbackImage returns a tiny transparent svg data URI used when no image src is supplied.
|
||||||
|
func fallbackImage() string {
|
||||||
|
return "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E"
|
||||||
|
}
|
||||||
|
|
||||||
|
// galleryFanComponent renders the mirrored gallery framed by sunburst rays.
|
||||||
|
templ galleryFanComponent(data GalleryFanData) {
|
||||||
|
<section data-block="art-deco:gallery_fan" class="py-16">
|
||||||
|
<div class="max-w-6xl mx-auto px-4">
|
||||||
|
<div class="relative deco-grain">
|
||||||
|
<div class="absolute inset-x-0 -top-2 h-12 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
||||||
|
<div class={ "grid gap-4 pt-12", galleryFanGridCols(data.Columns) }>
|
||||||
|
if len(data.Images) == 0 {
|
||||||
|
<div class="col-span-full text-center text-sm py-12" style="color: hsl(var(--muted-foreground));">
|
||||||
|
Add images to populate the fan gallery.
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
for _, img := range data.Images {
|
||||||
|
<figure class="deco-step">
|
||||||
|
if img.Src != "" {
|
||||||
|
<img src={ img.Src } alt={ img.Caption } class="block w-full h-auto object-cover" style="background-color: hsl(var(--muted));"/>
|
||||||
|
} else {
|
||||||
|
<img src={ fallbackImage() } alt="" class="block w-full h-auto" style="background-color: hsl(var(--muted));"/>
|
||||||
|
}
|
||||||
|
if img.Caption != "" {
|
||||||
|
<figcaption
|
||||||
|
class="mt-2 text-center italic text-sm"
|
||||||
|
style="color: hsl(var(--muted-foreground));"
|
||||||
|
>
|
||||||
|
{ img.Caption }
|
||||||
|
</figcaption>
|
||||||
|
}
|
||||||
|
</figure>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="absolute inset-x-0 -bottom-2 h-12 pointer-events-none deco-sunburst rotate-180" aria-hidden="true"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
169
gallery_fan_templ.go
Normal file
169
gallery_fan_templ.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// galleryFanGridCols maps the column count to a tailwind grid class with single-column collapse below 640px.
|
||||||
|
func galleryFanGridCols(cols int) string {
|
||||||
|
switch cols {
|
||||||
|
case 2:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2"
|
||||||
|
case 4:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
|
||||||
|
default:
|
||||||
|
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallbackImage returns a tiny transparent svg data URI used when no image src is supplied.
|
||||||
|
func fallbackImage() string {
|
||||||
|
return "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E"
|
||||||
|
}
|
||||||
|
|
||||||
|
// galleryFanComponent renders the mirrored gallery framed by sunburst rays.
|
||||||
|
func galleryFanComponent(data GalleryFanData) 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=\"art-deco:gallery_fan\" class=\"py-16\"><div class=\"max-w-6xl mx-auto px-4\"><div class=\"relative deco-grain\"><div class=\"absolute inset-x-0 -top-2 h-12 pointer-events-none deco-sunburst\" aria-hidden=\"true\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 = []any{"grid gap-4 pt-12", galleryFanGridCols(data.Columns)}
|
||||||
|
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, 2, "<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: `gallery_fan.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, 3, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(data.Images) == 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"col-span-full text-center text-sm py-12\" style=\"color: hsl(var(--muted-foreground));\">Add images to populate the fan gallery.</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, img := range data.Images {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<figure class=\"deco-step\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if img.Src != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<img src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(img.Src)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `gallery_fan.templ`, Line: 35, Col: 26}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" alt=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(img.Caption)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `gallery_fan.templ`, Line: 35, Col: 46}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" class=\"block w-full h-auto object-cover\" style=\"background-color: hsl(var(--muted));\"> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<img src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(fallbackImage())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `gallery_fan.templ`, Line: 37, Col: 34}
|
||||||
|
}
|
||||||
|
_, 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, "\" alt=\"\" class=\"block w-full h-auto\" style=\"background-color: hsl(var(--muted));\"> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if img.Caption != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<figcaption class=\"mt-2 text-center italic text-sm\" style=\"color: hsl(var(--muted-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(img.Caption)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `gallery_fan.templ`, Line: 44, Col: 22}
|
||||||
|
}
|
||||||
|
_, 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, 12, "</figcaption>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</figure>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div><div class=\"absolute inset-x-0 -bottom-2 h-12 pointer-events-none deco-sunburst rotate-180\" aria-hidden=\"true\"></div></div></div></section>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
20
go.mod
Normal file
20
go.mod
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module git.dev.alexdunmow.com/block/themes/art-deco
|
||||||
|
|
||||||
|
go 1.26.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.dev.alexdunmow.com/block/core v0.15.2
|
||||||
|
github.com/a-h/templ v0.3.1020
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
connectrpc.com/connect v1.20.0 // indirect
|
||||||
|
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.9.2 // indirect
|
||||||
|
golang.org/x/mod v0.34.0 // indirect
|
||||||
|
golang.org/x/text v0.36.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
)
|
||||||
46
go.sum
Normal file
46
go.sum
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
||||||
|
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
||||||
|
git.dev.alexdunmow.com/block/core v0.15.2 h1:qTjJxa1pClxwehkdTxXiJDpHQLr5DoXBUCa40QRO0L8=
|
||||||
|
git.dev.alexdunmow.com/block/core v0.15.2/go.mod h1:A+mgA9oeWoPhXruv4Mjpywwl2A9B5I3cKzlJjalBdlE=
|
||||||
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
|
||||||
|
github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
|
||||||
|
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
|
||||||
|
github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
|
||||||
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||||
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
44
heading_override.go
Normal file
44
heading_override.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseHeadingLevel reads "level" from a content map, defaulting to 2 and clamping to 1..6.
|
||||||
|
func parseHeadingLevel(content map[string]any) int {
|
||||||
|
if v, ok := content["level"].(float64); ok {
|
||||||
|
return clampInt(int(v), 1, 6)
|
||||||
|
}
|
||||||
|
if v, ok := content["level"].(int); ok {
|
||||||
|
return clampInt(v, 1, 6)
|
||||||
|
}
|
||||||
|
if v, ok := content["level"].(string); ok {
|
||||||
|
if i, err := strconv.Atoi(v); err == nil {
|
||||||
|
return clampInt(i, 1, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoHeadingBlock overrides the built-in "heading" block when the Art Deco theme is active.
|
||||||
|
// Content: {"text": "...", "level": 1-6, "textClass": "optional-utility-classes"}
|
||||||
|
func ArtDecoHeadingBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := HeadingData{
|
||||||
|
Text: getString(content, "text"),
|
||||||
|
Level: parseHeadingLevel(content),
|
||||||
|
ExtraCls: getString(content, "textClass"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoHeadingComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadingData is the typed view for the heading override component.
|
||||||
|
type HeadingData struct {
|
||||||
|
Text string
|
||||||
|
Level int
|
||||||
|
ExtraCls string
|
||||||
|
}
|
||||||
69
heading_override.templ
Normal file
69
heading_override.templ
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// headingSizeClass returns the responsive size utility for a given heading level.
|
||||||
|
func headingSizeClass(level int) string {
|
||||||
|
switch level {
|
||||||
|
case 1:
|
||||||
|
return "text-4xl md:text-5xl"
|
||||||
|
case 2:
|
||||||
|
return "text-3xl md:text-4xl"
|
||||||
|
case 3:
|
||||||
|
return "text-2xl md:text-3xl"
|
||||||
|
case 4:
|
||||||
|
return "text-xl md:text-2xl"
|
||||||
|
case 5:
|
||||||
|
return "text-lg md:text-xl"
|
||||||
|
case 6:
|
||||||
|
return "text-base md:text-lg"
|
||||||
|
default:
|
||||||
|
return "text-3xl md:text-4xl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoHeadingComponent renders an Art Deco heading with caps tracking and hairline gold underline.
|
||||||
|
templ artDecoHeadingComponent(data HeadingData) {
|
||||||
|
switch data.Level {
|
||||||
|
case 1:
|
||||||
|
<h1
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(1), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h1>
|
||||||
|
case 2:
|
||||||
|
<h2
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(2), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h2>
|
||||||
|
case 3:
|
||||||
|
<h3
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(3), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h3>
|
||||||
|
case 4:
|
||||||
|
<h4
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(4), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h4>
|
||||||
|
case 5:
|
||||||
|
<h5
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(5), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h5>
|
||||||
|
case 6:
|
||||||
|
<h6
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(6), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h6>
|
||||||
|
default:
|
||||||
|
<h2
|
||||||
|
data-block-override="art-deco:heading"
|
||||||
|
class={ "deco-caps deco-underline", headingSizeClass(2), data.ExtraCls }
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>{ data.Text }</h2>
|
||||||
|
}
|
||||||
|
}
|
||||||
311
heading_override_templ.go
Normal file
311
heading_override_templ.go
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// headingSizeClass returns the responsive size utility for a given heading level.
|
||||||
|
func headingSizeClass(level int) string {
|
||||||
|
switch level {
|
||||||
|
case 1:
|
||||||
|
return "text-4xl md:text-5xl"
|
||||||
|
case 2:
|
||||||
|
return "text-3xl md:text-4xl"
|
||||||
|
case 3:
|
||||||
|
return "text-2xl md:text-3xl"
|
||||||
|
case 4:
|
||||||
|
return "text-xl md:text-2xl"
|
||||||
|
case 5:
|
||||||
|
return "text-lg md:text-xl"
|
||||||
|
case 6:
|
||||||
|
return "text-base md:text-lg"
|
||||||
|
default:
|
||||||
|
return "text-3xl md:text-4xl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoHeadingComponent renders an Art Deco heading with caps tracking and hairline gold underline.
|
||||||
|
func artDecoHeadingComponent(data HeadingData) 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 data.Level {
|
||||||
|
case 1:
|
||||||
|
var templ_7745c5c3_Var2 = []any{"deco-caps deco-underline", headingSizeClass(1), data.ExtraCls}
|
||||||
|
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 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 31, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h1>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
var templ_7745c5c3_Var5 = []any{"deco-caps deco-underline", headingSizeClass(2), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h2 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var5).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 37, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</h2>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
var templ_7745c5c3_Var8 = []any{"deco-caps deco-underline", headingSizeClass(3), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<h3 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var8).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var10 string
|
||||||
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 43, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</h3>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
var templ_7745c5c3_Var11 = []any{"deco-caps deco-underline", headingSizeClass(4), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<h4 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var12 string
|
||||||
|
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var11).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var13 string
|
||||||
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 49, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</h4>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
var templ_7745c5c3_Var14 = []any{"deco-caps deco-underline", headingSizeClass(5), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<h5 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var15 string
|
||||||
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var14).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var16 string
|
||||||
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 55, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</h5>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
case 6:
|
||||||
|
var templ_7745c5c3_Var17 = []any{"deco-caps deco-underline", headingSizeClass(6), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<h6 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var17).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var19 string
|
||||||
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 61, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</h6>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
var templ_7745c5c3_Var20 = []any{"deco-caps deco-underline", headingSizeClass(2), data.ExtraCls}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var20...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<h2 data-block-override=\"art-deco:heading\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var21 string
|
||||||
|
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var20).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var22 string
|
||||||
|
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(data.Text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 67, Col: 15}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</h2>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
59
helpers.go
Normal file
59
helpers.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// getString extracts a string value from a content map.
|
||||||
|
func getString(content map[string]any, key string) string {
|
||||||
|
if v, ok := content[key].(string); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// getInt extracts an int value from a content map (handles float64 from JSON).
|
||||||
|
func getInt(content map[string]any, key string, defaultVal int) int {
|
||||||
|
if v, ok := content[key].(float64); ok {
|
||||||
|
return int(v)
|
||||||
|
}
|
||||||
|
if v, ok := content[key].(int); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSlice extracts a slice of maps from a content map.
|
||||||
|
func getSlice(content map[string]any, key string) []map[string]any {
|
||||||
|
if v, ok := content[key].([]any); ok {
|
||||||
|
result := make([]map[string]any, 0, len(v))
|
||||||
|
for _, item := range v {
|
||||||
|
if m, ok := item.(map[string]any); ok {
|
||||||
|
result = append(result, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getStringSlice extracts a slice of strings from a content map.
|
||||||
|
func getStringSlice(content map[string]any, key string) []string {
|
||||||
|
if v, ok := content[key].([]any); ok {
|
||||||
|
result := make([]string, 0, len(v))
|
||||||
|
for _, item := range v {
|
||||||
|
if s, ok := item.(string); ok {
|
||||||
|
result = append(result, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// clampInt clamps an int into [min, max] inclusive.
|
||||||
|
func clampInt(v, min, max int) int {
|
||||||
|
if v < min {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
if v > max {
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
43
image_override.go
Normal file
43
image_override.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageOverrideData is the typed view for the image override component.
|
||||||
|
type ImageOverrideData struct {
|
||||||
|
Src string
|
||||||
|
Alt string
|
||||||
|
Caption string
|
||||||
|
Frame string
|
||||||
|
}
|
||||||
|
|
||||||
|
// normaliseImageFrame clamps the frame option to the supported set.
|
||||||
|
func normaliseImageFrame(v string) string {
|
||||||
|
switch v {
|
||||||
|
case "stepped", "scallop", "plain":
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return "stepped"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoImageBlock overrides the built-in "image" block when the Art Deco theme is active.
|
||||||
|
// Content: {"src": "...", "alt": "...", "caption": "...", "frame": "stepped|scallop|plain"}
|
||||||
|
func ArtDecoImageBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := ImageOverrideData{
|
||||||
|
Src: getString(content, "src"),
|
||||||
|
Alt: getString(content, "alt"),
|
||||||
|
Caption: getString(content, "caption"),
|
||||||
|
Frame: normaliseImageFrame(getString(content, "frame")),
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Src == "" {
|
||||||
|
data.Src = fallbackImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoImageComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
30
image_override.templ
Normal file
30
image_override.templ
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// imageFrameClass returns the utility class for an image frame option.
|
||||||
|
func imageFrameClass(frame string) string {
|
||||||
|
switch frame {
|
||||||
|
case "scallop":
|
||||||
|
return "deco-scallop"
|
||||||
|
case "plain":
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "deco-step"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoImageComponent renders an image wrapped in the stepped ziggurat frame option.
|
||||||
|
templ artDecoImageComponent(data ImageOverrideData) {
|
||||||
|
<figure data-block-override="art-deco:image" class="my-8">
|
||||||
|
<div class={ imageFrameClass(data.Frame) }>
|
||||||
|
<img src={ data.Src } alt={ data.Alt } class="block w-full h-auto"/>
|
||||||
|
</div>
|
||||||
|
if data.Caption != "" {
|
||||||
|
<figcaption
|
||||||
|
class="mt-2 italic text-center text-sm"
|
||||||
|
style="color: hsl(var(--muted-foreground));"
|
||||||
|
>
|
||||||
|
{ data.Caption }
|
||||||
|
</figcaption>
|
||||||
|
}
|
||||||
|
</figure>
|
||||||
|
}
|
||||||
124
image_override_templ.go
Normal file
124
image_override_templ.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// imageFrameClass returns the utility class for an image frame option.
|
||||||
|
func imageFrameClass(frame string) string {
|
||||||
|
switch frame {
|
||||||
|
case "scallop":
|
||||||
|
return "deco-scallop"
|
||||||
|
case "plain":
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "deco-step"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// artDecoImageComponent renders an image wrapped in the stepped ziggurat frame option.
|
||||||
|
func artDecoImageComponent(data ImageOverrideData) 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 data-block-override=\"art-deco:image\" class=\"my-8\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 = []any{imageFrameClass(data.Frame)}
|
||||||
|
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, 2, "<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: `image_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, 3, "\"><img src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Src)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 19, Col: 22}
|
||||||
|
}
|
||||||
|
_, 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, 4, "\" alt=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Alt)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 19, Col: 39}
|
||||||
|
}
|
||||||
|
_, 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, 5, "\" class=\"block w-full h-auto\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Caption != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<figcaption class=\"mt-2 italic text-center text-sm\" style=\"color: hsl(var(--muted-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Caption)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `image_override.templ`, Line: 26, Col: 18}
|
||||||
|
}
|
||||||
|
_, 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, 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
|
||||||
17
main.go
Normal file
17
main.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//go:build wasip1
|
||||||
|
|
||||||
|
// Package main compiles the Art Deco theme to a wasip1 reactor-mode wasm guest
|
||||||
|
// (WO-WZ-015). The .so build path is retired; `ninja plugin build` produces the
|
||||||
|
// .bnp artifact the registry serves.
|
||||||
|
//
|
||||||
|
// Reactor mode: the host runs `_initialize` once per pooled instance, which
|
||||||
|
// runs this init func (hence wasmguest.Serve) before any bn_invoke. Serve is
|
||||||
|
// non-blocking; all theme work then arrives over the ABI hook calls. main is
|
||||||
|
// never called.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "git.dev.alexdunmow.com/block/core/plugin/wasmguest"
|
||||||
|
|
||||||
|
func init() { wasmguest.Serve(Registration) }
|
||||||
|
|
||||||
|
func main() {} // never called — reactor mode
|
||||||
256
manifest.yaml
256
manifest.yaml
@ -1,256 +0,0 @@
|
|||||||
# Art Deco theme — codeless .bnp manifest (WO-WZ-021 Phase B).
|
|
||||||
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
|
|
||||||
theme_presets: presets.json
|
|
||||||
bundled_fonts: fonts.json
|
|
||||||
master_pages: master_pages.json
|
|
||||||
|
|
||||||
system_templates:
|
|
||||||
- key: art-deco
|
|
||||||
title: Art Deco
|
|
||||||
description: "Luxury Art Deco theme with champagne gold gradients, jet black, ivory and geometric fan motifs for hotels, fine dining, weddings and jewellers."
|
|
||||||
|
|
||||||
page_templates:
|
|
||||||
- system: art-deco
|
|
||||||
key: default
|
|
||||||
title: Default
|
|
||||||
description: "Centered symmetric layout with gold rule header and footer."
|
|
||||||
slots: [header, main, footer]
|
|
||||||
- system: art-deco
|
|
||||||
key: landing
|
|
||||||
title: Marquee Landing
|
|
||||||
description: "Wide hero with sunburst overlay, reservation strip, CTA."
|
|
||||||
slots: [marquee, main, cta, footer]
|
|
||||||
- system: art-deco
|
|
||||||
key: article
|
|
||||||
title: Editorial
|
|
||||||
description: "Narrow editorial column for press, menus and stories."
|
|
||||||
slots: [header, main, aside, footer]
|
|
||||||
- system: art-deco
|
|
||||||
key: full-width
|
|
||||||
title: Grand Ballroom
|
|
||||||
description: "Edge-to-edge gallery layout for venues and lookbooks."
|
|
||||||
slots: [header, main, footer]
|
|
||||||
|
|
||||||
template_overrides:
|
|
||||||
- { template: art-deco, block: heading }
|
|
||||||
- { template: art-deco, block: text }
|
|
||||||
- { template: art-deco, block: button }
|
|
||||||
- { template: art-deco, block: image }
|
|
||||||
|
|
||||||
email_wrappers:
|
|
||||||
- art-deco
|
|
||||||
|
|
||||||
css:
|
|
||||||
input_css_append: |
|
|
||||||
/* Art Deco theme — utility CSS for foil, frames, fans and grain.
|
|
||||||
*
|
|
||||||
* Color is always consumed via hsl(var(--token)) — the tokens carry HSL triples.
|
|
||||||
* Font families always come from var(--font-heading|body|mono, <fallback>).
|
|
||||||
*/
|
|
||||||
|
|
||||||
@layer utilities {
|
|
||||||
/* deco-rule — hairline gold rule, 1px ascending to 2px on accent lines. */
|
|
||||||
.deco-rule {
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid hsl(var(--primary));
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.deco-rule-thick {
|
|
||||||
border: none;
|
|
||||||
border-top: 2px solid hsl(var(--primary));
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-frame — stepped ziggurat frame, layered borders + clipped corners. */
|
|
||||||
.deco-frame {
|
|
||||||
position: relative;
|
|
||||||
border: 1px solid hsl(var(--primary));
|
|
||||||
padding: 1.25rem;
|
|
||||||
}
|
|
||||||
.deco-frame::before,
|
|
||||||
.deco-frame::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: -6px;
|
|
||||||
right: -6px;
|
|
||||||
height: 4px;
|
|
||||||
background: hsl(var(--primary));
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
.deco-frame::before { top: -6px; }
|
|
||||||
.deco-frame::after { bottom: -6px; }
|
|
||||||
|
|
||||||
/* deco-step — stepped corner mask suitable for image frames. */
|
|
||||||
.deco-step {
|
|
||||||
position: relative;
|
|
||||||
padding: 4px;
|
|
||||||
background:
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) top left / 14px 1px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) top left / 1px 14px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) top right / 14px 1px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) top right / 1px 14px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) bottom left / 14px 1px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) bottom left / 1px 14px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) bottom right / 14px 1px no-repeat,
|
|
||||||
linear-gradient(hsl(var(--primary)), hsl(var(--primary))) bottom right / 1px 14px no-repeat;
|
|
||||||
}
|
|
||||||
.deco-step > * {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-grain — 3% film-grain noise, dark surfaces only. */
|
|
||||||
.deco-grain {
|
|
||||||
position: relative;
|
|
||||||
isolation: isolate;
|
|
||||||
}
|
|
||||||
.deco-grain::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0.03;
|
|
||||||
background-image:
|
|
||||||
repeating-radial-gradient(circle at 17% 23%, hsl(var(--foreground)) 0 1px, transparent 1px 3px),
|
|
||||||
repeating-radial-gradient(circle at 73% 61%, hsl(var(--foreground)) 0 1px, transparent 1px 3px);
|
|
||||||
mix-blend-mode: overlay;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-foil — inset gold "stamp" shadow used on hover states. */
|
|
||||||
.deco-foil {
|
|
||||||
box-shadow:
|
|
||||||
inset 0 0 0 1px hsl(var(--primary)),
|
|
||||||
inset 0 1px 0 hsl(var(--primary) / 0.6),
|
|
||||||
inset 0 -1px 0 hsl(var(--primary) / 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-sunburst — conic-gradient sunburst rays. Used by divider_fan & marquee_hero. */
|
|
||||||
.deco-sunburst {
|
|
||||||
background-image:
|
|
||||||
conic-gradient(
|
|
||||||
from 180deg at 50% 100%,
|
|
||||||
transparent 0deg,
|
|
||||||
hsl(var(--primary) / 0.7) 5deg,
|
|
||||||
transparent 10deg,
|
|
||||||
transparent 20deg,
|
|
||||||
hsl(var(--primary) / 0.55) 25deg,
|
|
||||||
transparent 30deg,
|
|
||||||
transparent 40deg,
|
|
||||||
hsl(var(--primary) / 0.7) 45deg,
|
|
||||||
transparent 50deg,
|
|
||||||
transparent 60deg,
|
|
||||||
hsl(var(--primary) / 0.55) 65deg,
|
|
||||||
transparent 70deg,
|
|
||||||
transparent 80deg,
|
|
||||||
hsl(var(--primary) / 0.7) 85deg,
|
|
||||||
transparent 90deg,
|
|
||||||
transparent 100deg,
|
|
||||||
hsl(var(--primary) / 0.55) 105deg,
|
|
||||||
transparent 110deg,
|
|
||||||
transparent 120deg,
|
|
||||||
hsl(var(--primary) / 0.7) 125deg,
|
|
||||||
transparent 130deg,
|
|
||||||
transparent 140deg,
|
|
||||||
hsl(var(--primary) / 0.55) 145deg,
|
|
||||||
transparent 150deg,
|
|
||||||
transparent 160deg,
|
|
||||||
hsl(var(--primary) / 0.7) 165deg,
|
|
||||||
transparent 170deg,
|
|
||||||
transparent 180deg
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-scallop — scalloped fan crest via radial gradient. */
|
|
||||||
.deco-scallop {
|
|
||||||
background-image:
|
|
||||||
radial-gradient(circle at 50% 100%, hsl(var(--primary) / 0.7) 0 2px, transparent 3px),
|
|
||||||
repeating-linear-gradient(
|
|
||||||
to right,
|
|
||||||
transparent 0,
|
|
||||||
transparent 12px,
|
|
||||||
hsl(var(--primary) / 0.55) 12px,
|
|
||||||
hsl(var(--primary) / 0.55) 13px,
|
|
||||||
transparent 13px,
|
|
||||||
transparent 24px
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-ziggurat — stepped ziggurat divider stripes. */
|
|
||||||
.deco-ziggurat {
|
|
||||||
background-image:
|
|
||||||
linear-gradient(to bottom, transparent 0 30%, hsl(var(--primary)) 30% 32%, transparent 32% 50%, hsl(var(--primary)) 50% 52%, transparent 52% 70%, hsl(var(--primary)) 70% 72%, transparent 72% 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-caps — caps tracking helper for Italiana display headings. */
|
|
||||||
.deco-caps {
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.18em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-dropcap — classical italic dropcap on first paragraph. */
|
|
||||||
.deco-dropcap[data-deco-dropcap]::first-letter {
|
|
||||||
font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 0.95;
|
|
||||||
float: left;
|
|
||||||
padding: 0.05em 0.12em 0 0;
|
|
||||||
color: hsl(var(--primary));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-underline — hairline gold underline on headings. */
|
|
||||||
.deco-underline {
|
|
||||||
position: relative;
|
|
||||||
padding-bottom: 0.35em;
|
|
||||||
}
|
|
||||||
.deco-underline::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
height: 1px;
|
|
||||||
background: hsl(var(--primary));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-pill — black pill button base for the button override. */
|
|
||||||
.deco-pill {
|
|
||||||
border-radius: 9999px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: hsl(var(--primary));
|
|
||||||
background-color: hsl(var(--foreground));
|
|
||||||
color: hsl(var(--background));
|
|
||||||
padding: 0.65rem 1.6rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.18em;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
transition: box-shadow 200ms ease, background-color 200ms ease;
|
|
||||||
}
|
|
||||||
.deco-pill:hover,
|
|
||||||
.deco-pill:focus-visible {
|
|
||||||
box-shadow:
|
|
||||||
inset 0 0 0 1px hsl(var(--primary)),
|
|
||||||
inset 0 1px 0 hsl(var(--primary) / 0.6),
|
|
||||||
inset 0 -1px 0 hsl(var(--primary) / 0.4);
|
|
||||||
}
|
|
||||||
.deco-pill:focus-visible {
|
|
||||||
outline: 2px solid hsl(var(--ring));
|
|
||||||
outline-offset: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deco-link — gold underline link state. */
|
|
||||||
.deco-link {
|
|
||||||
color: hsl(var(--primary));
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: 1px solid hsl(var(--primary));
|
|
||||||
transition: color 200ms ease, border-color 200ms ease;
|
|
||||||
}
|
|
||||||
.deco-link:hover,
|
|
||||||
.deco-link:focus-visible {
|
|
||||||
color: hsl(var(--accent));
|
|
||||||
border-bottom-color: hsl(var(--accent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
43
marquee_hero.go
Normal file
43
marquee_hero.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarqueeHeroBlockMeta defines the marquee hero block.
|
||||||
|
var MarqueeHeroBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "marquee_hero",
|
||||||
|
Title: "Marquee Hero",
|
||||||
|
Description: "Wide hero with stepped ziggurat frame and sunburst overlay.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarqueeHeroData is the typed view for the marquee hero component.
|
||||||
|
type MarqueeHeroData struct {
|
||||||
|
Eyebrow string
|
||||||
|
Title string
|
||||||
|
Subtitle string
|
||||||
|
CTALabel string
|
||||||
|
CTAHref string
|
||||||
|
Image string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarqueeHeroBlock renders the wide hero with stepped frame and sunburst overlay.
|
||||||
|
// Content: {"eyebrow": "...", "title": "...", "subtitle": "...", "ctaLabel": "...", "ctaHref": "...", "image": "..."}
|
||||||
|
func MarqueeHeroBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := MarqueeHeroData{
|
||||||
|
Eyebrow: getString(content, "eyebrow"),
|
||||||
|
Title: getString(content, "title"),
|
||||||
|
Subtitle: getString(content, "subtitle"),
|
||||||
|
CTALabel: getString(content, "ctaLabel"),
|
||||||
|
CTAHref: getString(content, "ctaHref"),
|
||||||
|
Image: getString(content, "image"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = marqueeHeroComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
42
marquee_hero.templ
Normal file
42
marquee_hero.templ
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// marqueeHeroComponent renders the wide hero with stepped ziggurat frame and sunburst overlay.
|
||||||
|
templ marqueeHeroComponent(data MarqueeHeroData) {
|
||||||
|
<section data-block="art-deco:marquee_hero" class="relative w-full overflow-hidden deco-grain" style="background-color: hsl(var(--foreground)); color: hsl(var(--background));">
|
||||||
|
if data.Image != "" {
|
||||||
|
<div class="absolute inset-0 z-0" aria-hidden="true">
|
||||||
|
<img src={ data.Image } alt="" class="w-full h-full object-cover" style="opacity: 0.5;"/>
|
||||||
|
<div class="absolute inset-0" style="background-color: hsl(var(--foreground) / 0.55);"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="absolute inset-x-0 top-0 h-24 z-10 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
||||||
|
<div class="relative z-20 max-w-4xl mx-auto px-4 py-32 text-center">
|
||||||
|
<div class="deco-frame inline-block px-12 py-10" style="background-color: hsl(var(--foreground) / 0.6); border-color: hsl(var(--primary));">
|
||||||
|
if data.Eyebrow != "" {
|
||||||
|
<p class="deco-caps mb-4 text-xs" style="color: hsl(var(--primary));">{ data.Eyebrow }</p>
|
||||||
|
}
|
||||||
|
if data.Title != "" {
|
||||||
|
<h1
|
||||||
|
class="deco-caps deco-underline mb-6 text-5xl md:text-6xl lg:text-7xl"
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--background));"
|
||||||
|
>
|
||||||
|
{ data.Title }
|
||||||
|
</h1>
|
||||||
|
}
|
||||||
|
if data.Subtitle != "" {
|
||||||
|
<div
|
||||||
|
class="text-lg md:text-xl mb-8 max-w-2xl mx-auto"
|
||||||
|
style="color: hsl(var(--background) / 0.9);"
|
||||||
|
>
|
||||||
|
@templ.Raw(data.Subtitle)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
if data.CTALabel != "" && data.CTAHref != "" {
|
||||||
|
<a href={ templ.SafeURL(data.CTAHref) } class="deco-pill" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));">
|
||||||
|
{ data.CTALabel }
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
152
marquee_hero_templ.go
Normal file
152
marquee_hero_templ.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// marqueeHeroComponent renders the wide hero with stepped ziggurat frame and sunburst overlay.
|
||||||
|
func marqueeHeroComponent(data MarqueeHeroData) 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=\"art-deco:marquee_hero\" class=\"relative w-full overflow-hidden deco-grain\" style=\"background-color: hsl(var(--foreground)); color: hsl(var(--background));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Image != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"absolute inset-0 z-0\" aria-hidden=\"true\"><img src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Image)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `marquee_hero.templ`, Line: 8, Col: 25}
|
||||||
|
}
|
||||||
|
_, 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=\"\" class=\"w-full h-full object-cover\" style=\"opacity: 0.5;\"><div class=\"absolute inset-0\" style=\"background-color: hsl(var(--foreground) / 0.55);\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"absolute inset-x-0 top-0 h-24 z-10 pointer-events-none deco-sunburst\" aria-hidden=\"true\"></div><div class=\"relative z-20 max-w-4xl mx-auto px-4 py-32 text-center\"><div class=\"deco-frame inline-block px-12 py-10\" style=\"background-color: hsl(var(--foreground) / 0.6); border-color: hsl(var(--primary));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Eyebrow != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<p class=\"deco-caps mb-4 text-xs\" style=\"color: hsl(var(--primary));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Eyebrow)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `marquee_hero.templ`, Line: 16, Col: 89}
|
||||||
|
}
|
||||||
|
_, 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, "</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.Title != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<h1 class=\"deco-caps deco-underline mb-6 text-5xl md:text-6xl lg:text-7xl\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--background));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `marquee_hero.templ`, Line: 23, Col: 18}
|
||||||
|
}
|
||||||
|
_, 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, "</h1>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.Subtitle != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"text-lg md:text-xl mb-8 max-w-2xl mx-auto\" style=\"color: hsl(var(--background) / 0.9);\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(data.Subtitle).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 data.CTALabel != "" && data.CTAHref != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<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(data.CTAHref))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `marquee_hero.templ`, Line: 35, Col: 42}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" class=\"deco-pill\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.CTALabel)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `marquee_hero.templ`, Line: 36, Col: 21}
|
||||||
|
}
|
||||||
|
_, 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, "</a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div></div></section>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
@ -1,25 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"key": "art-deco:default-master",
|
|
||||||
"title": "Art Deco Default Master",
|
|
||||||
"page_templates": ["default", "article"],
|
|
||||||
"blocks": [
|
|
||||||
{ "block_key": "navbar", "title": "Brass Navigation", "content": { "menuName": "main" }, "slot": "header", "sort_order": 0 },
|
|
||||||
{ "block_key": "art-deco:divider_fan", "title": "Header Fan Divider", "content": { "variant": "sunburst" }, "slot": "header", "sort_order": 1 },
|
|
||||||
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main", "placeholder": "Page content" }, "slot": "main", "sort_order": 0 },
|
|
||||||
{ "block_key": "art-deco:footer", "title": "Site Footer", "content": { "address": "", "reservationsEmail": "", "showSocial": "true" }, "slot": "footer", "sort_order": 0 }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "art-deco:marquee-master",
|
|
||||||
"title": "Art Deco Marquee Master",
|
|
||||||
"page_templates": ["landing", "full-width"],
|
|
||||||
"blocks": [
|
|
||||||
{ "block_key": "navbar", "title": "Brass Navigation", "content": { "menuName": "main" }, "slot": "marquee", "sort_order": 0 },
|
|
||||||
{ "block_key": "art-deco:reservation", "title": "Reservation Strip", "content": { "phone": "", "openTable": "" }, "slot": "marquee", "sort_order": 1 },
|
|
||||||
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
|
|
||||||
{ "block_key": "art-deco:divider_fan", "title": "CTA Fan Divider", "content": { "variant": "scallop" }, "slot": "cta", "sort_order": 0 },
|
|
||||||
{ "block_key": "art-deco:footer", "title": "Site Footer", "content": { "showSocial": "true" }, "slot": "footer", "sort_order": 0 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
52
menu.go
Normal file
52
menu.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MenuBlockMeta defines the tasting menu block.
|
||||||
|
var MenuBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "menu",
|
||||||
|
Title: "Tasting Menu",
|
||||||
|
Description: "Symmetric two-column menu card listing courses with description and price.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuCourse is a single course on the menu.
|
||||||
|
type MenuCourse struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
Price string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuData is the typed view for the menu component.
|
||||||
|
type MenuData struct {
|
||||||
|
Title string
|
||||||
|
Courses []MenuCourse
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuBlock renders a tasting menu card.
|
||||||
|
// Content: {"title": "...", "courses": [{"name": "...", "description": "...", "price": "..."}]}
|
||||||
|
func MenuBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
items := getSlice(content, "courses")
|
||||||
|
courses := make([]MenuCourse, 0, len(items))
|
||||||
|
for _, item := range items {
|
||||||
|
courses = append(courses, MenuCourse{
|
||||||
|
Name: getString(item, "name"),
|
||||||
|
Description: getString(item, "description"),
|
||||||
|
Price: getString(item, "price"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := MenuData{
|
||||||
|
Title: getString(content, "title"),
|
||||||
|
Courses: courses,
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = menuComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
50
menu.templ
Normal file
50
menu.templ
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// menuComponent renders the symmetric two-column menu card.
|
||||||
|
templ menuComponent(data MenuData) {
|
||||||
|
<section data-block="art-deco:menu" class="py-16">
|
||||||
|
<div class="max-w-3xl mx-auto px-4">
|
||||||
|
<div class="deco-frame text-center" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground));">
|
||||||
|
if data.Title != "" {
|
||||||
|
<h2
|
||||||
|
class="deco-caps deco-underline mb-8 text-3xl md:text-4xl"
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>
|
||||||
|
{ data.Title }
|
||||||
|
</h2>
|
||||||
|
}
|
||||||
|
if len(data.Courses) == 0 {
|
||||||
|
<p class="text-muted-foreground" style="color: hsl(var(--muted-foreground));">Add courses to start composing this menu.</p>
|
||||||
|
} else {
|
||||||
|
<ul class="space-y-6 text-left">
|
||||||
|
for _, course := range data.Courses {
|
||||||
|
<li class="flex items-start justify-between gap-6 border-b" style="border-color: hsl(var(--border));">
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3
|
||||||
|
class="deco-caps text-lg"
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>
|
||||||
|
{ course.Name }
|
||||||
|
</h3>
|
||||||
|
if course.Description != "" {
|
||||||
|
<div class="mt-1 italic" style="color: hsl(var(--muted-foreground));">
|
||||||
|
@templ.Raw(course.Description)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
if course.Price != "" {
|
||||||
|
<span
|
||||||
|
class="deco-caps text-base"
|
||||||
|
style="font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); color: hsl(var(--primary));"
|
||||||
|
>
|
||||||
|
{ course.Price }
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
139
menu_templ.go
Normal file
139
menu_templ.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// menuComponent renders the symmetric two-column menu card.
|
||||||
|
func menuComponent(data MenuData) 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=\"art-deco:menu\" class=\"py-16\"><div class=\"max-w-3xl mx-auto px-4\"><div class=\"deco-frame text-center\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Title != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<h2 class=\"deco-caps deco-underline mb-8 text-3xl md:text-4xl\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `menu.templ`, Line: 13, Col: 18}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h2>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(data.Courses) == 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<p class=\"text-muted-foreground\" style=\"color: hsl(var(--muted-foreground));\">Add courses to start composing this menu.</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<ul class=\"space-y-6 text-left\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, course := range data.Courses {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<li class=\"flex items-start justify-between gap-6 border-b\" style=\"border-color: hsl(var(--border));\"><div class=\"flex-1\"><h3 class=\"deco-caps text-lg\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(course.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `menu.templ`, Line: 27, Col: 23}
|
||||||
|
}
|
||||||
|
_, 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, "</h3>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if course.Description != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div class=\"mt-1 italic\" style=\"color: hsl(var(--muted-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(course.Description).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
|
||||||
|
}
|
||||||
|
if course.Price != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<span class=\"deco-caps text-base\" style=\"font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); color: hsl(var(--primary));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(course.Price)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `menu.templ`, Line: 40, Col: 24}
|
||||||
|
}
|
||||||
|
_, 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, 12, "</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</ul>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></div></section>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
@ -2,8 +2,11 @@
|
|||||||
name = "art-deco"
|
name = "art-deco"
|
||||||
display_name = "Art Deco"
|
display_name = "Art Deco"
|
||||||
scope = "@themes"
|
scope = "@themes"
|
||||||
version = "0.2.0"
|
version = "0.1.2"
|
||||||
description = "Luxury Art Deco theme with champagne gold gradients, jet black, ivory and geometric fan motifs for hotels, fine dining, weddings and jewellers."
|
description = "Luxury Art Deco theme with champagne gold gradients, jet black, ivory and geometric fan motifs for hotels, fine dining, weddings and jewellers."
|
||||||
kind = "theme"
|
kind = "theme"
|
||||||
categories = ["templates"]
|
categories = ["templates"]
|
||||||
tags = ["luxury", "gold", "hospitality", "hotel", "wedding", "jewellery", "vintage", "glam", "fine-dining"]
|
tags = ["luxury", "gold", "hospitality", "hotel", "wedding", "jewellery", "vintage", "glam", "fine-dining"]
|
||||||
|
|
||||||
|
[compatibility]
|
||||||
|
block_core = ">=0.15.0 <0.16.0"
|
||||||
|
|||||||
39
press_quote.go
Normal file
39
press_quote.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PressQuoteBlockMeta defines the press quote block.
|
||||||
|
var PressQuoteBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "press_quote",
|
||||||
|
Title: "Press Quote",
|
||||||
|
Description: "Italic Cormorant pull-quote between fan dividers, optional star rating.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// PressQuoteData is the typed view for the press quote component.
|
||||||
|
type PressQuoteData struct {
|
||||||
|
Quote string
|
||||||
|
Source string
|
||||||
|
Stars int
|
||||||
|
}
|
||||||
|
|
||||||
|
// PressQuoteBlock renders the italic pull-quote framed by fan dividers.
|
||||||
|
// Content: {"quote": "...", "source": "...", "stars": 5}
|
||||||
|
func PressQuoteBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
stars := clampInt(getInt(content, "stars", 0), 0, 5)
|
||||||
|
|
||||||
|
data := PressQuoteData{
|
||||||
|
Quote: getString(content, "quote"),
|
||||||
|
Source: getString(content, "source"),
|
||||||
|
Stars: stars,
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = pressQuoteComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
39
press_quote.templ
Normal file
39
press_quote.templ
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// pressQuoteComponent renders the italic Cormorant pull-quote between fan dividers.
|
||||||
|
templ pressQuoteComponent(data PressQuoteData) {
|
||||||
|
<section data-block="art-deco:press_quote" class="py-16">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 text-center">
|
||||||
|
<div class="h-6 mb-6 deco-sunburst" aria-hidden="true"></div>
|
||||||
|
<blockquote
|
||||||
|
class="italic text-2xl md:text-3xl leading-snug"
|
||||||
|
style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); font-style: italic; color: hsl(var(--foreground));"
|
||||||
|
>
|
||||||
|
if data.Quote != "" {
|
||||||
|
@templ.Raw(data.Quote)
|
||||||
|
} else {
|
||||||
|
<span style="color: hsl(var(--muted-foreground));">Add a press quote to populate this block.</span>
|
||||||
|
}
|
||||||
|
</blockquote>
|
||||||
|
if data.Stars > 0 {
|
||||||
|
<div class="mt-4 flex justify-center gap-1" aria-label="Star rating" data-stars={ starsAttr(data.Stars) }>
|
||||||
|
for i := 0; i < data.Stars; i++ {
|
||||||
|
<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>
|
||||||
|
}
|
||||||
|
for i := data.Stars; i < 5; i++ {
|
||||||
|
<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
if data.Source != "" {
|
||||||
|
<p
|
||||||
|
class="mt-6 deco-caps text-xs"
|
||||||
|
style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--muted-foreground));"
|
||||||
|
>
|
||||||
|
{ data.Source }
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
<div class="h-6 mt-6 deco-scallop" aria-hidden="true"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
8
press_quote_helpers.go
Normal file
8
press_quote_helpers.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// starsAttr renders an int into a stable data-stars attribute string.
|
||||||
|
func starsAttr(n int) string {
|
||||||
|
return strconv.Itoa(n)
|
||||||
|
}
|
||||||
114
press_quote_templ.go
Normal file
114
press_quote_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"
|
||||||
|
|
||||||
|
// pressQuoteComponent renders the italic Cormorant pull-quote between fan dividers.
|
||||||
|
func pressQuoteComponent(data PressQuoteData) 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=\"art-deco:press_quote\" class=\"py-16\"><div class=\"max-w-3xl mx-auto px-4 text-center\"><div class=\"h-6 mb-6 deco-sunburst\" aria-hidden=\"true\"></div><blockquote class=\"italic text-2xl md:text-3xl leading-snug\" style=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); font-style: italic; color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Quote != "" {
|
||||||
|
templ_7745c5c3_Err = templ.Raw(data.Quote).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span style=\"color: hsl(var(--muted-foreground));\">Add a press quote to populate this block.</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</blockquote>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Stars > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"mt-4 flex justify-center gap-1\" aria-label=\"Star rating\" data-stars=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.ResolveAttributeValue(starsAttr(data.Stars))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `press_quote.templ`, Line: 19, Col: 107}
|
||||||
|
}
|
||||||
|
_, 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, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for i := 0; i < data.Stars; i++ {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<span data-deco-star=\"filled\" aria-hidden=\"true\" style=\"color: hsl(var(--primary));\">★</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := data.Stars; i < 5; i++ {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span data-deco-star=\"empty\" aria-hidden=\"true\" style=\"color: hsl(var(--muted-foreground));\">☆</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.Source != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<p class=\"mt-6 deco-caps text-xs\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--muted-foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Source)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `press_quote.templ`, Line: 33, Col: 18}
|
||||||
|
}
|
||||||
|
_, 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, 10, "</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"h-6 mt-6 deco-scallop\" aria-hidden=\"true\"></div></div></section>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
174
register.go
Normal file
174
register.go
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
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 into a templates.TemplateFunc.
|
||||||
|
func wrap(f func(ctx context.Context, doc map[string]any) templ.Component) templates.TemplateFunc {
|
||||||
|
return func(ctx context.Context, doc map[string]any) templates.HTMLComponent {
|
||||||
|
return f(ctx, doc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register wires up the Art Deco system template, its page templates, blocks,
|
||||||
|
// template overrides and email wrapper.
|
||||||
|
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
||||||
|
// Schemas must be loaded BEFORE any br.Register call so block schemas bind.
|
||||||
|
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// System template metadata.
|
||||||
|
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
|
||||||
|
Key: "art-deco",
|
||||||
|
Title: "Art Deco",
|
||||||
|
Description: "Luxury Art Deco theme with champagne gold gradients, jet black, ivory and geometric fan motifs for hotels, fine dining, weddings and jewellers.",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Page templates.
|
||||||
|
if err := tr.RegisterPageTemplate("art-deco", templates.PageTemplateMeta{
|
||||||
|
Key: "default",
|
||||||
|
Title: "Default",
|
||||||
|
Description: "Centered symmetric layout with gold rule header and footer.",
|
||||||
|
Slots: []string{"header", "main", "footer"},
|
||||||
|
}, wrap(RenderArtDecoDefault)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tr.RegisterPageTemplate("art-deco", templates.PageTemplateMeta{
|
||||||
|
Key: "landing",
|
||||||
|
Title: "Marquee Landing",
|
||||||
|
Description: "Wide hero with sunburst overlay, reservation strip, CTA.",
|
||||||
|
Slots: []string{"marquee", "main", "cta", "footer"},
|
||||||
|
}, wrap(RenderArtDecoLanding)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tr.RegisterPageTemplate("art-deco", templates.PageTemplateMeta{
|
||||||
|
Key: "article",
|
||||||
|
Title: "Editorial",
|
||||||
|
Description: "Narrow editorial column for press, menus and stories.",
|
||||||
|
Slots: []string{"header", "main", "aside", "footer"},
|
||||||
|
}, wrap(RenderArtDecoArticle)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tr.RegisterPageTemplate("art-deco", templates.PageTemplateMeta{
|
||||||
|
Key: "full-width",
|
||||||
|
Title: "Grand Ballroom",
|
||||||
|
Description: "Edge-to-edge gallery layout for venues and lookbooks.",
|
||||||
|
Slots: []string{"header", "main", "footer"},
|
||||||
|
}, wrap(RenderArtDecoFullWidth)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Theme-specific blocks.
|
||||||
|
br.Register(ReservationBlockMeta, ReservationBlock)
|
||||||
|
br.Register(MenuBlockMeta, MenuBlock)
|
||||||
|
br.Register(GalleryFanBlockMeta, GalleryFanBlock)
|
||||||
|
br.Register(DividerFanBlockMeta, DividerFanBlock)
|
||||||
|
br.Register(FooterBlockMeta, FooterBlock)
|
||||||
|
br.Register(MarqueeHeroBlockMeta, MarqueeHeroBlock)
|
||||||
|
br.Register(PressQuoteBlockMeta, PressQuoteBlock)
|
||||||
|
|
||||||
|
// Template overrides — active only while the Art Deco system template is selected.
|
||||||
|
br.RegisterTemplateOverride("art-deco", "heading", ArtDecoHeadingBlock)
|
||||||
|
br.RegisterTemplateOverride("art-deco", "text", ArtDecoTextBlock)
|
||||||
|
br.RegisterTemplateOverride("art-deco", "button", ArtDecoButtonBlock)
|
||||||
|
br.RegisterTemplateOverride("art-deco", "image", ArtDecoImageBlock)
|
||||||
|
|
||||||
|
// Branded email wrapper.
|
||||||
|
tr.RegisterEmailWrapper("art-deco", ArtDecoEmailWrapper)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultMasterPages returns the master pages provisioned the first time the plugin loads.
|
||||||
|
func DefaultMasterPages() []plugin.MasterPageDefinition {
|
||||||
|
return []plugin.MasterPageDefinition{
|
||||||
|
{
|
||||||
|
Key: "art-deco:default-master",
|
||||||
|
Title: "Art Deco Default Master",
|
||||||
|
PageTemplates: []string{"default", "article"},
|
||||||
|
Blocks: []plugin.MasterPageBlock{
|
||||||
|
{
|
||||||
|
BlockKey: "navbar",
|
||||||
|
Title: "Brass Navigation",
|
||||||
|
Content: map[string]any{"menuName": "main"},
|
||||||
|
Slot: "header",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "art-deco:divider_fan",
|
||||||
|
Title: "Header Fan Divider",
|
||||||
|
Content: map[string]any{"variant": "sunburst"},
|
||||||
|
Slot: "header",
|
||||||
|
SortOrder: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "slot",
|
||||||
|
Title: "Main Content",
|
||||||
|
Content: map[string]any{"slotName": "main", "placeholder": "Page content"},
|
||||||
|
Slot: "main",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "art-deco:footer",
|
||||||
|
Title: "Site Footer",
|
||||||
|
Content: map[string]any{"address": "", "reservationsEmail": "", "showSocial": "true"},
|
||||||
|
Slot: "footer",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "art-deco:marquee-master",
|
||||||
|
Title: "Art Deco Marquee Master",
|
||||||
|
PageTemplates: []string{"landing", "full-width"},
|
||||||
|
Blocks: []plugin.MasterPageBlock{
|
||||||
|
{
|
||||||
|
BlockKey: "navbar",
|
||||||
|
Title: "Brass Navigation",
|
||||||
|
Content: map[string]any{"menuName": "main"},
|
||||||
|
Slot: "marquee",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "art-deco:reservation",
|
||||||
|
Title: "Reservation Strip",
|
||||||
|
Content: map[string]any{"phone": "", "openTable": ""},
|
||||||
|
Slot: "marquee",
|
||||||
|
SortOrder: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "slot",
|
||||||
|
Title: "Main Content",
|
||||||
|
Content: map[string]any{"slotName": "main"},
|
||||||
|
Slot: "main",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "art-deco:divider_fan",
|
||||||
|
Title: "CTA Fan Divider",
|
||||||
|
Content: map[string]any{"variant": "scallop"},
|
||||||
|
Slot: "cta",
|
||||||
|
SortOrder: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlockKey: "art-deco:footer",
|
||||||
|
Title: "Site Footer",
|
||||||
|
Content: map[string]any{"showSocial": "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 Art Deco theme.
|
||||||
|
var Registration = plugin.PluginRegistration{
|
||||||
|
Name: "art-deco",
|
||||||
|
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() },
|
||||||
|
}
|
||||||
37
reservation.go
Normal file
37
reservation.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/blocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReservationBlockMeta defines the reservation strip block.
|
||||||
|
var ReservationBlockMeta = blocks.BlockMeta{
|
||||||
|
Key: "reservation",
|
||||||
|
Title: "Reservation Strip",
|
||||||
|
Description: "Sticky gold-on-black reservation strip with phone, OpenTable CTA and trading hours.",
|
||||||
|
Source: "art-deco",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReservationData is the typed view used by the templ component.
|
||||||
|
type ReservationData struct {
|
||||||
|
Phone string
|
||||||
|
OpenTable string
|
||||||
|
Hours []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReservationBlock renders a reservation strip.
|
||||||
|
// Content: {"phone": "...", "openTable": "...", "hours": ["Tue–Sat · 6pm–late", ...]}
|
||||||
|
func ReservationBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := ReservationData{
|
||||||
|
Phone: getString(content, "phone"),
|
||||||
|
OpenTable: getString(content, "openTable"),
|
||||||
|
Hours: getStringSlice(content, "hours"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = reservationComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
36
reservation.templ
Normal file
36
reservation.templ
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// reservationComponent renders the sticky reservation strip.
|
||||||
|
// Empty inputs render a shell with a "Reservations" label so the strip is never blank.
|
||||||
|
templ reservationComponent(data ReservationData) {
|
||||||
|
<div
|
||||||
|
data-block="art-deco:reservation"
|
||||||
|
class="sticky top-0 z-30 w-full deco-grain"
|
||||||
|
style="background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-bottom: 1px solid hsl(var(--primary));"
|
||||||
|
>
|
||||||
|
<div class="max-w-5xl mx-auto px-4 py-2 flex flex-wrap items-center justify-between gap-2 text-sm">
|
||||||
|
<div class="flex items-center gap-3 deco-caps" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--primary));">
|
||||||
|
<span>Reservations</span>
|
||||||
|
if data.Phone != "" {
|
||||||
|
<span aria-hidden="true" style="color: hsl(var(--primary) / 0.5);">·</span>
|
||||||
|
<a href={ templ.SafeURL("tel:" + data.Phone) } class="deco-link" style="border-bottom-color: hsl(var(--primary));">{ data.Phone }</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
if len(data.Hours) > 0 {
|
||||||
|
<div class="flex flex-wrap items-center gap-3" style="color: hsl(var(--background));">
|
||||||
|
for i, line := range data.Hours {
|
||||||
|
if i > 0 {
|
||||||
|
<span aria-hidden="true" style="color: hsl(var(--primary) / 0.5);">·</span>
|
||||||
|
}
|
||||||
|
<span>{ line }</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
if data.OpenTable != "" {
|
||||||
|
<a href={ templ.SafeURL(data.OpenTable) } class="deco-pill" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));">
|
||||||
|
Book a Table
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
136
reservation_templ.go
Normal file
136
reservation_templ.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// reservationComponent renders the sticky reservation strip.
|
||||||
|
// Empty inputs render a shell with a "Reservations" label so the strip is never blank.
|
||||||
|
func reservationComponent(data ReservationData) 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=\"art-deco:reservation\" class=\"sticky top-0 z-30 w-full deco-grain\" style=\"background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-bottom: 1px solid hsl(var(--primary));\"><div class=\"max-w-5xl mx-auto px-4 py-2 flex flex-wrap items-center justify-between gap-2 text-sm\"><div class=\"flex items-center gap-3 deco-caps\" style=\"font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--primary));\"><span>Reservations</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if data.Phone != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span aria-hidden=\"true\" style=\"color: hsl(var(--primary) / 0.5);\">·</span> <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("tel:" + data.Phone))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `reservation.templ`, Line: 16, Col: 49}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" class=\"deco-link\" style=\"border-bottom-color: hsl(var(--primary));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Phone)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `reservation.templ`, Line: 16, Col: 132}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</a>")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
if len(data.Hours) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"flex flex-wrap items-center gap-3\" style=\"color: hsl(var(--background));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for i, line := range data.Hours {
|
||||||
|
if i > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span aria-hidden=\"true\" style=\"color: hsl(var(--primary) / 0.5);\">·</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " <span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(line)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `reservation.templ`, Line: 25, Col: 18}
|
||||||
|
}
|
||||||
|
_, 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>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.OpenTable != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<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(data.OpenTable))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `reservation.templ`, Line: 30, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" class=\"deco-pill\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));\">Book a Table</a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
270
template.templ
Normal file
270
template.templ
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/templates/bn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageData captures the inputs needed to render an Art Deco page template.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePageData reads a page-render doc into the typed PageData used by templ.
|
||||||
|
func parsePageData(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 := "dark"
|
||||||
|
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
|
||||||
|
themeMode = tm
|
||||||
|
}
|
||||||
|
|
||||||
|
return PageData{
|
||||||
|
Title: title,
|
||||||
|
Slots: slots,
|
||||||
|
ThemeMode: themeMode,
|
||||||
|
ThemeCSS: themeCSS,
|
||||||
|
SiteSettings: bn.ParseSiteSettings(doc),
|
||||||
|
PageMeta: bn.ParsePageMeta(doc),
|
||||||
|
StructuredData: structuredData,
|
||||||
|
CSSHash: cssHash,
|
||||||
|
PageviewNonce: pageviewNonce,
|
||||||
|
EngagementConfig: bn.ParseEngagementConfig(doc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// htmlClassForMode returns the html-element class hint that flips dark mode.
|
||||||
|
func htmlClassForMode(mode string) string {
|
||||||
|
if mode == "dark" {
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoDefault — centered symmetric layout with gold rule header and footer.
|
||||||
|
templ ArtDecoDefault(data PageData) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class={ htmlClassForMode(data.ThemeMode) }>
|
||||||
|
@bn.Head(bn.HeadData{
|
||||||
|
Title: data.Title,
|
||||||
|
Settings: data.SiteSettings,
|
||||||
|
PageMeta: data.PageMeta,
|
||||||
|
ThemeMode: data.ThemeMode,
|
||||||
|
ThemeCSS: data.ThemeCSS,
|
||||||
|
PluginStyles: []string{"/templates/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
})
|
||||||
|
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||||
|
@bn.AdminBypassBanner(data.SiteSettings)
|
||||||
|
<header class="w-full">
|
||||||
|
<div class="max-w-5xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["header"])
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="flex-grow max-w-3xl mx-auto w-full px-4 py-12 text-center">
|
||||||
|
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||||
|
@templ.Raw(main)
|
||||||
|
} else {
|
||||||
|
<div class="py-20">
|
||||||
|
<p class="text-muted-foreground">No content blocks assigned to this page.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</main>
|
||||||
|
<footer class="w-full mt-auto">
|
||||||
|
<div class="max-w-5xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["footer"])
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
@bn.BodyEnd(data.SiteSettings)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoLanding — Marquee Landing: wide hero, reservation strip, CTA.
|
||||||
|
templ ArtDecoLanding(data PageData) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class={ htmlClassForMode(data.ThemeMode) }>
|
||||||
|
@bn.Head(bn.HeadData{
|
||||||
|
Title: data.Title,
|
||||||
|
Settings: data.SiteSettings,
|
||||||
|
PageMeta: data.PageMeta,
|
||||||
|
ThemeMode: data.ThemeMode,
|
||||||
|
ThemeCSS: data.ThemeCSS,
|
||||||
|
PluginStyles: []string{"/templates/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
})
|
||||||
|
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||||
|
@bn.AdminBypassBanner(data.SiteSettings)
|
||||||
|
<section class="w-full">
|
||||||
|
@templ.Raw(data.Slots["marquee"])
|
||||||
|
</section>
|
||||||
|
<main class="flex-grow">
|
||||||
|
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||||
|
<div class="max-w-5xl mx-auto px-4 py-16 text-center">
|
||||||
|
@templ.Raw(main)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</main>
|
||||||
|
<section class="w-full">
|
||||||
|
@templ.Raw(data.Slots["cta"])
|
||||||
|
</section>
|
||||||
|
<footer class="w-full mt-auto">
|
||||||
|
<div class="max-w-5xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["footer"])
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
@bn.BodyEnd(data.SiteSettings)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoArticle — narrow editorial column for press, menus and stories.
|
||||||
|
templ ArtDecoArticle(data PageData) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class={ htmlClassForMode(data.ThemeMode) }>
|
||||||
|
@bn.Head(bn.HeadData{
|
||||||
|
Title: data.Title,
|
||||||
|
Settings: data.SiteSettings,
|
||||||
|
PageMeta: data.PageMeta,
|
||||||
|
ThemeMode: data.ThemeMode,
|
||||||
|
ThemeCSS: data.ThemeCSS,
|
||||||
|
PluginStyles: []string{"/templates/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
})
|
||||||
|
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||||
|
@bn.AdminBypassBanner(data.SiteSettings)
|
||||||
|
<header class="w-full">
|
||||||
|
<div class="max-w-3xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["header"])
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="flex-grow grid gap-12 max-w-5xl mx-auto w-full px-4 py-12 md:grid-cols-[2fr_1fr]">
|
||||||
|
<main class="prose max-w-none">
|
||||||
|
if main, ok := data.Slots["main"]; ok && main != "" {
|
||||||
|
<article class="deco-dropcap" data-deco-dropcap="true">
|
||||||
|
@templ.Raw(main)
|
||||||
|
</article>
|
||||||
|
} else {
|
||||||
|
<div class="py-20 text-center">
|
||||||
|
<p class="text-muted-foreground">No content blocks assigned to this page.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</main>
|
||||||
|
<aside class="w-full">
|
||||||
|
@templ.Raw(data.Slots["aside"])
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
<footer class="w-full mt-auto">
|
||||||
|
<div class="max-w-5xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["footer"])
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
@bn.BodyEnd(data.SiteSettings)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoFullWidth — Grand Ballroom: edge-to-edge gallery layout.
|
||||||
|
templ ArtDecoFullWidth(data PageData) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class={ htmlClassForMode(data.ThemeMode) }>
|
||||||
|
@bn.Head(bn.HeadData{
|
||||||
|
Title: data.Title,
|
||||||
|
Settings: data.SiteSettings,
|
||||||
|
PageMeta: data.PageMeta,
|
||||||
|
ThemeMode: data.ThemeMode,
|
||||||
|
ThemeCSS: data.ThemeCSS,
|
||||||
|
PluginStyles: []string{"/templates/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
})
|
||||||
|
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", 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="py-20 text-center">
|
||||||
|
<p class="text-muted-foreground">No content blocks assigned to this page.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</main>
|
||||||
|
<footer class="w-full mt-auto">
|
||||||
|
<div class="max-w-5xl mx-auto px-4">
|
||||||
|
@templ.Raw(data.Slots["footer"])
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
@bn.BodyEnd(data.SiteSettings)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page-render funcs adapt typed PageData into templ.Component values.
|
||||||
|
|
||||||
|
func RenderArtDecoDefault(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoDefault(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoLanding(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoLanding(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoArticle(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoArticle(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoFullWidth(parsePageData(doc))
|
||||||
|
}
|
||||||
607
template_templ.go
Normal file
607
template_templ.go
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.1020
|
||||||
|
package main
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.dev.alexdunmow.com/block/core/templates/bn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageData captures the inputs needed to render an Art Deco page template.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePageData reads a page-render doc into the typed PageData used by templ.
|
||||||
|
func parsePageData(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 := "dark"
|
||||||
|
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
|
||||||
|
themeMode = tm
|
||||||
|
}
|
||||||
|
|
||||||
|
return PageData{
|
||||||
|
Title: title,
|
||||||
|
Slots: slots,
|
||||||
|
ThemeMode: themeMode,
|
||||||
|
ThemeCSS: themeCSS,
|
||||||
|
SiteSettings: bn.ParseSiteSettings(doc),
|
||||||
|
PageMeta: bn.ParsePageMeta(doc),
|
||||||
|
StructuredData: structuredData,
|
||||||
|
CSSHash: cssHash,
|
||||||
|
PageviewNonce: pageviewNonce,
|
||||||
|
EngagementConfig: bn.ParseEngagementConfig(doc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// htmlClassForMode returns the html-element class hint that flips dark mode.
|
||||||
|
func htmlClassForMode(mode string) string {
|
||||||
|
if mode == "dark" {
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoDefault — centered symmetric layout with gold rule header and footer.
|
||||||
|
func ArtDecoDefault(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>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 = []any{htmlClassForMode(data.ThemeMode)}
|
||||||
|
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, 2, "<html lang=\"en\" 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: `template.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, 3, "\">")
|
||||||
|
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/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<body class=\"bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", 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, 5, "<header class=\"w-full\"><div class=\"max-w-5xl 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, 6, "</div></header><main class=\"flex-grow max-w-3xl mx-auto w-full px-4 py-12 text-center\">")
|
||||||
|
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, 7, "<div class=\"py-20\"><p class=\"text-muted-foreground\">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, 8, "</main><footer class=\"w-full mt-auto\"><div class=\"max-w-5xl mx-auto px-4\">")
|
||||||
|
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, 9, "</div></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, 10, "</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoLanding — Marquee Landing: wide hero, reservation strip, CTA.
|
||||||
|
func ArtDecoLanding(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, 11, "<!doctype html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 = []any{htmlClassForMode(data.ThemeMode)}
|
||||||
|
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, 12, "<html lang=\"en\" 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: `template.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, 13, "\">")
|
||||||
|
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/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<body class=\"bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", 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, 15, "<section class=\"w-full\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(data.Slots["marquee"]).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</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, 17, "<div class=\"max-w-5xl mx-auto px-4 py-16 text-center\">")
|
||||||
|
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, 18, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</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, 20, "</section><footer class=\"w-full mt-auto\"><div class=\"max-w-5xl mx-auto px-4\">")
|
||||||
|
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, 21, "</div></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, 22, "</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoArticle — narrow editorial column for press, menus and stories.
|
||||||
|
func ArtDecoArticle(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_Var7 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var7 == nil {
|
||||||
|
templ_7745c5c3_Var7 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<!doctype html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 = []any{htmlClassForMode(data.ThemeMode)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<html lang=\"en\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var8).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `template.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\">")
|
||||||
|
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/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<body class=\"bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", 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, 27, "<header class=\"w-full\"><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, 28, "</div></header><div class=\"flex-grow grid gap-12 max-w-5xl mx-auto w-full px-4 py-12 md:grid-cols-[2fr_1fr]\"><main class=\"prose max-w-none\">")
|
||||||
|
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, 29, "<article class=\"deco-dropcap\" data-deco-dropcap=\"true\">")
|
||||||
|
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, 30, "</article>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<div class=\"py-20 text-center\"><p class=\"text-muted-foreground\">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, 32, "</main><aside class=\"w-full\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(data.Slots["aside"]).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</aside></div><footer class=\"w-full mt-auto\"><div class=\"max-w-5xl mx-auto px-4\">")
|
||||||
|
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, 34, "</div></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, 35, "</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtDecoFullWidth — Grand Ballroom: edge-to-edge gallery layout.
|
||||||
|
func ArtDecoFullWidth(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_Var10 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var10 == nil {
|
||||||
|
templ_7745c5c3_Var10 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<!doctype html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var11 = []any{htmlClassForMode(data.ThemeMode)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<html lang=\"en\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var12 string
|
||||||
|
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var11).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `template.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "\">")
|
||||||
|
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/art-deco/style.css"},
|
||||||
|
StructuredData: data.StructuredData,
|
||||||
|
CSSHash: data.CSSHash,
|
||||||
|
PageviewNonce: data.PageviewNonce,
|
||||||
|
EngagementConfig: data.EngagementConfig,
|
||||||
|
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<body class=\"bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", 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, 40, "<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, 41, "</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, 42, "<div class=\"py-20 text-center\"><p class=\"text-muted-foreground\">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, 43, "</main><footer class=\"w-full mt-auto\"><div class=\"max-w-5xl mx-auto px-4\">")
|
||||||
|
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, 44, "</div></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, 45, "</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page-render funcs adapt typed PageData into templ.Component values.
|
||||||
|
|
||||||
|
func RenderArtDecoDefault(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoDefault(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoLanding(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoLanding(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoArticle(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoArticle(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderArtDecoFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
||||||
|
return ArtDecoFullWidth(parsePageData(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
|
||||||
{{ head_html|safe }}
|
|
||||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
|
||||||
{{ admin_banner_html|safe }}
|
|
||||||
<header class="w-full">
|
|
||||||
<div class="max-w-3xl mx-auto px-4">{{ slots.header|safe }}</div>
|
|
||||||
</header>
|
|
||||||
<div class="flex-grow grid gap-12 max-w-5xl mx-auto w-full px-4 py-12 md:grid-cols-[2fr_1fr]">
|
|
||||||
<main class="prose max-w-none">
|
|
||||||
{% if slots.main %}<article class="deco-dropcap" data-deco-dropcap="true">{{ slots.main|safe }}</article>{% else %}<div class="py-20 text-center"><p class="text-muted-foreground">No content blocks assigned to this page.</p></div>{% endif %}
|
|
||||||
</main>
|
|
||||||
<aside class="w-full">{{ slots.aside|safe }}</aside>
|
|
||||||
</div>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
|
||||||
</footer>
|
|
||||||
{{ body_end_html|safe }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
|
||||||
{{ head_html|safe }}
|
|
||||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
|
||||||
{{ admin_banner_html|safe }}
|
|
||||||
<header class="w-full">
|
|
||||||
<div class="max-w-5xl mx-auto px-4">{{ slots.header|safe }}</div>
|
|
||||||
</header>
|
|
||||||
<main class="flex-grow max-w-3xl mx-auto w-full px-4 py-12 text-center">
|
|
||||||
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20"><p class="text-muted-foreground">No content blocks assigned to this page.</p></div>{% endif %}
|
|
||||||
</main>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
|
||||||
</footer>
|
|
||||||
{{ body_end_html|safe }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
|
||||||
{{ head_html|safe }}
|
|
||||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
|
||||||
{{ admin_banner_html|safe }}
|
|
||||||
<header class="w-full">{{ slots.header|safe }}</header>
|
|
||||||
<main class="flex-grow w-full">
|
|
||||||
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center"><p class="text-muted-foreground">No content blocks assigned to this page.</p></div>{% endif %}
|
|
||||||
</main>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
|
||||||
</footer>
|
|
||||||
{{ body_end_html|safe }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
|
||||||
{{ head_html|safe }}
|
|
||||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
|
||||||
{{ admin_banner_html|safe }}
|
|
||||||
<section class="w-full">{{ slots.marquee|safe }}</section>
|
|
||||||
<main class="flex-grow">
|
|
||||||
{% if slots.main %}<div class="max-w-5xl mx-auto px-4 py-16 text-center">{{ slots.main|safe }}</div>{% endif %}
|
|
||||||
</main>
|
|
||||||
<section class="w-full">{{ slots.cta|safe }}</section>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
|
||||||
</footer>
|
|
||||||
{{ body_end_html|safe }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
<!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>{{ site_name }}</title>
|
|
||||||
<style type="text/css">
|
|
||||||
body, table, td, p, a, li, blockquote {
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
|
||||||
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
|
|
||||||
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
|
|
||||||
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
|
|
||||||
@media only screen and (max-width: 620px) {
|
|
||||||
.email-container { width: 100% !important; max-width: 100% !important; }
|
|
||||||
.content-padding { padding-left: 24px !important; padding-right: 24px !important; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body style="background-color: {{ colors.background }}; margin: 0; padding: 0; font-family: &#39;Cormorant Garamond&#39;, &#39;Cormorant&#39;, Georgia, serif;">
|
|
||||||
{% if preview_text %}<div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">{{ preview_text }}</div>{% endif %}
|
|
||||||
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="padding: 32px 10px; background-color: {{ colors.background }};">
|
|
||||||
<table role="presentation" class="email-container" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; background-color: {{ colors.background }}; border: 1px solid {{ colors.border }};">
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="padding: 0; background-color: {{ colors.foreground }};">
|
|
||||||
<img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%2080%22%3E%3Crect%20width%3D%22600%22%20height%3D%2280%22%20fill%3D%22%23191510%22%2F%3E%3Cg%20stroke%3D%22%23{{ colors.primary|default:"#c9a14a"|cut:"#" }}%22%20stroke-width%3D%221%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M300%2080%20L%20100%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20180%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20260%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20340%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20420%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20500%2010%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E" alt="" width="600" height="80" style="display: block; width: 100%; max-width: 600px; height: 80px; background-color: {{ colors.foreground }};">
|
|
||||||
{% if site_name %}<h1 style="margin: 0; padding: 24px 16px; font-family: &#39;Italiana&#39;, &#39;Cinzel&#39;, Georgia, serif; font-size: 28px; text-transform: uppercase; letter-spacing: 0.18em; color: {{ colors.primary }};">{{ site_name }}</h1>{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="content-padding" style="padding: 40px 48px; color: {{ colors.foreground }}; font-size: 16px; line-height: 1.7;">{{ body|safe }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 48px;"><hr style="border: none; border-top: 1px solid {{ colors.primary }}; margin: 0;"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="padding: 24px 48px; color: {{ colors.mutedForeground }}; font-size: 13px;">
|
|
||||||
<p style="margin: 0 0 8px; font-family: &#39;Italiana&#39;, &#39;Cinzel&#39;, Georgia, serif; text-transform: uppercase; letter-spacing: 0.18em; color: {{ colors.foreground }};">{{ site_name }}</p>
|
|
||||||
{% if site_url %}<p style="margin: 0 0 8px;"><a href="{{ site_url }}" style="color: {{ colors.primary }}; text-decoration: none; border-bottom: 1px solid {{ colors.primary }};">{{ site_url }}</a></p>{% endif %}
|
|
||||||
{% if support_email %}<p style="margin: 12px 0 0; font-style: italic; color: {{ colors.mutedForeground }};">P.S. Reservations & enquiries: {{ support_email }}</p>{% endif %}
|
|
||||||
{% if unsubscribe_url %}<p style="margin: 16px 0 0; font-size: 11px;"><a href="{{ unsubscribe_url }}" style="color: {{ colors.mutedForeground }}; text-decoration: none;">Unsubscribe</a></p>{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
{% if label %}{% if url %}<a data-block-override="art-deco:button" href="{{ url }}" class="deco-pill inline-block" style="{% if variant == "secondary" %}background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));{% elif variant == "ghost" %}background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));{% else %}background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));{% endif %}">{{ label }}</a>{% else %}<button type="button" data-block-override="art-deco:button" class="deco-pill" style="{% if variant == "secondary" %}background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));{% elif variant == "ghost" %}background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));{% else %}background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));{% endif %}">{{ label }}</button>{% endif %}{% endif %}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
{% if level|integer == 1 %}<h1 data-block-override="art-deco:heading" class="deco-caps deco-underline text-4xl md:text-5xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h1>{% elif level|integer == 3 %}<h3 data-block-override="art-deco:heading" class="deco-caps deco-underline text-2xl md:text-3xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h3>{% elif level|integer == 4 %}<h4 data-block-override="art-deco:heading" class="deco-caps deco-underline text-xl md:text-2xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h4>{% elif level|integer == 5 %}<h5 data-block-override="art-deco:heading" class="deco-caps deco-underline text-lg md:text-xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h5>{% elif level|integer == 6 %}<h6 data-block-override="art-deco:heading" class="deco-caps deco-underline text-base md:text-lg {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h6>{% else %}<h2 data-block-override="art-deco:heading" class="deco-caps deco-underline text-3xl md:text-4xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h2>{% endif %}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
<figure data-block-override="art-deco:image" class="my-8"><div class="{% if frame == "scallop" %}deco-scallop{% elif frame == "plain" %}{% else %}deco-step{% endif %}"><img src="{% if src %}{{ src }}{% else %}data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E{% endif %}" alt="{{ alt }}" class="block w-full h-auto"></div>{% if caption %}<figcaption class="mt-2 italic text-center text-sm" style="color: hsl(var(--muted-foreground));">{{ caption }}</figcaption>{% endif %}</figure>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
<div data-block-override="art-deco:text" data-deco-dropcap="true" class="deco-dropcap prose max-w-none {{ class }}" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); color: hsl(var(--foreground));">{{ text|safe }}</div>
|
|
||||||
26
text_override.go
Normal file
26
text_override.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArtDecoTextBlock overrides the built-in "text" block when the Art Deco theme is active.
|
||||||
|
// Renders prose in Cormorant body with a classical italic drop-cap on the first paragraph.
|
||||||
|
// Content: {"text": "<rich HTML>", "class": "optional-extra-class"}
|
||||||
|
func ArtDecoTextBlock(ctx context.Context, content map[string]any) string {
|
||||||
|
data := TextOverrideData{
|
||||||
|
Text: getString(content, "text"),
|
||||||
|
Class: getString(content, "class"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_ = artDecoTextComponent(data).Render(ctx, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextOverrideData is the typed view for the text override component.
|
||||||
|
type TextOverrideData struct {
|
||||||
|
Text string
|
||||||
|
Class string
|
||||||
|
}
|
||||||
13
text_override.templ
Normal file
13
text_override.templ
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// artDecoTextComponent renders rich text body copy with a classical italic dropcap.
|
||||||
|
templ artDecoTextComponent(data TextOverrideData) {
|
||||||
|
<div
|
||||||
|
data-block-override="art-deco:text"
|
||||||
|
data-deco-dropcap="true"
|
||||||
|
class={ "deco-dropcap prose max-w-none", data.Class }
|
||||||
|
style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); color: hsl(var(--foreground));"
|
||||||
|
>
|
||||||
|
@templ.Raw(data.Text)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
67
text_override_templ.go
Normal file
67
text_override_templ.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.1020
|
||||||
|
package main
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
// artDecoTextComponent renders rich text body copy with a classical italic dropcap.
|
||||||
|
func artDecoTextComponent(data TextOverrideData) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
var templ_7745c5c3_Var2 = []any{"deco-dropcap prose max-w-none", data.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 data-block-override=\"art-deco:text\" data-deco-dropcap=\"true\" 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=\"font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); color: hsl(var(--foreground));\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(data.Text).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
Loading…
x
Reference in New Issue
Block a user