feat: convert to codeless .bnp — templates + manifest, Go/templ deleted (WO-WZ-021)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b6d6f4b010
commit
dc4cc2d8b3
40
Makefile
40
Makefile
@ -1,26 +1,27 @@
|
|||||||
# scifi-clean — build & publish helpers (wasm .bnp workflow)
|
# scifi-clean — build & publish helpers (CODELESS .bnp workflow, WO-WZ-021)
|
||||||
#
|
#
|
||||||
# The theme compiles to a wasip1 reactor-mode wasm module packed into a .bnp
|
# This theme is a CODELESS .bnp: pure declaration the host runs — blocks
|
||||||
# artifact (`ninja plugin build`). The legacy .so path is retired (WO-WZ-015):
|
# (blocks/blocks.yaml + .ninjatpl), page/system templates, template overrides,
|
||||||
# the CMS is wasm-native and can no longer load .so plugins. Distribution is
|
# an email wrapper, master pages, presets, fonts and CSS in manifest.yaml. No
|
||||||
# publish-to-registry -> InstallFromRegistry (hot-load, no restart).
|
# Go, no templ, no plugin.wasm, no block/core dependency. `ninja plugin build`
|
||||||
|
# classifies the repo as codeless (no Go at the root) and packs the artifact
|
||||||
|
# with manifest.pb (codeless: true) and NO plugin.wasm.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# make build # compile wasm + pack scifi-clean-<version>.bnp
|
# make build # pack scifi-clean-<version>.bnp (codeless — no wasm)
|
||||||
# make verify # validate the built .bnp (layout/abi/name/size)
|
# make verify # validate the built .bnp (loader-identical checks)
|
||||||
# make archive-check # prove a clean `git archive HEAD` compiles to wasm
|
# make archive-check # prove a clean `git archive HEAD` still builds codeless
|
||||||
# make publish # ninja plugin publish --bnp (to the active registry)
|
# make publish # ninja plugin publish --bnp (to the active registry)
|
||||||
# make templ # regenerate templ Go files
|
|
||||||
# make clean # remove build artefacts
|
# make clean # remove build artefacts
|
||||||
|
|
||||||
.PHONY: build verify archive-check publish templ clean help
|
.PHONY: build verify archive-check publish clean help
|
||||||
|
|
||||||
PLUGIN_NAME := scifi-clean
|
PLUGIN_NAME := scifi-clean
|
||||||
NINJA := ninja
|
NINJA := ninja
|
||||||
BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp
|
BNP := $(PLUGIN_NAME)-$(shell grep '^version' plugin.mod | sed 's/.*"\(.*\)"/\1/').bnp
|
||||||
|
|
||||||
# Compile to wasm and pack the .bnp (GOOS=wasip1 GOARCH=wasm, DESCRIBE probe,
|
# Pack the codeless .bnp (manifest.pb synthesized from plugin.mod + manifest.yaml
|
||||||
# tar.zst of plugin.wasm + plugin.mod + manifest.pb + schemas/ + assets/).
|
# + blocks/ + templates/; no wasm compile, no DESCRIBE probe).
|
||||||
build:
|
build:
|
||||||
$(NINJA) plugin build --dir .
|
$(NINJA) plugin build --dir .
|
||||||
|
|
||||||
@ -28,12 +29,12 @@ build:
|
|||||||
verify:
|
verify:
|
||||||
$(NINJA) plugin verify $(BNP)
|
$(NINJA) plugin verify $(BNP)
|
||||||
|
|
||||||
# Prove a clean `git archive HEAD` (what publish ships) compiles to wasm.
|
# Prove a clean `git archive HEAD` (what publish ships) still packs codeless.
|
||||||
archive-check:
|
archive-check:
|
||||||
@T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \
|
@T=$$(mktemp -d /tmp/archive-check-$(PLUGIN_NAME).XXXXXX) && \
|
||||||
trap 'rm -rf "$$T"' EXIT && \
|
trap 'rm -rf "$$T"' EXIT && \
|
||||||
git archive HEAD | tar -x -C "$$T" && \
|
git archive HEAD | tar -x -C "$$T" && \
|
||||||
cd "$$T" && GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o "$$T/check.wasm" . && \
|
cd "$$T" && $(NINJA) plugin build --dir . && \
|
||||||
echo "archive-check OK"
|
echo "archive-check OK"
|
||||||
|
|
||||||
# Publish the prebuilt .bnp to the active registry.
|
# Publish the prebuilt .bnp to the active registry.
|
||||||
@ -41,19 +42,14 @@ archive-check:
|
|||||||
publish: build
|
publish: build
|
||||||
$(NINJA) plugin publish --bnp $(BNP)
|
$(NINJA) plugin publish --bnp $(BNP)
|
||||||
|
|
||||||
# Regenerate templ Go files locally.
|
|
||||||
templ:
|
|
||||||
templ generate
|
|
||||||
|
|
||||||
# Remove build artefacts.
|
# Remove build artefacts.
|
||||||
clean:
|
clean:
|
||||||
rm -f $(PLUGIN_NAME)-*.bnp $(PLUGIN_NAME).so plugin.wasm
|
rm -f $(PLUGIN_NAME)-*.bnp plugin.wasm
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Targets:"
|
@echo "Targets:"
|
||||||
@echo " build Compile wasm + pack the .bnp"
|
@echo " build Pack the codeless .bnp (no wasm)"
|
||||||
@echo " verify Validate the built .bnp (loader-identical checks)"
|
@echo " verify Validate the built .bnp (loader-identical checks)"
|
||||||
@echo " archive-check Prove a clean git archive HEAD compiles to wasm"
|
@echo " archive-check Prove a clean git archive HEAD packs codeless"
|
||||||
@echo " publish Publish the .bnp to the active registry"
|
@echo " publish Publish the .bnp to the active registry"
|
||||||
@echo " templ Regenerate templ Go files"
|
|
||||||
@echo " clean Remove build artefacts"
|
@echo " clean Remove build artefacts"
|
||||||
|
|||||||
42
blocks/blocks.yaml
Normal file
42
blocks/blocks.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Sci-Fi Clean theme block definitions (codeless .bnp, WO-WZ-021).
|
||||||
|
# Keys are fully qualified (scifi-clean:<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: scifi-clean:tech_spec
|
||||||
|
title: Tech Spec Table
|
||||||
|
description: Specification table with right-aligned mono numerals and hairline rows.
|
||||||
|
category: content
|
||||||
|
schema: tech_spec.schema.json
|
||||||
|
template: tech_spec.ninjatpl
|
||||||
|
- key: scifi-clean:diagram_caption
|
||||||
|
title: Diagram Caption
|
||||||
|
description: Annotated technical figure with a Fig. NN. heading and optional callout pins.
|
||||||
|
category: content
|
||||||
|
schema: diagram_caption.schema.json
|
||||||
|
template: diagram_caption.ninjatpl
|
||||||
|
- key: scifi-clean:mission_stat
|
||||||
|
title: Mission Stat
|
||||||
|
description: Headline metric in mono numerals with a signal-orange delta arrow.
|
||||||
|
category: content
|
||||||
|
schema: mission_stat.schema.json
|
||||||
|
template: mission_stat.ninjatpl
|
||||||
|
- key: scifi-clean:status_bar
|
||||||
|
title: Status Bar
|
||||||
|
description: Persistent top rail with optional UTC clock, build hash, and callsign.
|
||||||
|
category: navigation
|
||||||
|
schema: status_bar.schema.json
|
||||||
|
template: status_bar.ninjatpl
|
||||||
|
- key: scifi-clean:footer
|
||||||
|
title: Instrument Footer
|
||||||
|
description: Hairline-rule footer with callsign, optional signup, and link list.
|
||||||
|
category: layout
|
||||||
|
schema: footer.schema.json
|
||||||
|
template: footer.ninjatpl
|
||||||
|
- key: scifi-clean:schematic_hero
|
||||||
|
title: Schematic Hero
|
||||||
|
description: Landing hero with a large display title over a blueprint image and dual CTAs.
|
||||||
|
category: layout
|
||||||
|
schema: schematic_hero.schema.json
|
||||||
|
template: schematic_hero.ninjatpl
|
||||||
9
blocks/diagram_caption.ninjatpl
Normal file
9
blocks/diagram_caption.ninjatpl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<figure data-block="scifi-clean:diagram_caption" class="my-8 max-w-3xl mx-auto px-4">
|
||||||
|
<div class="relative hairline bg-card">
|
||||||
|
{% if image %}<img src="{{ image }}" alt="{{ title }}" class="block w-full h-auto">{% for pin in calloutPins %}<span class="absolute inline-flex items-center scifi-mono text-xs uppercase tracking-wider px-2 py-1 bg-card text-foreground hairline" style="left: {{ pin.x|floatformat:2 }}%; top: {{ pin.y|floatformat:2 }}%;">{{ pin.label }}</span>{% endfor %}{% else %}<div class="bg-grid aspect-video flex items-center justify-center"><span class="scifi-mono text-sm text-muted-foreground uppercase tracking-widest">No diagram yet</span></div>{% endif %}
|
||||||
|
</div>
|
||||||
|
<figcaption class="mt-3 hairline-t pt-3">
|
||||||
|
<h4 class="scifi-h4 scifi-mono text-sm uppercase tracking-widest text-foreground">Fig. {% if figureNumber %}{{ figureNumber }}{% else %}00{% endif %} . {% if title %}<span class="text-muted-foreground ml-2">{{ title }}</span>{% endif %}</h4>
|
||||||
|
{% if body %}<div class="scifi-body prose prose-sm max-w-none text-muted-foreground mt-2">{{ body|safe }}</div>{% endif %}
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
24
blocks/footer.ninjatpl
Normal file
24
blocks/footer.ninjatpl
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<div data-block="scifi-clean:footer" class="w-full">
|
||||||
|
<div class="hairline-t pt-8 pb-10">
|
||||||
|
<div class="max-w-6xl mx-auto px-4">
|
||||||
|
<div class="flex flex-col md:flex-row md:items-start md:justify-between gap-8">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div data-scifi-callsign class="scifi-mono uppercase tracking-widest text-xs text-foreground" style="font-family: var(--font-mono);">{{ callsign|default:"SCF-CLN" }}</div>
|
||||||
|
<p class="scifi-body text-sm text-muted-foreground max-w-md">Telemetry, mission briefs, and engineering notes from this surface.</p>
|
||||||
|
</div>
|
||||||
|
{% if links %}<ul class="space-y-2 scifi-body text-sm">{% for link in links %}<li><a href="{% if link.url %}{{ link.url }}{% else %}#{% endif %}" class="text-muted-foreground hover:text-foreground transition-colors">{{ link.text }}</a></li>{% endfor %}</ul>{% endif %}
|
||||||
|
{% if showSignup == true or showSignup == "true" %}<form class="space-y-2 max-w-xs" method="post" action="/subscribe">
|
||||||
|
<label class="scifi-mono uppercase text-xs tracking-widest text-muted-foreground block">Mission updates</label>
|
||||||
|
<div class="flex hairline">
|
||||||
|
<input type="email" name="email" required placeholder="ops@station.local" class="scifi-body flex-1 px-3 py-2 bg-card text-foreground text-sm focus:outline-none scifi-focus">
|
||||||
|
<button type="submit" class="scifi-mono uppercase text-xs tracking-widest px-4 py-2 bg-primary text-primary-foreground scifi-chevron scifi-focus">Subscribe</button>
|
||||||
|
</div>
|
||||||
|
</form>{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 hairline-t pt-4 flex items-center justify-between scifi-mono text-xs uppercase tracking-widest text-muted-foreground tabular-nums">
|
||||||
|
<span>Project Aurora</span>
|
||||||
|
<span>v0.1.0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
8
blocks/mission_stat.ninjatpl
Normal file
8
blocks/mission_stat.ninjatpl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<div data-block="scifi-clean:mission_stat" class="hairline p-6 bg-card text-card-foreground">
|
||||||
|
{% if metric %}<div class="scifi-mono uppercase text-xs tracking-widest text-muted-foreground mb-3">{{ metric }}</div>{% endif %}
|
||||||
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="scifi-mono text-5xl font-medium tabular-nums text-foreground" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums;">{% if value %}{{ value }}{% else %}—{% endif %}</span>
|
||||||
|
{% if unit %}<span class="scifi-mono text-base text-muted-foreground tabular-nums" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums;">{{ unit }}</span>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if delta %}<div class="mt-3 scifi-mono text-sm tabular-nums" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: hsl(var(--accent));">{% if trend == "up" %}↑{% elif trend == "down" %}↓{% else %}→{% endif %} {{ delta }}</div>{% endif %}
|
||||||
|
</div>
|
||||||
13
blocks/schematic_hero.ninjatpl
Normal file
13
blocks/schematic_hero.ninjatpl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<section data-block="scifi-clean:schematic_hero" class="relative overflow-hidden bg-grid">
|
||||||
|
{% if image %}<div class="absolute inset-0 z-0"><img src="{{ image }}" alt="" class="w-full h-full object-cover opacity-25"></div>{% endif %}
|
||||||
|
<div class="scrim relative z-10">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 py-24 md:py-32">
|
||||||
|
{% if kicker %}<div class="scifi-mono uppercase tracking-widest text-xs text-accent mb-4">{{ kicker }}</div>{% endif %}
|
||||||
|
<h1 class="scifi-h1 font-medium tracking-tight text-foreground" style="font-family: var(--font-heading); font-size: clamp(3rem, 6vw, 5rem); line-height: 1.05;">{% if title %}{{ title }}{% else %}Untitled mission{% endif %}</h1>
|
||||||
|
<div class="mt-8 flex flex-wrap gap-3">
|
||||||
|
{% if primaryCta.text and primaryCta.href %}<a href="{{ primaryCta.href }}" class="scifi-mono uppercase tracking-widest text-xs px-5 py-3 bg-primary text-primary-foreground scifi-chevron scifi-focus">{{ primaryCta.text }}</a>{% endif %}
|
||||||
|
{% if secondaryCta.text and secondaryCta.href %}<a href="{{ secondaryCta.href }}" class="scifi-mono uppercase tracking-widest text-xs px-5 py-3 hairline text-foreground scifi-chevron scifi-focus">{{ secondaryCta.text }}</a>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
27
blocks/status_bar.ninjatpl
Normal file
27
blocks/status_bar.ninjatpl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<div data-block="scifi-clean:status_bar" class="w-full hairline-b bg-card text-card-foreground scifi-mono text-xs uppercase tracking-widest" style="position: sticky; top: 0; z-index: 30;">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 py-2 flex items-center justify-between gap-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-muted-foreground">{{ callsign|default:"SCF-CLN" }}</span>
|
||||||
|
<span class="text-muted-foreground">|</span>
|
||||||
|
<span class="text-foreground">PUBLIC</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 tabular-nums">
|
||||||
|
{% if showClock != false and showClock != "false" %}<span data-status-bar-clock="utc" class="text-muted-foreground tabular-nums">00:00:00 UTC</span>{% endif %}
|
||||||
|
{% if showBuild != false and showBuild != "false" %}<span class="text-muted-foreground">|</span>
|
||||||
|
<span class="text-foreground tabular-nums">BLD a1b2c3</span>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
var el = document.querySelector('[data-status-bar-clock="utc"]');
|
||||||
|
if (!el) return;
|
||||||
|
function fmt(n){ return n < 10 ? '0' + n : String(n); }
|
||||||
|
function tick(){
|
||||||
|
var d = new Date();
|
||||||
|
el.textContent = fmt(d.getUTCHours()) + ':' + fmt(d.getUTCMinutes()) + ':' + fmt(d.getUTCSeconds()) + ' UTC';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
10
blocks/tech_spec.ninjatpl
Normal file
10
blocks/tech_spec.ninjatpl
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<section data-block="scifi-clean:tech_spec" class="py-8">
|
||||||
|
<div class="max-w-3xl mx-auto px-4">
|
||||||
|
{% if caption %}<p class="scifi-mono text-xs uppercase tracking-widest text-muted-foreground mb-3">{{ caption }}</p>{% endif %}
|
||||||
|
<table class="w-full text-sm hairline">
|
||||||
|
<tbody>
|
||||||
|
{% if rows %}{% for row in rows %}<tr class="{% if not forloop.Last %}hairline-b{% endif %}"><td class="scifi-body py-3 px-4 text-muted-foreground uppercase text-xs tracking-wider">{{ row.label }}</td><td class="scifi-mono py-3 px-4 text-right tabular-nums text-foreground font-medium" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right;">{{ row.value }}</td><td class="scifi-mono py-3 pr-4 text-right text-muted-foreground text-xs" style="font-family: var(--font-mono); text-align: right;">{{ row.unit }}</td></tr>{% endfor %}{% else %}<tr class="hairline-b"><td class="scifi-body py-3 px-4 text-foreground">No spec rows yet.</td><td class="scifi-mono py-3 px-4 text-right tabular-nums text-muted-foreground">--</td><td class="scifi-mono py-3 pr-4 text-right text-muted-foreground"></td></tr>{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ScifiButtonBlock renders a button with the Sci-Fi Clean treatment:
|
|
||||||
// mono uppercase label, hairline outline variant, right-arrow chevron suffix.
|
|
||||||
// Built-in button content shape: {"text": "...", "url": "...", "variant": "primary|outline"}.
|
|
||||||
func ScifiButtonBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
text := getString(content, "text")
|
|
||||||
url := getString(content, "url")
|
|
||||||
variant := getStringDefault(content, "variant", "primary")
|
|
||||||
if text == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = scifiButtonComponent(text, url, variant).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// scifiButtonComponent renders the Sci-Fi Clean button. The `→` chevron is a
|
|
||||||
// literal U+2192 inside an explicit data-icon span so UAT §13.14 can grep
|
|
||||||
// for it deterministically.
|
|
||||||
templ scifiButtonComponent(text, url, variant string) {
|
|
||||||
<a
|
|
||||||
href={ templ.SafeURL(safeHref(url)) }
|
|
||||||
class={ "scifi-mono uppercase tracking-widest text-xs px-5 py-3 scifi-focus inline-flex items-center justify-center gap-2", buttonVariantClass(variant) }
|
|
||||||
style="font-family: var(--font-mono);"
|
|
||||||
>
|
|
||||||
<span>{ text }</span>
|
|
||||||
<span data-icon="chevron-right" aria-hidden="true">{ "→" }</span>
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
|
|
||||||
// buttonVariantClass picks the visual treatment.
|
|
||||||
func buttonVariantClass(variant string) string {
|
|
||||||
switch variant {
|
|
||||||
case "outline":
|
|
||||||
return "hairline text-foreground bg-transparent"
|
|
||||||
case "destructive":
|
|
||||||
return "bg-destructive text-destructive-foreground"
|
|
||||||
default:
|
|
||||||
return "bg-primary text-primary-foreground"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// scifiButtonComponent renders the Sci-Fi Clean button. The `→` chevron is a
|
|
||||||
// literal U+2192 inside an explicit data-icon span so UAT §13.14 can grep
|
|
||||||
// for it deterministically.
|
|
||||||
func scifiButtonComponent(text, url, variant string) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var1 == nil {
|
|
||||||
templ_7745c5c3_Var1 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
var templ_7745c5c3_Var2 = []any{"scifi-mono uppercase tracking-widest text-xs px-5 py-3 scifi-focus inline-flex items-center justify-center gap-2", buttonVariantClass(variant)}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<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(safeHref(url)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 8, Col: 37}
|
|
||||||
}
|
|
||||||
_, 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, 2, "\" 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_Var2).String())
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.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, 3, "\" style=\"font-family: var(--font-mono);\"><span>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 12, Col: 14}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</span> <span data-icon=\"chevron-right\" aria-hidden=\"true\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var6 string
|
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("→")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 13, Col: 60}
|
|
||||||
}
|
|
||||||
_, 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, 5, "</span></a>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// buttonVariantClass picks the visual treatment.
|
|
||||||
func buttonVariantClass(variant string) string {
|
|
||||||
switch variant {
|
|
||||||
case "outline":
|
|
||||||
return "hairline text-foreground bg-transparent"
|
|
||||||
case "destructive":
|
|
||||||
return "bg-destructive text-destructive-foreground"
|
|
||||||
default:
|
|
||||||
return "bg-primary text-primary-foreground"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
119
css.go
119
css.go
@ -1,119 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// scifiCleanInputCSS is appended to the host Tailwind input.css via CSSManifest.
|
|
||||||
//
|
|
||||||
// Contents:
|
|
||||||
// 1. CSS-variable fallback stacks for --font-heading / --font-body / --font-mono.
|
|
||||||
// Per docs/FONTS.md (wave-1 policy), the theme bundles no fonts and consumes
|
|
||||||
// fonts exclusively via these variables. The fallback stacks intentionally
|
|
||||||
// already approximate Sci-Fi Clean's aesthetic so the theme looks right
|
|
||||||
// before the admin picks any Google Fonts.
|
|
||||||
// 2. .hairline utility — exactly border: 1px solid hsl(var(--border)).
|
|
||||||
// UAT §13.5 mandates 1px width; do not raise.
|
|
||||||
// 3. .bg-grid utility — translucent blueprint grid as a CSS gradient.
|
|
||||||
// Uses currentColor + opacity to track --foreground.
|
|
||||||
// 4. .tabular-nums / .mono-numerals helpers — UAT §13.7 wants
|
|
||||||
// font-variant-numeric: tabular-nums on every mission_stat value.
|
|
||||||
// 5. .scrim utility — required scrim layer for full-bleed hero text (UAT §6).
|
|
||||||
//
|
|
||||||
// The literal substrings 'Space Grotesk', 'JetBrains Mono', '.hairline', '.bg-grid'
|
|
||||||
// must appear here verbatim (UAT §13.4).
|
|
||||||
const scifiCleanInputCSS = `
|
|
||||||
/* === Sci-Fi Clean: font-family fallback variables ===
|
|
||||||
* The site admin assigns real fonts via the typography settings; until then,
|
|
||||||
* the variables fall through to the stacks below. 'Space Grotesk', 'Inter',
|
|
||||||
* and 'JetBrains Mono' are spec §5 recommendations, available in the Google
|
|
||||||
* Fonts picker.
|
|
||||||
*/
|
|
||||||
:root {
|
|
||||||
--font-heading: "Space Grotesk", "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
--font-body: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Sci-Fi Clean: utilities ===
|
|
||||||
* Hairline rules and a translucent blueprint grid are the two utility classes
|
|
||||||
* the theme uses heavily. Tailwind's defaults cover everything else.
|
|
||||||
*/
|
|
||||||
.hairline {
|
|
||||||
border: 1px solid hsl(var(--border));
|
|
||||||
}
|
|
||||||
|
|
||||||
.hairline-t {
|
|
||||||
border-top: 1px solid hsl(var(--border));
|
|
||||||
}
|
|
||||||
|
|
||||||
.hairline-b {
|
|
||||||
border-bottom: 1px solid hsl(var(--border));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-grid {
|
|
||||||
background-color: hsl(var(--background));
|
|
||||||
background-image:
|
|
||||||
linear-gradient(to right, hsl(var(--border) / 0.6) 1px, transparent 1px),
|
|
||||||
linear-gradient(to bottom, hsl(var(--border) / 0.6) 1px, transparent 1px);
|
|
||||||
background-size: 32px 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mono-numerals {
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabular-nums {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrim {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrim::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background-color: hsl(var(--background) / 0.65);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrim > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Sci-Fi Clean: focus rings ===
|
|
||||||
* Use the --ring token (a precise technical blue) for all focus states so
|
|
||||||
* the keyboard cursor is visible against either preset.
|
|
||||||
*/
|
|
||||||
.scifi-focus:focus-visible {
|
|
||||||
outline: 2px solid hsl(var(--ring));
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Sci-Fi Clean: chevron ===
|
|
||||||
* Right-arrow chevron used in ScifiButtonBlock; encoded as Unicode so it
|
|
||||||
* never breaks across renderers (UAT §13.14).
|
|
||||||
*/
|
|
||||||
.scifi-chevron::after {
|
|
||||||
content: " \2192";
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Sci-Fi Clean: heading family ===
|
|
||||||
* The host shadcn layer doesn't apply --font-heading by default; wire it
|
|
||||||
* up here for the four heading levels we render.
|
|
||||||
*/
|
|
||||||
.scifi-h1, .scifi-h2, .scifi-h3, .scifi-h4 {
|
|
||||||
font-family: var(--font-heading);
|
|
||||||
font-feature-settings: "ss01" on;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scifi-body {
|
|
||||||
font-family: var(--font-body);
|
|
||||||
}
|
|
||||||
|
|
||||||
.scifi-mono {
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DiagramCaptionBlockMeta defines metadata for the diagram-caption block.
|
|
||||||
var DiagramCaptionBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "diagram_caption",
|
|
||||||
Title: "Diagram Caption",
|
|
||||||
Description: "Annotated technical figure with a Fig. NN. heading and optional callout pins.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiagramCalloutPin is a percent-positioned overlay pin.
|
|
||||||
type DiagramCalloutPin struct {
|
|
||||||
X float64
|
|
||||||
Y float64
|
|
||||||
Label string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiagramCaptionData drives the templ render.
|
|
||||||
type DiagramCaptionData struct {
|
|
||||||
Image string
|
|
||||||
FigureNumber string
|
|
||||||
Title string
|
|
||||||
Body string
|
|
||||||
CalloutPins []DiagramCalloutPin
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiagramCaptionBlock renders the diagram-caption block.
|
|
||||||
// Content shape: {"image": "media:...", "figureNumber": "...", "title": "...", "body": "...",
|
|
||||||
// "calloutPins": [{"x": 12, "y": 50, "label": "..."}]}
|
|
||||||
func DiagramCaptionBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := DiagramCaptionData{
|
|
||||||
Image: blocks.ResolveMediaPath(getString(content, "image")),
|
|
||||||
FigureNumber: getString(content, "figureNumber"),
|
|
||||||
Title: getString(content, "title"),
|
|
||||||
Body: getString(content, "body"),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, raw := range getSlice(content, "calloutPins") {
|
|
||||||
data.CalloutPins = append(data.CalloutPins, DiagramCalloutPin{
|
|
||||||
X: getFloat(raw, "x", 0),
|
|
||||||
Y: getFloat(raw, "y", 0),
|
|
||||||
Label: getString(raw, "label"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = diagramCaptionComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// percentStyle returns a tiny inline style string positioning the pin in percent.
|
|
||||||
func percentStyle(x, y float64) string {
|
|
||||||
return "left: " + strconv.FormatFloat(x, 'f', 2, 64) + "%; top: " + strconv.FormatFloat(y, 'f', 2, 64) + "%;"
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// diagramCaptionComponent renders the figure with overlay pins and a Fig. heading.
|
|
||||||
templ diagramCaptionComponent(data DiagramCaptionData) {
|
|
||||||
<figure data-block="scifi-clean:diagram_caption" class="my-8 max-w-3xl mx-auto px-4">
|
|
||||||
<div class="relative hairline bg-card">
|
|
||||||
if data.Image == "" {
|
|
||||||
<div class="bg-grid aspect-video flex items-center justify-center">
|
|
||||||
<span class="scifi-mono text-sm text-muted-foreground uppercase tracking-widest">
|
|
||||||
No diagram yet
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
} else {
|
|
||||||
<img
|
|
||||||
src={ data.Image }
|
|
||||||
alt={ data.Title }
|
|
||||||
class="block w-full h-auto"
|
|
||||||
/>
|
|
||||||
for _, pin := range data.CalloutPins {
|
|
||||||
<span
|
|
||||||
class="absolute inline-flex items-center scifi-mono text-xs uppercase tracking-wider px-2 py-1 bg-card text-foreground hairline"
|
|
||||||
style={ percentStyle(pin.X, pin.Y) }
|
|
||||||
>
|
|
||||||
{ pin.Label }
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<figcaption class="mt-3 hairline-t pt-3">
|
|
||||||
<h4 class="scifi-h4 scifi-mono text-sm uppercase tracking-widest text-foreground">
|
|
||||||
{ "Fig. " }
|
|
||||||
if data.FigureNumber != "" {
|
|
||||||
{ data.FigureNumber }
|
|
||||||
} else {
|
|
||||||
{ "00" }
|
|
||||||
}
|
|
||||||
{ "." }
|
|
||||||
if data.Title != "" {
|
|
||||||
<span class="text-muted-foreground ml-2">{ data.Title }</span>
|
|
||||||
}
|
|
||||||
</h4>
|
|
||||||
if data.Body != "" {
|
|
||||||
<div class="scifi-body prose prose-sm max-w-none text-muted-foreground mt-2">
|
|
||||||
@templ.Raw(data.Body)
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
}
|
|
||||||
@ -1,210 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// diagramCaptionComponent renders the figure with overlay pins and a Fig. heading.
|
|
||||||
func diagramCaptionComponent(data DiagramCaptionData) 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=\"scifi-clean:diagram_caption\" class=\"my-8 max-w-3xl mx-auto px-4\"><div class=\"relative hairline bg-card\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Image == "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"bg-grid aspect-video flex items-center justify-center\"><span class=\"scifi-mono text-sm text-muted-foreground uppercase tracking-widest\">No diagram yet</span></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<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: `diagram_caption.templ`, Line: 15, Col: 21}
|
|
||||||
}
|
|
||||||
_, 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, 4, "\" alt=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Title)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 16, Col: 21}
|
|
||||||
}
|
|
||||||
_, 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, 5, "\" class=\"block w-full h-auto\"> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
for _, pin := range data.CalloutPins {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<span class=\"absolute inline-flex items-center scifi-mono text-xs uppercase tracking-wider px-2 py-1 bg-card text-foreground hairline\" style=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var4 string
|
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(percentStyle(pin.X, pin.Y))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 22, Col: 40}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(pin.Label)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 24, Col: 17}
|
|
||||||
}
|
|
||||||
_, 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, 8, "</span>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div><figcaption class=\"mt-3 hairline-t pt-3\"><h4 class=\"scifi-h4 scifi-mono text-sm uppercase tracking-widest text-foreground\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var6 string
|
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("Fig. ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 31, Col: 13}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.FigureNumber != "" {
|
|
||||||
var templ_7745c5c3_Var7 string
|
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(data.FigureNumber)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 33, Col: 24}
|
|
||||||
}
|
|
||||||
_, 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, 11, " ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var templ_7745c5c3_Var8 string
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("00")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 35, Col: 11}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var9 string
|
|
||||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(".")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 37, Col: 9}
|
|
||||||
}
|
|
||||||
_, 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, 13, " ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Title != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<span class=\"text-muted-foreground ml-2\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var10 string
|
|
||||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `diagram_caption.templ`, Line: 39, Col: 58}
|
|
||||||
}
|
|
||||||
_, 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, 15, "</span>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</h4>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Body != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<div class=\"scifi-body prose prose-sm max-w-none text-muted-foreground mt-2\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(data.Body).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</figcaption></figure>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ScifiEmailWrapper wraps body content in a branded Sci-Fi Clean email shell:
|
|
||||||
// 600px white card, hairline border, mono callsign top-right, instrument footer.
|
|
||||||
func ScifiEmailWrapper(body string, emailCtx templates.EmailContext) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = scifiEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
// scifiEmailBgColor / scifiEmailCardColor / scifiEmailBorderColor pull from the
|
|
||||||
// caller-provided EmailColors so the wrapper inherits the active preset.
|
|
||||||
func scifiEmailBgColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Background != "" {
|
|
||||||
return c.Colors.Background
|
|
||||||
}
|
|
||||||
return "#F6F7F8"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailCardColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Card != "" {
|
|
||||||
return c.Colors.Card
|
|
||||||
}
|
|
||||||
return "#FFFFFF"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailBorderColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Border != "" {
|
|
||||||
return c.Colors.Border
|
|
||||||
}
|
|
||||||
return "#D6D9DD"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailFgColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Foreground != "" {
|
|
||||||
return c.Colors.Foreground
|
|
||||||
}
|
|
||||||
return "#16202E"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailMutedColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.MutedForeground != "" {
|
|
||||||
return c.Colors.MutedForeground
|
|
||||||
}
|
|
||||||
return "#5C6776"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailCallsign(c templates.EmailContext) string {
|
|
||||||
if c.SiteSettings.SiteName != "" {
|
|
||||||
return "SCF / " + c.SiteSettings.SiteName
|
|
||||||
}
|
|
||||||
return "SCF-CLN"
|
|
||||||
}
|
|
||||||
|
|
||||||
// scifiEmailTemplate is the Sci-Fi Clean branded email wrapper.
|
|
||||||
templ scifiEmailTemplate(emailCtx templates.EmailContext, body string) {
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
<meta name="x-apple-disable-message-reformatting"/>
|
|
||||||
<title>{ emailCtx.SiteSettings.SiteName }</title>
|
|
||||||
<style type="text/css">
|
|
||||||
body, table, td, p, a, li {
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
img { border: 0; height: auto; outline: none; text-decoration: none; }
|
|
||||||
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
|
|
||||||
/* Mono numeral preservation across clients. */
|
|
||||||
.scifi-num {
|
|
||||||
font-family: ui-monospace, "JetBrains Mono", "Menlo", monospace !important;
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 620px) {
|
|
||||||
.scifi-email-container { width: 100% !important; max-width: 100% !important; }
|
|
||||||
.scifi-pad { padding-left: 20px !important; padding-right: 20px !important; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body style={ fmt.Sprintf("background-color: %s; margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: %s;", scifiEmailBgColor(emailCtx), scifiEmailFgColor(emailCtx)) }>
|
|
||||||
if emailCtx.PreviewText != "" {
|
|
||||||
<div style="display: none; max-height: 0; overflow: hidden;">{ emailCtx.PreviewText }</div>
|
|
||||||
}
|
|
||||||
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
||||||
<tr>
|
|
||||||
<td align="center" style={ fmt.Sprintf("padding: 32px 12px; background-color: %s;", scifiEmailBgColor(emailCtx)) }>
|
|
||||||
<table
|
|
||||||
role="presentation"
|
|
||||||
class="scifi-email-container"
|
|
||||||
width="600"
|
|
||||||
cellspacing="0"
|
|
||||||
cellpadding="0"
|
|
||||||
border="0"
|
|
||||||
style={ fmt.Sprintf("max-width: 600px; background-color: %s; border: 1px solid %s;", scifiEmailCardColor(emailCtx), scifiEmailBorderColor(emailCtx)) }
|
|
||||||
>
|
|
||||||
<tr>
|
|
||||||
<td class="scifi-pad" style={ fmt.Sprintf("padding: 20px 28px; border-bottom: 1px solid %s;", scifiEmailBorderColor(emailCtx)) }>
|
|
||||||
<table width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
||||||
<tr>
|
|
||||||
<td align="left" style={ fmt.Sprintf("font-family: 'Space Grotesk', 'Inter', sans-serif; font-weight: 600; font-size: 16px; letter-spacing: 0.02em; color: %s;", scifiEmailFgColor(emailCtx)) }>
|
|
||||||
{ emailCtx.SiteSettings.SiteName }
|
|
||||||
</td>
|
|
||||||
<td align="right" class="scifi-num" style={ fmt.Sprintf("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: %s;", scifiEmailMutedColor(emailCtx)) }>
|
|
||||||
{ scifiEmailCallsign(emailCtx) }
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="scifi-pad" style={ fmt.Sprintf("padding: 28px; font-size: 15px; line-height: 1.55; color: %s;", scifiEmailFgColor(emailCtx)) }>
|
|
||||||
@templ.Raw(body)
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="scifi-pad" style={ fmt.Sprintf("padding: 16px 28px; border-top: 1px solid %s; background-color: %s;", scifiEmailBorderColor(emailCtx), scifiEmailCardColor(emailCtx)) }>
|
|
||||||
<table width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
||||||
<tr>
|
|
||||||
<td class="scifi-num" align="left" style={ fmt.Sprintf("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: %s;", scifiEmailMutedColor(emailCtx)) }>
|
|
||||||
{ emailCtx.SiteSettings.SiteURL }
|
|
||||||
</td>
|
|
||||||
if emailCtx.UnsubscribeURL != "" {
|
|
||||||
<td class="scifi-num" align="right" style={ fmt.Sprintf("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;") }>
|
|
||||||
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style={ fmt.Sprintf("color: %s; text-decoration: underline;", scifiEmailMutedColor(emailCtx)) }>Unsubscribe</a>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
@ -1,340 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
// scifiEmailBgColor / scifiEmailCardColor / scifiEmailBorderColor pull from the
|
|
||||||
// caller-provided EmailColors so the wrapper inherits the active preset.
|
|
||||||
func scifiEmailBgColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Background != "" {
|
|
||||||
return c.Colors.Background
|
|
||||||
}
|
|
||||||
return "#F6F7F8"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailCardColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Card != "" {
|
|
||||||
return c.Colors.Card
|
|
||||||
}
|
|
||||||
return "#FFFFFF"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailBorderColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Border != "" {
|
|
||||||
return c.Colors.Border
|
|
||||||
}
|
|
||||||
return "#D6D9DD"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailFgColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.Foreground != "" {
|
|
||||||
return c.Colors.Foreground
|
|
||||||
}
|
|
||||||
return "#16202E"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailMutedColor(c templates.EmailContext) string {
|
|
||||||
if c.Colors.MutedForeground != "" {
|
|
||||||
return c.Colors.MutedForeground
|
|
||||||
}
|
|
||||||
return "#5C6776"
|
|
||||||
}
|
|
||||||
|
|
||||||
func scifiEmailCallsign(c templates.EmailContext) string {
|
|
||||||
if c.SiteSettings.SiteName != "" {
|
|
||||||
return "SCF / " + c.SiteSettings.SiteName
|
|
||||||
}
|
|
||||||
return "SCF-CLN"
|
|
||||||
}
|
|
||||||
|
|
||||||
// scifiEmailTemplate is the Sci-Fi Clean branded email wrapper.
|
|
||||||
func scifiEmailTemplate(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\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"x-apple-disable-message-reformatting\"><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: 61, 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 {\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\timg { border: 0; height: auto; outline: none; text-decoration: none; }\n\t\t\t\tbody { margin: 0 !important; padding: 0 !important; width: 100% !important; }\n\t\t\t\t/* Mono numeral preservation across clients. */\n\t\t\t\t.scifi-num {\n\t\t\t\t\tfont-family: ui-monospace, \"JetBrains Mono\", \"Menlo\", monospace !important;\n\t\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\t}\n\t\t\t\t@media only screen and (max-width: 620px) {\n\t\t\t\t\t.scifi-email-container { width: 100% !important; max-width: 100% !important; }\n\t\t\t\t\t.scifi-pad { padding-left: 20px !important; padding-right: 20px !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: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: %s;", scifiEmailBgColor(emailCtx), scifiEmailFgColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 80, Col: 225}
|
|
||||||
}
|
|
||||||
_, 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;\">")
|
|
||||||
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: 82, Col: 87}
|
|
||||||
}
|
|
||||||
_, 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 12px; background-color: %s;", scifiEmailBgColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 86, Col: 117}
|
|
||||||
}
|
|
||||||
_, 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=\"scifi-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;", scifiEmailCardColor(emailCtx), scifiEmailBorderColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 94, Col: 155}
|
|
||||||
}
|
|
||||||
_, 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 class=\"scifi-pad\" 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: 20px 28px; border-bottom: 1px solid %s;", scifiEmailBorderColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 97, Col: 134}
|
|
||||||
}
|
|
||||||
_, 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, "\"><table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tr><td align=\"left\" style=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var8 string
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("font-family: 'Space Grotesk', 'Inter', sans-serif; font-weight: 600; font-size: 16px; letter-spacing: 0.02em; color: %s;", scifiEmailFgColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 100, Col: 200}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var9 string
|
|
||||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteName)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 101, Col: 44}
|
|
||||||
}
|
|
||||||
_, 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, "</td><td align=\"right\" class=\"scifi-num\" 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("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: %s;", scifiEmailMutedColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 103, Col: 236}
|
|
||||||
}
|
|
||||||
_, 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, 12, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var11 string
|
|
||||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(scifiEmailCallsign(emailCtx))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 104, Col: 42}
|
|
||||||
}
|
|
||||||
_, 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, 13, "</td></tr></table></td></tr><tr><td class=\"scifi-pad\" 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: 28px; font-size: 15px; line-height: 1.55; color: %s;", scifiEmailFgColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 111, Col: 143}
|
|
||||||
}
|
|
||||||
_, 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, 14, "\">")
|
|
||||||
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, 15, "</td></tr><tr><td class=\"scifi-pad\" 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: 16px 28px; border-top: 1px solid %s; background-color: %s;", scifiEmailBorderColor(emailCtx), scifiEmailCardColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 116, Col: 184}
|
|
||||||
}
|
|
||||||
_, 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, 16, "\"><table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tr><td class=\"scifi-num\" align=\"left\" 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("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: %s;", scifiEmailMutedColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 119, Col: 235}
|
|
||||||
}
|
|
||||||
_, 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, 17, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var15 string
|
|
||||||
templ_7745c5c3_Var15, 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: 120, Col: 43}
|
|
||||||
}
|
|
||||||
_, 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, 18, "</td>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if emailCtx.UnsubscribeURL != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<td class=\"scifi-num\" align=\"right\" 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("font-family: ui-monospace, 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;"))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 123, Col: 194}
|
|
||||||
}
|
|
||||||
_, 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, 20, "\"><a href=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var17 templ.SafeURL
|
|
||||||
templ_7745c5c3_Var17, 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: 124, Col: 61}
|
|
||||||
}
|
|
||||||
_, 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, 21, "\" style=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var18 string
|
|
||||||
templ_7745c5c3_Var18, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("color: %s; text-decoration: underline;", scifiEmailMutedColor(emailCtx)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 124, Col: 157}
|
|
||||||
}
|
|
||||||
_, 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, 22, "\">Unsubscribe</a></td>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</tr></table></td></tr></table></td></tr></table></body></html>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
60
embed.go
60
embed.go
@ -1,60 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed assets/*
|
|
||||||
var assetsFS embed.FS
|
|
||||||
|
|
||||||
//go:embed schemas/*
|
|
||||||
var schemasFS embed.FS
|
|
||||||
|
|
||||||
//go:embed presets.json
|
|
||||||
var presetsData []byte
|
|
||||||
|
|
||||||
//go:embed fonts.json
|
|
||||||
var fontsData []byte
|
|
||||||
|
|
||||||
//go:embed plugin.mod
|
|
||||||
var pluginModBytes []byte
|
|
||||||
|
|
||||||
// Assets returns the embedded assets filesystem.
|
|
||||||
func Assets() fs.FS {
|
|
||||||
sub, _ := fs.Sub(assetsFS, "assets")
|
|
||||||
return sub
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schemas returns the embedded schemas filesystem.
|
|
||||||
func Schemas() fs.FS {
|
|
||||||
sub, _ := fs.Sub(schemasFS, "schemas")
|
|
||||||
return sub
|
|
||||||
}
|
|
||||||
|
|
||||||
// AssetsHandler returns an http.Handler that serves the embedded assets.
|
|
||||||
func AssetsHandler() http.Handler {
|
|
||||||
return http.FileServer(http.FS(Assets()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThemePresets returns the embedded theme presets JSON.
|
|
||||||
func ThemePresets() []byte {
|
|
||||||
return presetsData
|
|
||||||
}
|
|
||||||
|
|
||||||
// BundledFonts returns the embedded fonts manifest JSON.
|
|
||||||
func BundledFonts() []byte {
|
|
||||||
return fontsData
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThemeCSSManifest returns the CSS manifest containing the theme's custom
|
|
||||||
// utilities (.hairline, .bg-grid) and font-family fallback CSS variables.
|
|
||||||
// It is injected into the host Tailwind input by the CMS at build time.
|
|
||||||
func ThemeCSSManifest() *plugin.CSSManifest {
|
|
||||||
return &plugin.CSSManifest{
|
|
||||||
InputCSSAppend: scifiCleanInputCSS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
footer.go
58
footer.go
@ -1,58 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FooterBlockMeta defines metadata for the instrument footer block.
|
|
||||||
var FooterBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "footer",
|
|
||||||
Title: "Instrument Footer",
|
|
||||||
Description: "Hairline-rule footer with callsign, optional signup, and link list.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryLayout,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FooterLink is one footer link entry.
|
|
||||||
type FooterLink struct {
|
|
||||||
Text string
|
|
||||||
URL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// FooterData drives the templ render.
|
|
||||||
type FooterData struct {
|
|
||||||
ShowSignup bool
|
|
||||||
Callsign string
|
|
||||||
Links []FooterLink
|
|
||||||
}
|
|
||||||
|
|
||||||
// FooterBlock renders the footer.
|
|
||||||
// Content shape: {"showSignup": false, "callsign": "SCF-CLN", "links": [{"text": "...", "url": "..."}]}
|
|
||||||
func FooterBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := FooterData{
|
|
||||||
ShowSignup: getBool(content, "showSignup", false),
|
|
||||||
Callsign: getStringDefault(content, "callsign", "SCF-CLN"),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, raw := range getSlice(content, "links") {
|
|
||||||
data.Links = append(data.Links, FooterLink{
|
|
||||||
Text: getString(raw, "text"),
|
|
||||||
URL: getString(raw, "url"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = footerComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// safeHref returns # for blank URLs so the templ.SafeURL helper has something to chew on.
|
|
||||||
func safeHref(u string) string {
|
|
||||||
if u == "" {
|
|
||||||
return "#"
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
69
footer.templ
69
footer.templ
@ -1,69 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// footerComponent renders the instrument-bar footer.
|
|
||||||
// UAT §13.10 requires a callsign element rendered in JetBrains Mono and at
|
|
||||||
// least one .hairline rule above the footer.
|
|
||||||
templ footerComponent(data FooterData) {
|
|
||||||
<div data-block="scifi-clean:footer" class="w-full">
|
|
||||||
<div class="hairline-t pt-8 pb-10">
|
|
||||||
<div class="max-w-6xl mx-auto px-4">
|
|
||||||
<div class="flex flex-col md:flex-row md:items-start md:justify-between gap-8">
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div
|
|
||||||
data-scifi-callsign
|
|
||||||
class="scifi-mono uppercase tracking-widest text-xs text-foreground"
|
|
||||||
style="font-family: var(--font-mono);"
|
|
||||||
>
|
|
||||||
{ data.Callsign }
|
|
||||||
</div>
|
|
||||||
<p class="scifi-body text-sm text-muted-foreground max-w-md">
|
|
||||||
Telemetry, mission briefs, and engineering notes from this surface.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
if len(data.Links) > 0 {
|
|
||||||
<ul class="space-y-2 scifi-body text-sm">
|
|
||||||
for _, link := range data.Links {
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href={ templ.SafeURL(safeHref(link.URL)) }
|
|
||||||
class="text-muted-foreground hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
{ link.Text }
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.ShowSignup {
|
|
||||||
<form class="space-y-2 max-w-xs" method="post" action="/subscribe">
|
|
||||||
<label class="scifi-mono uppercase text-xs tracking-widest text-muted-foreground block">
|
|
||||||
Mission updates
|
|
||||||
</label>
|
|
||||||
<div class="flex hairline">
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
name="email"
|
|
||||||
required
|
|
||||||
placeholder="ops@station.local"
|
|
||||||
class="scifi-body flex-1 px-3 py-2 bg-card text-foreground text-sm focus:outline-none scifi-focus"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="scifi-mono uppercase text-xs tracking-widest px-4 py-2 bg-primary text-primary-foreground scifi-chevron scifi-focus"
|
|
||||||
>
|
|
||||||
Subscribe
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="mt-8 hairline-t pt-4 flex items-center justify-between scifi-mono text-xs uppercase tracking-widest text-muted-foreground tabular-nums">
|
|
||||||
<span>Project Aurora</span>
|
|
||||||
<span>v0.1.0</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
108
footer_templ.go
108
footer_templ.go
@ -1,108 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// footerComponent renders the instrument-bar footer.
|
|
||||||
// UAT §13.10 requires a callsign element rendered in JetBrains Mono and at
|
|
||||||
// least one .hairline rule above the 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, "<div data-block=\"scifi-clean:footer\" class=\"w-full\"><div class=\"hairline-t pt-8 pb-10\"><div class=\"max-w-6xl mx-auto px-4\"><div class=\"flex flex-col md:flex-row md:items-start md:justify-between gap-8\"><div class=\"space-y-2\"><div data-scifi-callsign class=\"scifi-mono uppercase tracking-widest text-xs text-foreground\" style=\"font-family: var(--font-mono);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var2 string
|
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Callsign)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 17, Col: 22}
|
|
||||||
}
|
|
||||||
_, 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, "</div><p class=\"scifi-body text-sm text-muted-foreground max-w-md\">Telemetry, mission briefs, and engineering notes from this surface.</p></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if len(data.Links) > 0 {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<ul class=\"space-y-2 scifi-body text-sm\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
for _, link := range data.Links {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<li><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(safeHref(link.URL)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 29, Col: 50}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" class=\"text-muted-foreground hover:text-foreground transition-colors\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var4 string
|
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(link.Text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer.templ`, Line: 32, Col: 21}
|
|
||||||
}
|
|
||||||
_, 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, 6, "</a></li>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</ul>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if data.ShowSignup {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<form class=\"space-y-2 max-w-xs\" method=\"post\" action=\"/subscribe\"><label class=\"scifi-mono uppercase text-xs tracking-widest text-muted-foreground block\">Mission updates</label><div class=\"flex hairline\"><input type=\"email\" name=\"email\" required placeholder=\"ops@station.local\" class=\"scifi-body flex-1 px-3 py-2 bg-card text-foreground text-sm focus:outline-none scifi-focus\"> <button type=\"submit\" class=\"scifi-mono uppercase text-xs tracking-widest px-4 py-2 bg-primary text-primary-foreground scifi-chevron scifi-focus\">Subscribe</button></div></form>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div><div class=\"mt-8 hairline-t pt-4 flex items-center justify-between scifi-mono text-xs uppercase tracking-widest text-muted-foreground tabular-nums\"><span>Project Aurora</span> <span>v0.1.0</span></div></div></div></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
20
go.mod
20
go.mod
@ -1,20 +0,0 @@
|
|||||||
module git.dev.alexdunmow.com/block/themes/scifi-clean
|
|
||||||
|
|
||||||
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
46
go.sum
@ -1,46 +0,0 @@
|
|||||||
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
|
||||||
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
|
||||||
git.dev.alexdunmow.com/block/core v0.15.2 h1:qTjJxa1pClxwehkdTxXiJDpHQLr5DoXBUCa40QRO0L8=
|
|
||||||
git.dev.alexdunmow.com/block/core v0.15.2/go.mod h1:A+mgA9oeWoPhXruv4Mjpywwl2A9B5I3cKzlJjalBdlE=
|
|
||||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
|
||||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
|
||||||
github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
|
|
||||||
github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
|
||||||
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
|
|
||||||
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
|
||||||
github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
|
|
||||||
github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
|
|
||||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
|
||||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
|
||||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
|
||||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
|
||||||
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
|
||||||
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
|
||||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
|
||||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ScifiHeadingBlock renders a heading with the Sci-Fi Clean treatment:
|
|
||||||
// Space Grotesk weights, optional mono kicker prefix ("FIG / SEC / SYS" etc.).
|
|
||||||
// Reuses the built-in heading schema; reads optional kicker via content["kicker"].
|
|
||||||
func ScifiHeadingBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
text := getString(content, "text")
|
|
||||||
textClass := getString(content, "textClass")
|
|
||||||
kicker := getString(content, "kicker")
|
|
||||||
level := parseHeadingLevel(content)
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = scifiHeadingComponent(level, text, textClass, kicker).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseHeadingLevel coerces an incoming heading level to 1..6, defaulting to 2.
|
|
||||||
func parseHeadingLevel(content map[string]any) int {
|
|
||||||
if level, ok := content["level"].(float64); ok {
|
|
||||||
l := int(level)
|
|
||||||
if l >= 1 && l <= 6 {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if level, ok := content["level"].(int); ok {
|
|
||||||
if level >= 1 && level <= 6 {
|
|
||||||
return level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if level, ok := content["level"].(string); ok {
|
|
||||||
if l, err := strconv.Atoi(level); err == nil && l >= 1 && l <= 6 {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// scifiHeadingBaseClass returns level-specific tracking + weight classes.
|
|
||||||
func scifiHeadingBaseClass(level int) string {
|
|
||||||
switch level {
|
|
||||||
case 1:
|
|
||||||
return "scifi-h1 text-4xl md:text-5xl font-medium tracking-tight"
|
|
||||||
case 2:
|
|
||||||
return "scifi-h2 text-3xl font-medium tracking-tight"
|
|
||||||
case 3:
|
|
||||||
return "scifi-h3 text-2xl font-medium"
|
|
||||||
case 4:
|
|
||||||
return "scifi-h4 text-xl font-medium"
|
|
||||||
case 5:
|
|
||||||
return "scifi-h4 text-lg font-medium"
|
|
||||||
case 6:
|
|
||||||
return "scifi-h4 text-base font-medium uppercase tracking-widest"
|
|
||||||
default:
|
|
||||||
return "scifi-h2 text-3xl font-medium tracking-tight"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// scifiHeadingComponent renders a heading with an optional mono kicker rail.
|
|
||||||
templ scifiHeadingComponent(level int, text, textClass, kicker string) {
|
|
||||||
<div class="my-6">
|
|
||||||
if kicker != "" {
|
|
||||||
<div class="scifi-mono uppercase tracking-widest text-xs text-accent mb-2">
|
|
||||||
{ kicker }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
switch level {
|
|
||||||
case 1:
|
|
||||||
<h1 class={ scifiHeadingBaseClass(1), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h1>
|
|
||||||
case 2:
|
|
||||||
<h2 class={ scifiHeadingBaseClass(2), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h2>
|
|
||||||
case 3:
|
|
||||||
<h3 class={ scifiHeadingBaseClass(3), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h3>
|
|
||||||
case 4:
|
|
||||||
<h4 class={ scifiHeadingBaseClass(4), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h4>
|
|
||||||
case 5:
|
|
||||||
<h5 class={ scifiHeadingBaseClass(5), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h5>
|
|
||||||
case 6:
|
|
||||||
<h6 class={ scifiHeadingBaseClass(6), "text-muted-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h6>
|
|
||||||
default:
|
|
||||||
<h2 class={ scifiHeadingBaseClass(2), "text-foreground", textClass } style="font-family: var(--font-heading);">{ text }</h2>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@ -1,338 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// scifiHeadingBaseClass returns level-specific tracking + weight classes.
|
|
||||||
func scifiHeadingBaseClass(level int) string {
|
|
||||||
switch level {
|
|
||||||
case 1:
|
|
||||||
return "scifi-h1 text-4xl md:text-5xl font-medium tracking-tight"
|
|
||||||
case 2:
|
|
||||||
return "scifi-h2 text-3xl font-medium tracking-tight"
|
|
||||||
case 3:
|
|
||||||
return "scifi-h3 text-2xl font-medium"
|
|
||||||
case 4:
|
|
||||||
return "scifi-h4 text-xl font-medium"
|
|
||||||
case 5:
|
|
||||||
return "scifi-h4 text-lg font-medium"
|
|
||||||
case 6:
|
|
||||||
return "scifi-h4 text-base font-medium uppercase tracking-widest"
|
|
||||||
default:
|
|
||||||
return "scifi-h2 text-3xl font-medium tracking-tight"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// scifiHeadingComponent renders a heading with an optional mono kicker rail.
|
|
||||||
func scifiHeadingComponent(level int, text, textClass, kicker 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, "<div class=\"my-6\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if kicker != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"scifi-mono uppercase tracking-widest text-xs text-accent mb-2\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var2 string
|
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(kicker)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 28, Col: 12}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch level {
|
|
||||||
case 1:
|
|
||||||
var templ_7745c5c3_Var3 = []any{scifiHeadingBaseClass(1), "text-foreground", textClass}
|
|
||||||
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, 4, "<h1 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: `heading_override.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, 5, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 33, Col: 121}
|
|
||||||
}
|
|
||||||
_, 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, "</h1>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
var templ_7745c5c3_Var6 = []any{scifiHeadingBaseClass(2), "text-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<h2 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var7 string
|
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var6).String())
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var8 string
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 35, Col: 121}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</h2>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
var templ_7745c5c3_Var9 = []any{scifiHeadingBaseClass(3), "text-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<h3 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var10 string
|
|
||||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var9).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_Var10)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var11 string
|
|
||||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 37, Col: 121}
|
|
||||||
}
|
|
||||||
_, 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, 12, "</h3>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
var templ_7745c5c3_Var12 = []any{scifiHeadingBaseClass(4), "text-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<h4 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var13 string
|
|
||||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var12).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_Var13)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var14 string
|
|
||||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 39, Col: 121}
|
|
||||||
}
|
|
||||||
_, 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, 15, "</h4>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
case 5:
|
|
||||||
var templ_7745c5c3_Var15 = []any{scifiHeadingBaseClass(5), "text-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var15...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<h5 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var16 string
|
|
||||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var15).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_Var16)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var17 string
|
|
||||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 41, Col: 121}
|
|
||||||
}
|
|
||||||
_, 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, 18, "</h5>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
var templ_7745c5c3_Var18 = []any{scifiHeadingBaseClass(6), "text-muted-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var18...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<h6 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var19 string
|
|
||||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var18).String())
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var20 string
|
|
||||||
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 43, Col: 127}
|
|
||||||
}
|
|
||||||
_, 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, 21, "</h6>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
var templ_7745c5c3_Var21 = []any{scifiHeadingBaseClass(2), "text-foreground", textClass}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var21...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<h2 class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var22 string
|
|
||||||
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var21).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_Var22)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" style=\"font-family: var(--font-heading);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var23 string
|
|
||||||
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 45, Col: 121}
|
|
||||||
}
|
|
||||||
_, 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, 24, "</h2>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
82
helpers.go
82
helpers.go
@ -1,82 +0,0 @@
|
|||||||
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 ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// getStringDefault returns the string at key, falling back to def if missing/blank.
|
|
||||||
func getStringDefault(content map[string]any, key, def string) string {
|
|
||||||
if v := getString(content, key); v != "" {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBool extracts a boolean from a content map. Accepts native bool, string ("true"/"1"),
|
|
||||||
// or numeric truthiness. Returns def when no value is present or parseable.
|
|
||||||
func getBool(content map[string]any, key string, def bool) bool {
|
|
||||||
if v, ok := content[key]; ok {
|
|
||||||
switch t := v.(type) {
|
|
||||||
case bool:
|
|
||||||
return t
|
|
||||||
case string:
|
|
||||||
switch t {
|
|
||||||
case "true", "TRUE", "True", "1", "yes", "on":
|
|
||||||
return true
|
|
||||||
case "false", "FALSE", "False", "0", "no", "off":
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
return t != 0
|
|
||||||
case int:
|
|
||||||
return t != 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
// getSlice extracts a slice of maps from content under key. Returns nil if not a slice.
|
|
||||||
func getSlice(content map[string]any, key string) []map[string]any {
|
|
||||||
if v, ok := content[key].([]any); ok {
|
|
||||||
out := make([]map[string]any, 0, len(v))
|
|
||||||
for _, item := range v {
|
|
||||||
if m, ok := item.(map[string]any); ok {
|
|
||||||
out = append(out, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getMap returns the map at key, or nil.
|
|
||||||
func getMap(content map[string]any, key string) map[string]any {
|
|
||||||
if m, ok := content[key].(map[string]any); ok {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFloat returns the float at key, or def if missing / wrong type.
|
|
||||||
func getFloat(content map[string]any, key string, def float64) float64 {
|
|
||||||
if v, ok := content[key].(float64); ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if v, ok := content[key].(int); ok {
|
|
||||||
return float64(v)
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalizeTrend coerces an incoming trend string to {up, down, flat}, defaulting to flat.
|
|
||||||
func normalizeTrend(s string) string {
|
|
||||||
switch s {
|
|
||||||
case "up", "down", "flat":
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return "flat"
|
|
||||||
}
|
|
||||||
17
main.go
17
main.go
@ -1,17 +0,0 @@
|
|||||||
//go:build wasip1
|
|
||||||
|
|
||||||
// Package main compiles the scifi-clean 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
|
|
||||||
140
manifest.yaml
Normal file
140
manifest.yaml
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
# Sci-Fi Clean theme — codeless .bnp manifest (WO-WZ-021 Phase B1).
|
||||||
|
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
|
||||||
|
theme_presets: presets.json
|
||||||
|
bundled_fonts: fonts.json
|
||||||
|
master_pages: master_pages.json
|
||||||
|
|
||||||
|
system_templates:
|
||||||
|
- key: scifi-clean
|
||||||
|
title: Sci-Fi Clean
|
||||||
|
description: "Minimalist futurist theme for aerospace, robotics, and R&D — off-white surfaces, technical blue, signal-orange accents, mono numerals."
|
||||||
|
|
||||||
|
page_templates:
|
||||||
|
- system: scifi-clean
|
||||||
|
key: default
|
||||||
|
title: Default
|
||||||
|
description: "Standard cleanroom layout with header rail, main column, and footer instrument panel."
|
||||||
|
slots: [header, main, footer]
|
||||||
|
- system: scifi-clean
|
||||||
|
key: landing
|
||||||
|
title: Landing
|
||||||
|
description: "Hero diagram + spec strip + CTA banner."
|
||||||
|
slots: [hero, specs, main, cta, footer]
|
||||||
|
- system: scifi-clean
|
||||||
|
key: article
|
||||||
|
title: Article
|
||||||
|
description: "Narrow column with rail metadata and figure margin."
|
||||||
|
slots: [header, rail, main, footer]
|
||||||
|
- system: scifi-clean
|
||||||
|
key: full-width
|
||||||
|
title: Full Width
|
||||||
|
description: "Edge-to-edge schematic surface for diagrams and dashboards."
|
||||||
|
slots: [header, main, footer]
|
||||||
|
|
||||||
|
template_overrides:
|
||||||
|
- { template: scifi-clean, block: heading }
|
||||||
|
- { template: scifi-clean, block: text }
|
||||||
|
- { template: scifi-clean, block: button }
|
||||||
|
|
||||||
|
email_wrappers:
|
||||||
|
- scifi-clean
|
||||||
|
|
||||||
|
css:
|
||||||
|
input_css_append: |
|
||||||
|
/* === Sci-Fi Clean: font-family fallback variables ===
|
||||||
|
* The site admin assigns real fonts via the typography settings; until then,
|
||||||
|
* the variables fall through to the stacks below. 'Space Grotesk', 'Inter',
|
||||||
|
* and 'JetBrains Mono' are spec §5 recommendations, available in the Google
|
||||||
|
* Fonts picker.
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--font-heading: "Space Grotesk", "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
--font-body: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Sci-Fi Clean: utilities ===
|
||||||
|
* Hairline rules and a translucent blueprint grid are the two utility classes
|
||||||
|
* the theme uses heavily. Tailwind's defaults cover everything else.
|
||||||
|
*/
|
||||||
|
.hairline {
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hairline-t {
|
||||||
|
border-top: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hairline-b {
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-grid {
|
||||||
|
background-color: hsl(var(--background));
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, hsl(var(--border) / 0.6) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, hsl(var(--border) / 0.6) 1px, transparent 1px);
|
||||||
|
background-size: 32px 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mono-numerals {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabular-nums {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrim {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrim::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: hsl(var(--background) / 0.65);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrim > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Sci-Fi Clean: focus rings ===
|
||||||
|
* Use the --ring token (a precise technical blue) for all focus states so
|
||||||
|
* the keyboard cursor is visible against either preset.
|
||||||
|
*/
|
||||||
|
.scifi-focus:focus-visible {
|
||||||
|
outline: 2px solid hsl(var(--ring));
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Sci-Fi Clean: chevron ===
|
||||||
|
* Right-arrow chevron used in ScifiButtonBlock; encoded as Unicode so it
|
||||||
|
* never breaks across renderers (UAT §13.14).
|
||||||
|
*/
|
||||||
|
.scifi-chevron::after {
|
||||||
|
content: " \2192";
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Sci-Fi Clean: heading family ===
|
||||||
|
* The host shadcn layer doesn't apply --font-heading by default; wire it
|
||||||
|
* up here for the four heading levels we render.
|
||||||
|
*/
|
||||||
|
.scifi-h1, .scifi-h2, .scifi-h3, .scifi-h4 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-feature-settings: "ss01" on;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scifi-body {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scifi-mono {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
25
master_pages.json
Normal file
25
master_pages.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "scifi-clean:default-master",
|
||||||
|
"title": "Sci-Fi Clean Default Master",
|
||||||
|
"page_templates": ["default", "article", "full-width"],
|
||||||
|
"blocks": [
|
||||||
|
{ "block_key": "navbar", "title": "Mission Header", "content": { "menuName": "main" }, "slot": "header", "sort_order": 0 },
|
||||||
|
{ "block_key": "scifi-clean:status_bar", "title": "System Status Rail", "content": { "showClock": true, "showBuild": true, "callsign": "SCF-CLN" }, "slot": "header", "sort_order": 10 },
|
||||||
|
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main", "placeholder": "Page payload" }, "slot": "main", "sort_order": 0 },
|
||||||
|
{ "block_key": "scifi-clean:footer", "title": "Instrument Footer", "content": { "showSignup": true, "callsign": "SCF-CLN" }, "slot": "footer", "sort_order": 0 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "scifi-clean:landing-master",
|
||||||
|
"title": "Sci-Fi Clean Landing Master",
|
||||||
|
"page_templates": ["landing"],
|
||||||
|
"blocks": [
|
||||||
|
{ "block_key": "scifi-clean:status_bar", "title": "System Status Rail", "content": { "showClock": true, "showBuild": true, "callsign": "SCF-CLN" }, "slot": "header", "sort_order": 0 },
|
||||||
|
{ "block_key": "scifi-clean:mission_stat", "title": "Hero Mission Stat", "content": { "metric": "Apogee", "value": "412", "unit": "km", "delta": "+12", "trend": "up" }, "slot": "hero", "sort_order": 0 },
|
||||||
|
{ "block_key": "scifi-clean:tech_spec", "title": "Hero Tech Spec", "content": { "caption": "Launch envelope", "rows": [ { "label": "Thrust", "value": "1.42", "unit": "MN" }, { "label": "Burn time", "value": "186", "unit": "s" }, { "label": "Payload", "value": "320", "unit": "kg" } ] }, "slot": "specs", "sort_order": 0 },
|
||||||
|
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main", "placeholder": "Page payload" }, "slot": "main", "sort_order": 0 },
|
||||||
|
{ "block_key": "scifi-clean:footer", "title": "Instrument Footer", "content": { "showSignup": true, "callsign": "SCF-CLN" }, "slot": "footer", "sort_order": 0 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MissionStatBlockMeta defines metadata for the mission-stat block.
|
|
||||||
var MissionStatBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "mission_stat",
|
|
||||||
Title: "Mission Stat",
|
|
||||||
Description: "Headline metric in mono numerals with a signal-orange delta arrow.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
// MissionStatData drives the templ render.
|
|
||||||
type MissionStatData struct {
|
|
||||||
Metric string
|
|
||||||
Value string
|
|
||||||
Unit string
|
|
||||||
Delta string
|
|
||||||
Trend string // "up", "down", "flat"
|
|
||||||
}
|
|
||||||
|
|
||||||
// MissionStatBlock renders the mission-stat block.
|
|
||||||
// Content shape: {"metric": "...", "value": "...", "unit": "...", "delta": "...", "trend": "up|down|flat"}
|
|
||||||
func MissionStatBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := MissionStatData{
|
|
||||||
Metric: getString(content, "metric"),
|
|
||||||
Value: getString(content, "value"),
|
|
||||||
Unit: getString(content, "unit"),
|
|
||||||
Delta: getString(content, "delta"),
|
|
||||||
Trend: normalizeTrend(getString(content, "trend")),
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = missionStatComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// trendGlyph returns the arrow character for a given trend.
|
|
||||||
func trendGlyph(trend string) string {
|
|
||||||
switch trend {
|
|
||||||
case "up":
|
|
||||||
return "↑" // ↑
|
|
||||||
case "down":
|
|
||||||
return "↓" // ↓
|
|
||||||
default:
|
|
||||||
return "→" // →
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// missionStatComponent renders the headline metric card with mono numerals
|
|
||||||
// and an accent-colored delta arrow.
|
|
||||||
templ missionStatComponent(data MissionStatData) {
|
|
||||||
<div data-block="scifi-clean:mission_stat" class="hairline p-6 bg-card text-card-foreground">
|
|
||||||
if data.Metric != "" {
|
|
||||||
<div class="scifi-mono uppercase text-xs tracking-widest text-muted-foreground mb-3">
|
|
||||||
{ data.Metric }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="flex items-baseline gap-2">
|
|
||||||
<span
|
|
||||||
class="scifi-mono text-5xl font-medium tabular-nums text-foreground"
|
|
||||||
style="font-family: var(--font-mono); font-variant-numeric: tabular-nums;"
|
|
||||||
>
|
|
||||||
if data.Value == "" {
|
|
||||||
{ "—" }
|
|
||||||
} else {
|
|
||||||
{ data.Value }
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
if data.Unit != "" {
|
|
||||||
<span class="scifi-mono text-base text-muted-foreground tabular-nums" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums;">
|
|
||||||
{ data.Unit }
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
if data.Delta != "" {
|
|
||||||
<div class="mt-3 scifi-mono text-sm tabular-nums" style={ "font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: hsl(var(--accent));" }>
|
|
||||||
{ trendGlyph(data.Trend) } { data.Delta }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@ -1,162 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// missionStatComponent renders the headline metric card with mono numerals
|
|
||||||
// and an accent-colored delta arrow.
|
|
||||||
func missionStatComponent(data MissionStatData) 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=\"scifi-clean:mission_stat\" class=\"hairline p-6 bg-card text-card-foreground\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Metric != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"scifi-mono uppercase text-xs tracking-widest text-muted-foreground mb-3\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var2 string
|
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Metric)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 9, 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, 3, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"flex items-baseline gap-2\"><span class=\"scifi-mono text-5xl font-medium tabular-nums text-foreground\" style=\"font-family: var(--font-mono); font-variant-numeric: tabular-nums;\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Value == "" {
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("—")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 18, Col: 12}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var templ_7745c5c3_Var4 string
|
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Value)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 20, Col: 17}
|
|
||||||
}
|
|
||||||
_, 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, "</span> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Unit != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<span class=\"scifi-mono text-base text-muted-foreground tabular-nums\" style=\"font-family: var(--font-mono); font-variant-numeric: tabular-nums;\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Unit)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 25, Col: 16}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</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.Delta != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"mt-3 scifi-mono text-sm tabular-nums\" style=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var6 string
|
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: hsl(var(--accent));")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 30, Col: 156}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var7 string
|
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(trendGlyph(data.Trend))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 31, Col: 28}
|
|
||||||
}
|
|
||||||
_, 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, 11, " ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var8 string
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.Delta)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `mission_stat.templ`, Line: 31, Col: 43}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
@ -2,11 +2,8 @@
|
|||||||
name = "scifi-clean"
|
name = "scifi-clean"
|
||||||
display_name = "Sci-Fi Clean"
|
display_name = "Sci-Fi Clean"
|
||||||
scope = "@themes"
|
scope = "@themes"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
description = "Minimalist futurist theme for aerospace, robotics, and R&D — off-white surfaces, technical blue, signal-orange accents, mono numerals."
|
description = "Minimalist futurist theme for aerospace, robotics, and R&D — off-white surfaces, technical blue, signal-orange accents, mono numerals."
|
||||||
kind = "theme"
|
kind = "theme"
|
||||||
categories = ["templates"]
|
categories = ["templates"]
|
||||||
tags = ["futurist", "technical", "aerospace", "hardware", "robotics", "biotech", "rnd", "clean", "minimalist"]
|
tags = ["futurist", "technical", "aerospace", "hardware", "robotics", "biotech", "rnd", "clean", "minimalist"]
|
||||||
|
|
||||||
[compatibility]
|
|
||||||
block_core = ">=0.15.0 <0.16.0"
|
|
||||||
|
|||||||
197
register.go
197
register.go
@ -1,197 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/a-h/templ"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
"git.dev.alexdunmow.com/block/core/plugin"
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
// wrap adapts a templ-returning render function to templates.TemplateFunc.
|
|
||||||
// templ.Component already implements templates.HTMLComponent via Render.
|
|
||||||
func wrap(f func(ctx context.Context, doc map[string]any) templ.Component) templates.TemplateFunc {
|
|
||||||
return func(ctx context.Context, doc map[string]any) templates.HTMLComponent {
|
|
||||||
return f(ctx, doc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register is the plugin entry point. It registers the system template, the
|
|
||||||
// four page templates, the six theme-specific blocks, the three overrides,
|
|
||||||
// and the email wrapper.
|
|
||||||
//
|
|
||||||
// IMPORTANT: schemas are loaded BEFORE any br.Register(...) call — this is a
|
|
||||||
// hard rule (CLAUDE.md, UAT §3) so the block registry binds content schemas
|
|
||||||
// at registration time.
|
|
||||||
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
|
||||||
// --- System template ---
|
|
||||||
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
|
|
||||||
Key: "scifi-clean",
|
|
||||||
Title: "Sci-Fi Clean",
|
|
||||||
Description: "Minimalist futurist theme for aerospace, robotics, and R&D — off-white surfaces, technical blue, signal-orange accents, mono numerals.",
|
|
||||||
})
|
|
||||||
|
|
||||||
// --- Page templates (spec §6) ---
|
|
||||||
if err := tr.RegisterPageTemplate("scifi-clean", templates.PageTemplateMeta{
|
|
||||||
Key: "default",
|
|
||||||
Title: "Default",
|
|
||||||
Description: "Standard cleanroom layout with header rail, main column, and footer instrument panel.",
|
|
||||||
Slots: []string{"header", "main", "footer"},
|
|
||||||
}, wrap(RenderScifiClean)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tr.RegisterPageTemplate("scifi-clean", templates.PageTemplateMeta{
|
|
||||||
Key: "landing",
|
|
||||||
Title: "Landing",
|
|
||||||
Description: "Hero diagram + spec strip + CTA banner.",
|
|
||||||
Slots: []string{"hero", "specs", "main", "cta", "footer"},
|
|
||||||
}, wrap(RenderScifiCleanLanding)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tr.RegisterPageTemplate("scifi-clean", templates.PageTemplateMeta{
|
|
||||||
Key: "article",
|
|
||||||
Title: "Article",
|
|
||||||
Description: "Narrow column with rail metadata and figure margin.",
|
|
||||||
Slots: []string{"header", "rail", "main", "footer"},
|
|
||||||
}, wrap(RenderScifiCleanArticle)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tr.RegisterPageTemplate("scifi-clean", templates.PageTemplateMeta{
|
|
||||||
Key: "full-width",
|
|
||||||
Title: "Full Width",
|
|
||||||
Description: "Edge-to-edge schematic surface for diagrams and dashboards.",
|
|
||||||
Slots: []string{"header", "main", "footer"},
|
|
||||||
}, wrap(RenderScifiCleanFullWidth)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Load JSON Schemas BEFORE any block registration ---
|
|
||||||
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Theme-specific blocks (spec §8) ---
|
|
||||||
br.Register(TechSpecBlockMeta, TechSpecBlock)
|
|
||||||
br.Register(DiagramCaptionBlockMeta, DiagramCaptionBlock)
|
|
||||||
br.Register(MissionStatBlockMeta, MissionStatBlock)
|
|
||||||
br.Register(StatusBarBlockMeta, StatusBarBlock)
|
|
||||||
br.Register(FooterBlockMeta, FooterBlock)
|
|
||||||
br.Register(SchematicHeroBlockMeta, SchematicHeroBlock)
|
|
||||||
|
|
||||||
// --- Built-in overrides (spec §9) ---
|
|
||||||
br.RegisterTemplateOverride("scifi-clean", "heading", ScifiHeadingBlock)
|
|
||||||
br.RegisterTemplateOverride("scifi-clean", "text", ScifiTextBlock)
|
|
||||||
br.RegisterTemplateOverride("scifi-clean", "button", ScifiButtonBlock)
|
|
||||||
|
|
||||||
// --- Email wrapper (spec §10) ---
|
|
||||||
tr.RegisterEmailWrapper("scifi-clean", ScifiEmailWrapper)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultMasterPages returns the two master pages that Sci-Fi Clean provisions
|
|
||||||
// on first plugin load (spec §7, UAT §9).
|
|
||||||
//
|
|
||||||
// - scifi-clean:default-master → attached to `default`, `article`, `full-width`
|
|
||||||
// - scifi-clean:landing-master → attached to `landing`, pre-populates `hero`
|
|
||||||
// with a mission_stat and `specs` with a tech_spec.
|
|
||||||
func DefaultMasterPages() []plugin.MasterPageDefinition {
|
|
||||||
defaultMaster := plugin.MasterPageDefinition{
|
|
||||||
Key: "scifi-clean:default-master",
|
|
||||||
Title: "Sci-Fi Clean Default Master",
|
|
||||||
PageTemplates: []string{"default", "article", "full-width"},
|
|
||||||
Blocks: []plugin.MasterPageBlock{
|
|
||||||
{
|
|
||||||
BlockKey: "navbar",
|
|
||||||
Title: "Mission Header",
|
|
||||||
Content: map[string]any{"menuName": "main"},
|
|
||||||
Slot: "header",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:status_bar",
|
|
||||||
Title: "System Status Rail",
|
|
||||||
Content: map[string]any{"showClock": true, "showBuild": true, "callsign": "SCF-CLN"},
|
|
||||||
Slot: "header",
|
|
||||||
SortOrder: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "slot",
|
|
||||||
Title: "Main Content",
|
|
||||||
Content: map[string]any{"slotName": "main", "placeholder": "Page payload"},
|
|
||||||
Slot: "main",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:footer",
|
|
||||||
Title: "Instrument Footer",
|
|
||||||
Content: map[string]any{"showSignup": true, "callsign": "SCF-CLN"},
|
|
||||||
Slot: "footer",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
landingMaster := plugin.MasterPageDefinition{
|
|
||||||
Key: "scifi-clean:landing-master",
|
|
||||||
Title: "Sci-Fi Clean Landing Master",
|
|
||||||
PageTemplates: []string{"landing"},
|
|
||||||
Blocks: []plugin.MasterPageBlock{
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:status_bar",
|
|
||||||
Title: "System Status Rail",
|
|
||||||
Content: map[string]any{"showClock": true, "showBuild": true, "callsign": "SCF-CLN"},
|
|
||||||
Slot: "header",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:mission_stat",
|
|
||||||
Title: "Hero Mission Stat",
|
|
||||||
Content: map[string]any{
|
|
||||||
"metric": "Apogee",
|
|
||||||
"value": "412",
|
|
||||||
"unit": "km",
|
|
||||||
"delta": "+12",
|
|
||||||
"trend": "up",
|
|
||||||
},
|
|
||||||
Slot: "hero",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:tech_spec",
|
|
||||||
Title: "Hero Tech Spec",
|
|
||||||
Content: map[string]any{
|
|
||||||
"caption": "Launch envelope",
|
|
||||||
"rows": []any{
|
|
||||||
map[string]any{"label": "Thrust", "value": "1.42", "unit": "MN"},
|
|
||||||
map[string]any{"label": "Burn time", "value": "186", "unit": "s"},
|
|
||||||
map[string]any{"label": "Payload", "value": "320", "unit": "kg"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Slot: "specs",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "slot",
|
|
||||||
Title: "Main Content",
|
|
||||||
Content: map[string]any{"slotName": "main", "placeholder": "Page payload"},
|
|
||||||
Slot: "main",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
BlockKey: "scifi-clean:footer",
|
|
||||||
Title: "Instrument Footer",
|
|
||||||
Content: map[string]any{"showSignup": true, "callsign": "SCF-CLN"},
|
|
||||||
Slot: "footer",
|
|
||||||
SortOrder: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return []plugin.MasterPageDefinition{defaultMaster, landingMaster}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
"git.dev.alexdunmow.com/block/core/plugin"
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Registration is the compile-time plugin registration for the Sci-Fi Clean theme.
|
|
||||||
var Registration = plugin.PluginRegistration{
|
|
||||||
Name: "scifi-clean",
|
|
||||||
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() },
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SchematicHeroBlockMeta defines metadata for the landing hero.
|
|
||||||
var SchematicHeroBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "schematic_hero",
|
|
||||||
Title: "Schematic Hero",
|
|
||||||
Description: "Landing hero with a large display title over a blueprint image and dual CTAs.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryLayout,
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchematicCTA is a single call-to-action link.
|
|
||||||
type SchematicCTA struct {
|
|
||||||
Text string
|
|
||||||
Href string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchematicHeroData drives the templ render.
|
|
||||||
type SchematicHeroData struct {
|
|
||||||
Title string
|
|
||||||
Kicker string
|
|
||||||
Image string
|
|
||||||
PrimaryCTA SchematicCTA
|
|
||||||
SecondaryCTA SchematicCTA
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchematicHeroBlock renders the landing hero.
|
|
||||||
// Content shape: {"title": "...", "kicker": "...", "image": "media:...",
|
|
||||||
// "primaryCta": {"text": "...", "href": "..."},
|
|
||||||
// "secondaryCta": {"text": "...", "href": "..."}}
|
|
||||||
func SchematicHeroBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := SchematicHeroData{
|
|
||||||
Title: getString(content, "title"),
|
|
||||||
Kicker: getString(content, "kicker"),
|
|
||||||
Image: blocks.ResolveMediaPath(getString(content, "image")),
|
|
||||||
}
|
|
||||||
|
|
||||||
if m := getMap(content, "primaryCta"); m != nil {
|
|
||||||
data.PrimaryCTA = SchematicCTA{Text: getString(m, "text"), Href: getString(m, "href")}
|
|
||||||
}
|
|
||||||
if m := getMap(content, "secondaryCta"); m != nil {
|
|
||||||
data.SecondaryCTA = SchematicCTA{Text: getString(m, "text"), Href: getString(m, "href")}
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = schematicHeroComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// schematicHeroComponent renders the landing-page hero.
|
|
||||||
// UAT §13.6 requires the <h1> to render in Space Grotesk at >= 64px on 1440x900.
|
|
||||||
// UAT §6 requires a scrim layer between the background image and the title text.
|
|
||||||
templ schematicHeroComponent(data SchematicHeroData) {
|
|
||||||
<section data-block="scifi-clean:schematic_hero" class="relative overflow-hidden bg-grid">
|
|
||||||
if data.Image != "" {
|
|
||||||
<div class="absolute inset-0 z-0">
|
|
||||||
<img
|
|
||||||
src={ data.Image }
|
|
||||||
alt=""
|
|
||||||
class="w-full h-full object-cover opacity-25"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="scrim relative z-10">
|
|
||||||
<div class="max-w-6xl mx-auto px-4 py-24 md:py-32">
|
|
||||||
if data.Kicker != "" {
|
|
||||||
<div class="scifi-mono uppercase tracking-widest text-xs text-accent mb-4">
|
|
||||||
{ data.Kicker }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<h1
|
|
||||||
class="scifi-h1 font-medium tracking-tight text-foreground"
|
|
||||||
style="font-family: var(--font-heading); font-size: clamp(3rem, 6vw, 5rem); line-height: 1.05;"
|
|
||||||
>
|
|
||||||
if data.Title == "" {
|
|
||||||
{ "Untitled mission" }
|
|
||||||
} else {
|
|
||||||
{ data.Title }
|
|
||||||
}
|
|
||||||
</h1>
|
|
||||||
<div class="mt-8 flex flex-wrap gap-3">
|
|
||||||
if data.PrimaryCTA.Text != "" && data.PrimaryCTA.Href != "" {
|
|
||||||
<a
|
|
||||||
href={ templ.SafeURL(data.PrimaryCTA.Href) }
|
|
||||||
class="scifi-mono uppercase tracking-widest text-xs px-5 py-3 bg-primary text-primary-foreground scifi-chevron scifi-focus"
|
|
||||||
>
|
|
||||||
{ data.PrimaryCTA.Text }
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
if data.SecondaryCTA.Text != "" && data.SecondaryCTA.Href != "" {
|
|
||||||
<a
|
|
||||||
href={ templ.SafeURL(data.SecondaryCTA.Href) }
|
|
||||||
class="scifi-mono uppercase tracking-widest text-xs px-5 py-3 hairline text-foreground scifi-chevron scifi-focus"
|
|
||||||
>
|
|
||||||
{ data.SecondaryCTA.Text }
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// schematicHeroComponent renders the landing-page hero.
|
|
||||||
// UAT §13.6 requires the <h1> to render in Space Grotesk at >= 64px on 1440x900.
|
|
||||||
// UAT §6 requires a scrim layer between the background image and the title text.
|
|
||||||
func schematicHeroComponent(data SchematicHeroData) 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=\"scifi-clean:schematic_hero\" class=\"relative overflow-hidden bg-grid\">")
|
|
||||||
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\"><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: `schematic_hero.templ`, Line: 11, Col: 21}
|
|
||||||
}
|
|
||||||
_, 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 opacity-25\"></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"scrim relative z-10\"><div class=\"max-w-6xl mx-auto px-4 py-24 md:py-32\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Kicker != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div class=\"scifi-mono uppercase tracking-widest text-xs text-accent mb-4\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.Kicker)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 21, Col: 19}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<h1 class=\"scifi-h1 font-medium tracking-tight text-foreground\" style=\"font-family: var(--font-heading); font-size: clamp(3rem, 6vw, 5rem); line-height: 1.05;\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Title == "" {
|
|
||||||
var templ_7745c5c3_Var4 string
|
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("Untitled mission")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 29, Col: 26}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 31, Col: 18}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</h1><div class=\"mt-8 flex flex-wrap gap-3\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.PrimaryCTA.Text != "" && data.PrimaryCTA.Href != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<a href=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var6 templ.SafeURL
|
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.PrimaryCTA.Href))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 37, Col: 49}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" class=\"scifi-mono uppercase tracking-widest text-xs px-5 py-3 bg-primary text-primary-foreground scifi-chevron scifi-focus\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var7 string
|
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(data.PrimaryCTA.Text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 40, Col: 29}
|
|
||||||
}
|
|
||||||
_, 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, 11, "</a> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if data.SecondaryCTA.Text != "" && data.SecondaryCTA.Href != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<a href=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var8 templ.SafeURL
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(data.SecondaryCTA.Href))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 45, Col: 51}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\" class=\"scifi-mono uppercase tracking-widest text-xs px-5 py-3 hairline text-foreground scifi-chevron scifi-focus\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var9 string
|
|
||||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(data.SecondaryCTA.Text)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `schematic_hero.templ`, Line: 48, Col: 31}
|
|
||||||
}
|
|
||||||
_, 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, 14, "</a>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></div></div></section>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StatusBarBlockMeta defines metadata for the persistent status-bar rail.
|
|
||||||
var StatusBarBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "status_bar",
|
|
||||||
Title: "Status Bar",
|
|
||||||
Description: "Persistent top rail with optional UTC clock, build hash, and callsign.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryNavigation,
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusBarData drives the templ render.
|
|
||||||
type StatusBarData struct {
|
|
||||||
ShowClock bool
|
|
||||||
ShowBuild bool
|
|
||||||
Callsign string
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusBarBlock renders the persistent top rail.
|
|
||||||
// Content shape: {"showClock": true, "showBuild": true, "callsign": "SCF-CLN"}
|
|
||||||
func StatusBarBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := StatusBarData{
|
|
||||||
ShowClock: getBool(content, "showClock", true),
|
|
||||||
ShowBuild: getBool(content, "showBuild", true),
|
|
||||||
Callsign: getStringDefault(content, "callsign", "SCF-CLN"),
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = statusBarComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// statusBarComponent renders the sticky top status rail.
|
|
||||||
// UAT §13.9 requires position: sticky and top: 0.
|
|
||||||
templ statusBarComponent(data StatusBarData) {
|
|
||||||
<div
|
|
||||||
data-block="scifi-clean:status_bar"
|
|
||||||
class="w-full hairline-b bg-card text-card-foreground scifi-mono text-xs uppercase tracking-widest"
|
|
||||||
style="position: sticky; top: 0; z-index: 30;"
|
|
||||||
>
|
|
||||||
<div class="max-w-6xl mx-auto px-4 py-2 flex items-center justify-between gap-4">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<span class="text-muted-foreground">{ data.Callsign }</span>
|
|
||||||
<span class="text-muted-foreground">|</span>
|
|
||||||
<span class="text-foreground">PUBLIC</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-3 tabular-nums">
|
|
||||||
if data.ShowClock {
|
|
||||||
<span
|
|
||||||
data-status-bar-clock="utc"
|
|
||||||
class="text-muted-foreground tabular-nums"
|
|
||||||
>
|
|
||||||
{ "00:00:00 UTC" }
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
if data.ShowBuild {
|
|
||||||
<span class="text-muted-foreground">|</span>
|
|
||||||
<span class="text-foreground tabular-nums">BLD a1b2c3</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
(function(){
|
|
||||||
var el = document.querySelector('[data-status-bar-clock="utc"]');
|
|
||||||
if (!el) return;
|
|
||||||
function fmt(n){ return n < 10 ? '0' + n : String(n); }
|
|
||||||
function tick(){
|
|
||||||
var d = new Date();
|
|
||||||
el.textContent = fmt(d.getUTCHours()) + ':' + fmt(d.getUTCMinutes()) + ':' + fmt(d.getUTCSeconds()) + ' UTC';
|
|
||||||
}
|
|
||||||
tick();
|
|
||||||
setInterval(tick, 1000);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// statusBarComponent renders the sticky top status rail.
|
|
||||||
// UAT §13.9 requires position: sticky and top: 0.
|
|
||||||
func statusBarComponent(data StatusBarData) 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=\"scifi-clean:status_bar\" class=\"w-full hairline-b bg-card text-card-foreground scifi-mono text-xs uppercase tracking-widest\" style=\"position: sticky; top: 0; z-index: 30;\"><div class=\"max-w-6xl mx-auto px-4 py-2 flex items-center justify-between gap-4\"><div class=\"flex items-center gap-3\"><span class=\"text-muted-foreground\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var2 string
|
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Callsign)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `status_bar.templ`, Line: 13, Col: 55}
|
|
||||||
}
|
|
||||||
_, 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, "</span> <span class=\"text-muted-foreground\">|</span> <span class=\"text-foreground\">PUBLIC</span></div><div class=\"flex items-center gap-3 tabular-nums\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.ShowClock {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<span data-status-bar-clock=\"utc\" class=\"text-muted-foreground tabular-nums\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("00:00:00 UTC")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `status_bar.templ`, Line: 23, Col: 22}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</span> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if data.ShowBuild {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<span class=\"text-muted-foreground\">|</span> <span class=\"text-foreground tabular-nums\">BLD a1b2c3</span>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</div></div><script>\n\t\t(function(){\n\t\t\tvar el = document.querySelector('[data-status-bar-clock=\"utc\"]');\n\t\t\tif (!el) return;\n\t\t\tfunction fmt(n){ return n < 10 ? '0' + n : String(n); }\n\t\t\tfunction tick(){\n\t\t\t\tvar d = new Date();\n\t\t\t\tel.textContent = fmt(d.getUTCHours()) + ':' + fmt(d.getUTCMinutes()) + ':' + fmt(d.getUTCSeconds()) + ' UTC';\n\t\t\t}\n\t\t\ttick();\n\t\t\tsetInterval(tick, 1000);\n\t\t})();\n\t\t</script></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
50
tech_spec.go
50
tech_spec.go
@ -1,50 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/blocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TechSpecBlockMeta defines metadata for the tech-spec table block.
|
|
||||||
var TechSpecBlockMeta = blocks.BlockMeta{
|
|
||||||
Key: "tech_spec",
|
|
||||||
Title: "Tech Spec Table",
|
|
||||||
Description: "Specification table with right-aligned mono numerals and hairline rows.",
|
|
||||||
Source: "scifi-clean",
|
|
||||||
Category: blocks.CategoryContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TechSpecRow is one label/value/unit triple.
|
|
||||||
type TechSpecRow struct {
|
|
||||||
Label string
|
|
||||||
Value string
|
|
||||||
Unit string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TechSpecData drives the templ render.
|
|
||||||
type TechSpecData struct {
|
|
||||||
Caption string
|
|
||||||
Rows []TechSpecRow
|
|
||||||
}
|
|
||||||
|
|
||||||
// TechSpecBlock renders the tech-spec block.
|
|
||||||
// Content shape: {"caption": "...", "rows": [{"label": "...", "value": "...", "unit": "..."}]}
|
|
||||||
func TechSpecBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
data := TechSpecData{
|
|
||||||
Caption: getString(content, "caption"),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, raw := range getSlice(content, "rows") {
|
|
||||||
data.Rows = append(data.Rows, TechSpecRow{
|
|
||||||
Label: getString(raw, "label"),
|
|
||||||
Value: getString(raw, "value"),
|
|
||||||
Unit: getString(raw, "unit"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = techSpecComponent(data).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// techSpecComponent renders the tech-spec table with right-aligned mono numerals
|
|
||||||
// and hairline row rules.
|
|
||||||
templ techSpecComponent(data TechSpecData) {
|
|
||||||
<section data-block="scifi-clean:tech_spec" class="py-8">
|
|
||||||
<div class="max-w-3xl mx-auto px-4">
|
|
||||||
if data.Caption != "" {
|
|
||||||
<p class="scifi-mono text-xs uppercase tracking-widest text-muted-foreground mb-3">
|
|
||||||
{ data.Caption }
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
<table class="w-full text-sm hairline">
|
|
||||||
<tbody>
|
|
||||||
if len(data.Rows) == 0 {
|
|
||||||
<tr class="hairline-b">
|
|
||||||
<td class="scifi-body py-3 px-4 text-foreground">No spec rows yet.</td>
|
|
||||||
<td class="scifi-mono py-3 px-4 text-right tabular-nums text-muted-foreground">--</td>
|
|
||||||
<td class="scifi-mono py-3 pr-4 text-right text-muted-foreground"></td>
|
|
||||||
</tr>
|
|
||||||
} else {
|
|
||||||
for i, row := range data.Rows {
|
|
||||||
@techSpecRow(row, i == len(data.Rows)-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
|
|
||||||
// techSpecRow renders a single row. Last-row check controls whether to drop
|
|
||||||
// the bottom hairline.
|
|
||||||
templ techSpecRow(row TechSpecRow, last bool) {
|
|
||||||
<tr class={ rowBorderClass(last) }>
|
|
||||||
<td class="scifi-body py-3 px-4 text-muted-foreground uppercase text-xs tracking-wider">
|
|
||||||
{ row.Label }
|
|
||||||
</td>
|
|
||||||
<td class="scifi-mono py-3 px-4 text-right tabular-nums text-foreground font-medium" style="font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right;">
|
|
||||||
{ row.Value }
|
|
||||||
</td>
|
|
||||||
<td class="scifi-mono py-3 pr-4 text-right text-muted-foreground text-xs" style="font-family: var(--font-mono); text-align: right;">
|
|
||||||
{ row.Unit }
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
|
|
||||||
func rowBorderClass(last bool) string {
|
|
||||||
if last {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "hairline-b"
|
|
||||||
}
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// techSpecComponent renders the tech-spec table with right-aligned mono numerals
|
|
||||||
// and hairline row rules.
|
|
||||||
func techSpecComponent(data TechSpecData) 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=\"scifi-clean:tech_spec\" class=\"py-8\"><div class=\"max-w-3xl mx-auto px-4\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if data.Caption != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"scifi-mono text-xs uppercase tracking-widest text-muted-foreground mb-3\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var2 string
|
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Caption)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `tech_spec.templ`, Line: 10, Col: 19}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</p>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<table class=\"w-full text-sm hairline\"><tbody>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if len(data.Rows) == 0 {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr class=\"hairline-b\"><td class=\"scifi-body py-3 px-4 text-foreground\">No spec rows yet.</td><td class=\"scifi-mono py-3 px-4 text-right tabular-nums text-muted-foreground\">--</td><td class=\"scifi-mono py-3 pr-4 text-right text-muted-foreground\"></td></tr>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i, row := range data.Rows {
|
|
||||||
templ_7745c5c3_Err = techSpecRow(row, i == len(data.Rows)-1).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</tbody></table></div></section>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// techSpecRow renders a single row. Last-row check controls whether to drop
|
|
||||||
// the bottom hairline.
|
|
||||||
func techSpecRow(row TechSpecRow, last bool) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var3 == nil {
|
|
||||||
templ_7745c5c3_Var3 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
var templ_7745c5c3_Var4 = []any{rowBorderClass(last)}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<tr class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var5 string
|
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var4).String())
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `tech_spec.templ`, Line: 1, Col: 0}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\"><td class=\"scifi-body py-3 px-4 text-muted-foreground uppercase text-xs tracking-wider\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var6 string
|
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(row.Label)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `tech_spec.templ`, Line: 37, Col: 14}
|
|
||||||
}
|
|
||||||
_, 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, 9, "</td><td class=\"scifi-mono py-3 px-4 text-right tabular-nums text-foreground font-medium\" style=\"font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right;\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var7 string
|
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(row.Value)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `tech_spec.templ`, Line: 40, Col: 14}
|
|
||||||
}
|
|
||||||
_, 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, 10, "</td><td class=\"scifi-mono py-3 pr-4 text-right text-muted-foreground text-xs\" style=\"font-family: var(--font-mono); text-align: right;\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var8 string
|
|
||||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(row.Unit)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `tech_spec.templ`, Line: 43, Col: 13}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</td></tr>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func rowBorderClass(last bool) string {
|
|
||||||
if last {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "hairline-b"
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
281
template.templ
281
template.templ
@ -1,281 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates/bn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PageData holds the values lifted out of the render `doc` map for the
|
|
||||||
// four Sci-Fi Clean page templates.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseScifiPageData lifts the well-known keys out of the inbound doc map.
|
|
||||||
// Unknown keys (e.g. block content) are ignored by the page renderers.
|
|
||||||
func parseScifiPageData(doc map[string]any) PageData {
|
|
||||||
title := "Untitled"
|
|
||||||
if t, ok := doc["title"].(string); ok {
|
|
||||||
title = t
|
|
||||||
}
|
|
||||||
|
|
||||||
slots := make(map[string]string)
|
|
||||||
if s, ok := doc["slots"].(map[string]string); ok {
|
|
||||||
slots = s
|
|
||||||
}
|
|
||||||
|
|
||||||
themeCSS := ""
|
|
||||||
if tc, ok := doc["theme_css"].(string); ok {
|
|
||||||
themeCSS = tc
|
|
||||||
}
|
|
||||||
|
|
||||||
structuredData := ""
|
|
||||||
if sd, ok := doc["structured_data"].(string); ok {
|
|
||||||
structuredData = sd
|
|
||||||
}
|
|
||||||
|
|
||||||
cssHash := ""
|
|
||||||
if ch, ok := doc["css_hash"].(string); ok {
|
|
||||||
cssHash = ch
|
|
||||||
}
|
|
||||||
|
|
||||||
pageviewNonce := ""
|
|
||||||
if pn, ok := doc["pageview_nonce"].(string); ok {
|
|
||||||
pageviewNonce = pn
|
|
||||||
}
|
|
||||||
|
|
||||||
themeMode := "light"
|
|
||||||
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
|
|
||||||
themeMode = tm
|
|
||||||
}
|
|
||||||
|
|
||||||
siteSettings := bn.ParseSiteSettings(doc)
|
|
||||||
pageMeta := bn.ParsePageMeta(doc)
|
|
||||||
engagementConfig := bn.ParseEngagementConfig(doc)
|
|
||||||
|
|
||||||
return PageData{
|
|
||||||
Title: title,
|
|
||||||
Slots: slots,
|
|
||||||
ThemeMode: themeMode,
|
|
||||||
ThemeCSS: themeCSS,
|
|
||||||
SiteSettings: siteSettings,
|
|
||||||
PageMeta: pageMeta,
|
|
||||||
StructuredData: structuredData,
|
|
||||||
CSSHash: cssHash,
|
|
||||||
PageviewNonce: pageviewNonce,
|
|
||||||
EngagementConfig: engagementConfig,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// htmlClassForMode returns the root <html> class for the current theme mode.
|
|
||||||
func htmlClassForMode(mode string) string {
|
|
||||||
if mode == "dark" {
|
|
||||||
return "dark"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Default template (header / main / footer) =====
|
|
||||||
|
|
||||||
templ ScifiClean(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{},
|
|
||||||
StructuredData: data.StructuredData,
|
|
||||||
CSSHash: data.CSSHash,
|
|
||||||
PageviewNonce: data.PageviewNonce,
|
|
||||||
EngagementConfig: data.EngagementConfig,
|
|
||||||
})
|
|
||||||
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
|
||||||
@bn.AdminBypassBanner(data.SiteSettings)
|
|
||||||
<header class="w-full">
|
|
||||||
@templ.Raw(data.Slots["header"])
|
|
||||||
</header>
|
|
||||||
<main class="flex-grow max-w-5xl mx-auto w-full px-4 py-8">
|
|
||||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
|
||||||
@templ.Raw(main)
|
|
||||||
} else {
|
|
||||||
<div class="py-20 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground">
|
|
||||||
No content blocks assigned to this page.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</main>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
@templ.Raw(data.Slots["footer"])
|
|
||||||
</footer>
|
|
||||||
@bn.BodyEnd(data.SiteSettings)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Landing template (hero / specs / main / cta / footer) =====
|
|
||||||
|
|
||||||
templ ScifiCleanLanding(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{},
|
|
||||||
StructuredData: data.StructuredData,
|
|
||||||
CSSHash: data.CSSHash,
|
|
||||||
PageviewNonce: data.PageviewNonce,
|
|
||||||
EngagementConfig: data.EngagementConfig,
|
|
||||||
})
|
|
||||||
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
|
||||||
@bn.AdminBypassBanner(data.SiteSettings)
|
|
||||||
<section class="w-full">
|
|
||||||
@templ.Raw(data.Slots["hero"])
|
|
||||||
</section>
|
|
||||||
if specs, ok := data.Slots["specs"]; ok && specs != "" {
|
|
||||||
<section class="w-full hairline-b py-12">
|
|
||||||
<div class="max-w-6xl mx-auto px-4">
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
||||||
@templ.Raw(specs)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
<main class="flex-grow w-full">
|
|
||||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
|
||||||
<div class="max-w-6xl mx-auto px-4 py-16">
|
|
||||||
@templ.Raw(main)
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</main>
|
|
||||||
if cta, ok := data.Slots["cta"]; ok && cta != "" {
|
|
||||||
<section class="w-full hairline-t py-16">
|
|
||||||
<div class="max-w-6xl mx-auto px-4">
|
|
||||||
@templ.Raw(cta)
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
@templ.Raw(data.Slots["footer"])
|
|
||||||
</footer>
|
|
||||||
@bn.BodyEnd(data.SiteSettings)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Article template (header / rail / main / footer) =====
|
|
||||||
|
|
||||||
templ ScifiCleanArticle(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{},
|
|
||||||
StructuredData: data.StructuredData,
|
|
||||||
CSSHash: data.CSSHash,
|
|
||||||
PageviewNonce: data.PageviewNonce,
|
|
||||||
EngagementConfig: data.EngagementConfig,
|
|
||||||
})
|
|
||||||
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
|
||||||
@bn.AdminBypassBanner(data.SiteSettings)
|
|
||||||
<header class="w-full hairline-b">
|
|
||||||
@templ.Raw(data.Slots["header"])
|
|
||||||
</header>
|
|
||||||
<main class="flex-grow w-full">
|
|
||||||
<div class="max-w-5xl mx-auto px-4 py-12 grid grid-cols-12 gap-8">
|
|
||||||
if rail, ok := data.Slots["rail"]; ok && rail != "" {
|
|
||||||
<aside class="col-span-12 md:col-span-3 scifi-mono uppercase text-xs tracking-widest text-muted-foreground space-y-3">
|
|
||||||
@templ.Raw(rail)
|
|
||||||
</aside>
|
|
||||||
}
|
|
||||||
<article class="col-span-12 md:col-span-9 scifi-body max-w-2xl">
|
|
||||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
|
||||||
@templ.Raw(main)
|
|
||||||
} else {
|
|
||||||
<p class="text-muted-foreground">No article body.</p>
|
|
||||||
}
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
@templ.Raw(data.Slots["footer"])
|
|
||||||
</footer>
|
|
||||||
@bn.BodyEnd(data.SiteSettings)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Full-width template (header / main / footer) =====
|
|
||||||
|
|
||||||
templ ScifiCleanFullWidth(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{},
|
|
||||||
StructuredData: data.StructuredData,
|
|
||||||
CSSHash: data.CSSHash,
|
|
||||||
PageviewNonce: data.PageviewNonce,
|
|
||||||
EngagementConfig: data.EngagementConfig,
|
|
||||||
})
|
|
||||||
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
|
||||||
@bn.AdminBypassBanner(data.SiteSettings)
|
|
||||||
<header class="w-full">
|
|
||||||
@templ.Raw(data.Slots["header"])
|
|
||||||
</header>
|
|
||||||
<main class="flex-grow w-full bg-grid">
|
|
||||||
if main, ok := data.Slots["main"]; ok && main != "" {
|
|
||||||
@templ.Raw(main)
|
|
||||||
} else {
|
|
||||||
<div class="max-w-5xl mx-auto py-20 px-4 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground">
|
|
||||||
No content blocks assigned to this page.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</main>
|
|
||||||
<footer class="w-full mt-auto">
|
|
||||||
@templ.Raw(data.Slots["footer"])
|
|
||||||
</footer>
|
|
||||||
@bn.BodyEnd(data.SiteSettings)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Render entry points (adapted by wrap() in register.go) =====
|
|
||||||
|
|
||||||
func RenderScifiClean(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiClean(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanLanding(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanLanding(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanArticle(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanArticle(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanFullWidth(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
@ -1,643 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/core/templates/bn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PageData holds the values lifted out of the render `doc` map for the
|
|
||||||
// four Sci-Fi Clean page templates.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseScifiPageData lifts the well-known keys out of the inbound doc map.
|
|
||||||
// Unknown keys (e.g. block content) are ignored by the page renderers.
|
|
||||||
func parseScifiPageData(doc map[string]any) PageData {
|
|
||||||
title := "Untitled"
|
|
||||||
if t, ok := doc["title"].(string); ok {
|
|
||||||
title = t
|
|
||||||
}
|
|
||||||
|
|
||||||
slots := make(map[string]string)
|
|
||||||
if s, ok := doc["slots"].(map[string]string); ok {
|
|
||||||
slots = s
|
|
||||||
}
|
|
||||||
|
|
||||||
themeCSS := ""
|
|
||||||
if tc, ok := doc["theme_css"].(string); ok {
|
|
||||||
themeCSS = tc
|
|
||||||
}
|
|
||||||
|
|
||||||
structuredData := ""
|
|
||||||
if sd, ok := doc["structured_data"].(string); ok {
|
|
||||||
structuredData = sd
|
|
||||||
}
|
|
||||||
|
|
||||||
cssHash := ""
|
|
||||||
if ch, ok := doc["css_hash"].(string); ok {
|
|
||||||
cssHash = ch
|
|
||||||
}
|
|
||||||
|
|
||||||
pageviewNonce := ""
|
|
||||||
if pn, ok := doc["pageview_nonce"].(string); ok {
|
|
||||||
pageviewNonce = pn
|
|
||||||
}
|
|
||||||
|
|
||||||
themeMode := "light"
|
|
||||||
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
|
|
||||||
themeMode = tm
|
|
||||||
}
|
|
||||||
|
|
||||||
siteSettings := bn.ParseSiteSettings(doc)
|
|
||||||
pageMeta := bn.ParsePageMeta(doc)
|
|
||||||
engagementConfig := bn.ParseEngagementConfig(doc)
|
|
||||||
|
|
||||||
return PageData{
|
|
||||||
Title: title,
|
|
||||||
Slots: slots,
|
|
||||||
ThemeMode: themeMode,
|
|
||||||
ThemeCSS: themeCSS,
|
|
||||||
SiteSettings: siteSettings,
|
|
||||||
PageMeta: pageMeta,
|
|
||||||
StructuredData: structuredData,
|
|
||||||
CSSHash: cssHash,
|
|
||||||
PageviewNonce: pageviewNonce,
|
|
||||||
EngagementConfig: engagementConfig,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// htmlClassForMode returns the root <html> class for the current theme mode.
|
|
||||||
func htmlClassForMode(mode string) string {
|
|
||||||
if mode == "dark" {
|
|
||||||
return "dark"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Default template (header / main / footer) =====
|
|
||||||
func ScifiClean(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{},
|
|
||||||
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=\"scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body);\">")
|
|
||||||
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\">")
|
|
||||||
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, "</header><main class=\"flex-grow max-w-5xl mx-auto w-full px-4 py-8\">")
|
|
||||||
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 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground\">No content blocks assigned to this page.</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\">")
|
|
||||||
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, "</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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Landing template (hero / specs / main / cta / footer) =====
|
|
||||||
func ScifiCleanLanding(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{},
|
|
||||||
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=\"scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body);\">")
|
|
||||||
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["hero"]).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</section>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if specs, ok := data.Slots["specs"]; ok && specs != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<section class=\"w-full hairline-b py-12\"><div class=\"max-w-6xl mx-auto px-4\"><div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(specs).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div></div></section>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<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 = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div class=\"max-w-6xl mx-auto px-4 py-16\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</main>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if cta, ok := data.Slots["cta"]; ok && cta != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<section class=\"w-full hairline-t py-16\"><div class=\"max-w-6xl mx-auto px-4\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(cta).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div></section>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<footer class=\"w-full mt-auto\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</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, 27, "</body></html>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Article template (header / rail / main / footer) =====
|
|
||||||
func ScifiCleanArticle(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, 28, "<!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, 29, "<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, 30, "\">")
|
|
||||||
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{},
|
|
||||||
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, 31, "<body class=\"scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body);\">")
|
|
||||||
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, 32, "<header class=\"w-full hairline-b\">")
|
|
||||||
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, 33, "</header><main class=\"flex-grow w-full\"><div class=\"max-w-5xl mx-auto px-4 py-12 grid grid-cols-12 gap-8\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if rail, ok := data.Slots["rail"]; ok && rail != "" {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<aside class=\"col-span-12 md:col-span-3 scifi-mono uppercase text-xs tracking-widest text-muted-foreground space-y-3\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(rail).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</aside>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<article class=\"col-span-12 md:col-span-9 scifi-body max-w-2xl\">")
|
|
||||||
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, 37, "<p class=\"text-muted-foreground\">No article body.</p>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</article></div></main><footer class=\"w-full mt-auto\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</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, 40, "</body></html>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Full-width template (header / main / footer) =====
|
|
||||||
func ScifiCleanFullWidth(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, 41, "<!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, 42, "<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, 43, "\">")
|
|
||||||
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{},
|
|
||||||
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, 44, "<body class=\"scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col\" style=\"font-family: var(--font-body);\">")
|
|
||||||
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, 45, "<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, 46, "</header><main class=\"flex-grow w-full bg-grid\">")
|
|
||||||
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, 47, "<div class=\"max-w-5xl mx-auto py-20 px-4 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground\">No content blocks assigned to this page.</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</main><footer class=\"w-full mt-auto\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(data.Slots["footer"]).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</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, 50, "</body></html>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Render entry points (adapted by wrap() in register.go) =====
|
|
||||||
|
|
||||||
func RenderScifiClean(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiClean(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanLanding(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanLanding(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanArticle(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanArticle(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderScifiCleanFullWidth(ctx context.Context, doc map[string]any) templ.Component {
|
|
||||||
return ScifiCleanFullWidth(parseScifiPageData(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
60
templates/email/scifi-clean.ninjatpl
Normal file
60
templates/email/scifi-clean.ninjatpl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="x-apple-disable-message-reformatting">
|
||||||
|
<title>{{ site_name }}</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body, table, td, p, a, li {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
img { border: 0; height: auto; outline: none; text-decoration: none; }
|
||||||
|
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
|
||||||
|
/* Mono numeral preservation across clients. */
|
||||||
|
.scifi-num {
|
||||||
|
font-family: ui-monospace, "JetBrains Mono", "Menlo", monospace !important;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 620px) {
|
||||||
|
.scifi-email-container { width: 100% !important; max-width: 100% !important; }
|
||||||
|
.scifi-pad { padding-left: 20px !important; padding-right: 20px !important; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="background-color: {{ colors.background|default:"#F6F7F8" }}; margin: 0; padding: 0; font-family: &#39;Inter&#39;, -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, sans-serif; color: {{ colors.foreground|default:"#16202E" }};">
|
||||||
|
{% if preview_text %}<div style="display: none; max-height: 0; overflow: hidden;">{{ preview_text }}</div>{% endif %}
|
||||||
|
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 32px 12px; background-color: {{ colors.background|default:"#F6F7F8" }};">
|
||||||
|
<table role="presentation" class="scifi-email-container" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; background-color: {{ colors.card|default:"#FFFFFF" }}; border: 1px solid {{ colors.border|default:"#D6D9DD" }};">
|
||||||
|
<tr>
|
||||||
|
<td class="scifi-pad" style="padding: 20px 28px; border-bottom: 1px solid {{ colors.border|default:"#D6D9DD" }};">
|
||||||
|
<table width="100%" cellspacing="0" cellpadding="0" border="0">
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-family: &#39;Space Grotesk&#39;, &#39;Inter&#39;, sans-serif; font-weight: 600; font-size: 16px; letter-spacing: 0.02em; color: {{ colors.foreground|default:"#16202E" }};">{{ site_name }}</td>
|
||||||
|
<td align="right" class="scifi-num" style="font-family: ui-monospace, &#39;JetBrains Mono&#39;, monospace; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: {{ colors.mutedForeground|default:"#5C6776" }};">{% if site_name %}SCF / {{ site_name }}{% else %}SCF-CLN{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="scifi-pad" style="padding: 28px; font-size: 15px; line-height: 1.55; color: {{ colors.foreground|default:"#16202E" }};">{{ body|safe }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="scifi-pad" style="padding: 16px 28px; border-top: 1px solid {{ colors.border|default:"#D6D9DD" }}; background-color: {{ colors.card|default:"#FFFFFF" }};">
|
||||||
|
<table width="100%" cellspacing="0" cellpadding="0" border="0">
|
||||||
|
<tr>
|
||||||
|
<td class="scifi-num" align="left" style="font-family: ui-monospace, &#39;JetBrains Mono&#39;, monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: {{ colors.mutedForeground|default:"#5C6776" }};">{{ site_url }}</td>
|
||||||
|
{% if unsubscribe_url %}<td class="scifi-num" align="right" style="font-family: ui-monospace, &#39;JetBrains Mono&#39;, monospace; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;"><a href="{{ unsubscribe_url }}" style="color: {{ colors.mutedForeground|default:"#5C6776" }}; text-decoration: underline;">Unsubscribe</a></td>{% endif %}
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1
templates/overrides/scifi-clean/button.ninjatpl
Normal file
1
templates/overrides/scifi-clean/button.ninjatpl
Normal file
@ -0,0 +1 @@
|
|||||||
|
{% if text %}<a href="{% if url %}{{ url }}{% else %}#{% endif %}" class="scifi-mono uppercase tracking-widest text-xs px-5 py-3 scifi-focus inline-flex items-center justify-center gap-2 {% if variant == "outline" %}hairline text-foreground bg-transparent{% elif variant == "destructive" %}bg-destructive text-destructive-foreground{% else %}bg-primary text-primary-foreground{% endif %}" style="font-family: var(--font-mono);"><span>{{ text }}</span> <span data-icon="chevron-right" aria-hidden="true">→</span></a>{% endif %}
|
||||||
1
templates/overrides/scifi-clean/heading.ninjatpl
Normal file
1
templates/overrides/scifi-clean/heading.ninjatpl
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div class="my-6">{% if kicker %}<div class="scifi-mono uppercase tracking-widest text-xs text-accent mb-2">{{ kicker }}</div>{% endif %}{% if level|integer == 1 %}<h1 class="scifi-h1 text-4xl md:text-5xl font-medium tracking-tight text-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h1>{% elif level|integer == 3 %}<h3 class="scifi-h3 text-2xl font-medium text-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h3>{% elif level|integer == 4 %}<h4 class="scifi-h4 text-xl font-medium text-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h4>{% elif level|integer == 5 %}<h5 class="scifi-h4 text-lg font-medium text-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h5>{% elif level|integer == 6 %}<h6 class="scifi-h4 text-base font-medium uppercase tracking-widest text-muted-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h6>{% else %}<h2 class="scifi-h2 text-3xl font-medium tracking-tight text-foreground {{ textClass }}" style="font-family: var(--font-heading);">{{ text }}</h2>{% endif %}</div>
|
||||||
1
templates/overrides/scifi-clean/text.ninjatpl
Normal file
1
templates/overrides/scifi-clean/text.ninjatpl
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div class="scifi-body prose max-w-none text-foreground tabular-nums {{ class }}" style="font-family: var(--font-body);">{{ text|safe }}</div>
|
||||||
18
templates/scifi-clean/article.ninjatpl
Normal file
18
templates/scifi-clean/article.ninjatpl
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||||
|
{{ head_html|safe }}
|
||||||
|
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
||||||
|
{{ admin_banner_html|safe }}
|
||||||
|
<header class="w-full hairline-b">{{ slots.header|safe }}</header>
|
||||||
|
<main class="flex-grow w-full">
|
||||||
|
<div class="max-w-5xl mx-auto px-4 py-12 grid grid-cols-12 gap-8">
|
||||||
|
{% if slots.rail %}<aside class="col-span-12 md:col-span-3 scifi-mono uppercase text-xs tracking-widest text-muted-foreground space-y-3">{{ slots.rail|safe }}</aside>{% endif %}
|
||||||
|
<article class="col-span-12 md:col-span-9 scifi-body max-w-2xl">
|
||||||
|
{% if slots.main %}{{ slots.main|safe }}{% else %}<p class="text-muted-foreground">No article body.</p>{% endif %}
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||||
|
{{ body_end_html|safe }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
13
templates/scifi-clean/default.ninjatpl
Normal file
13
templates/scifi-clean/default.ninjatpl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||||
|
{{ head_html|safe }}
|
||||||
|
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
||||||
|
{{ admin_banner_html|safe }}
|
||||||
|
<header class="w-full">{{ slots.header|safe }}</header>
|
||||||
|
<main class="flex-grow max-w-5xl mx-auto w-full px-4 py-8">
|
||||||
|
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground">No content blocks assigned to this page.</div>{% endif %}
|
||||||
|
</main>
|
||||||
|
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||||
|
{{ body_end_html|safe }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
13
templates/scifi-clean/full-width.ninjatpl
Normal file
13
templates/scifi-clean/full-width.ninjatpl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||||
|
{{ head_html|safe }}
|
||||||
|
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
||||||
|
{{ admin_banner_html|safe }}
|
||||||
|
<header class="w-full">{{ slots.header|safe }}</header>
|
||||||
|
<main class="flex-grow w-full bg-grid">
|
||||||
|
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="max-w-5xl mx-auto py-20 px-4 text-center scifi-mono uppercase tracking-widest text-xs text-muted-foreground">No content blocks assigned to this page.</div>{% endif %}
|
||||||
|
</main>
|
||||||
|
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||||
|
{{ body_end_html|safe }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
15
templates/scifi-clean/landing.ninjatpl
Normal file
15
templates/scifi-clean/landing.ninjatpl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||||
|
{{ head_html|safe }}
|
||||||
|
<body class="scifi-body bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body);">
|
||||||
|
{{ admin_banner_html|safe }}
|
||||||
|
<section class="w-full">{{ slots.hero|safe }}</section>
|
||||||
|
{% if slots.specs %}<section class="w-full hairline-b py-12"><div class="max-w-6xl mx-auto px-4"><div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">{{ slots.specs|safe }}</div></div></section>{% endif %}
|
||||||
|
<main class="flex-grow w-full">
|
||||||
|
{% if slots.main %}<div class="max-w-6xl mx-auto px-4 py-16">{{ slots.main|safe }}</div>{% endif %}
|
||||||
|
</main>
|
||||||
|
{% if slots.cta %}<section class="w-full hairline-t py-16"><div class="max-w-6xl mx-auto px-4">{{ slots.cta|safe }}</div></section>{% endif %}
|
||||||
|
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||||
|
{{ body_end_html|safe }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ScifiTextBlock renders body text with Inter via the --font-body variable.
|
|
||||||
// Inline numerals retain a tabular-nums treatment via the scifi-text class.
|
|
||||||
func ScifiTextBlock(ctx context.Context, content map[string]any) string {
|
|
||||||
text := getString(content, "text")
|
|
||||||
class := getString(content, "class")
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
_ = scifiTextComponent(text, class).Render(ctx, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// scifiTextComponent renders Inter body copy with the tabular-nums numeral treatment.
|
|
||||||
templ scifiTextComponent(text, class string) {
|
|
||||||
<div class={ "scifi-body prose max-w-none text-foreground tabular-nums", class } style="font-family: var(--font-body);">
|
|
||||||
@templ.Raw(text)
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
// Code generated by templ - DO NOT EDIT.
|
|
||||||
|
|
||||||
// templ: version: v0.3.1020
|
|
||||||
package main
|
|
||||||
|
|
||||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
||||||
|
|
||||||
import "github.com/a-h/templ"
|
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
|
||||||
|
|
||||||
// scifiTextComponent renders Inter body copy with the tabular-nums numeral treatment.
|
|
||||||
func scifiTextComponent(text, class string) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var1 == nil {
|
|
||||||
templ_7745c5c3_Var1 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
var templ_7745c5c3_Var2 = []any{"scifi-body prose max-w-none text-foreground tabular-nums", class}
|
|
||||||
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `text_override.templ`, Line: 1, Col: 0}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" style=\"font-family: var(--font-body);\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templ.Raw(text).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = templruntime.GeneratedTemplate
|
|
||||||
Loading…
x
Reference in New Issue
Block a user