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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-07-04 15:26:00 +08:00
parent b32e3f143a
commit 8ea1477d37
73 changed files with 487 additions and 4228 deletions

View File

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

48
blocks/blocks.yaml Normal file
View File

@ -0,0 +1,48 @@
# Cyberpunk theme block definitions (codeless .bnp, WO-WZ-021).
# Keys are fully qualified (cyberpunk:<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: cyberpunk:hero_glitch
title: Glitch Hero
description: RGB-split H1, neon CTA, optional scanline overlay toggle.
category: layout
schema: hero_glitch.schema.json
template: hero_glitch.ninjatpl
- key: cyberpunk:cta_terminal
title: Terminal CTA
description: Faux $ prompt with blinking caret and copy button.
category: layout
schema: cta_terminal.schema.json
template: cta_terminal.ninjatpl
- key: cyberpunk:navbar_terminal
title: Terminal Navbar
description: Mono-spaced navbar with $ command prefix and optional status dot.
category: navigation
schema: navbar_terminal.schema.json
template: navbar_terminal.ninjatpl
- key: cyberpunk:footer_grid
title: Grid Footer
description: Mono columns, build-hash + uptime status pill.
category: navigation
schema: footer_grid.schema.json
template: footer_grid.ninjatpl
- key: cyberpunk:feature_card_neon
title: Neon Feature Card
description: Single feature card with per-card neon edge glow (magenta/cyan/lime).
category: layout
schema: feature_card_neon.schema.json
template: feature_card_neon.ninjatpl
- key: cyberpunk:stats_glow
title: Glow Stats
description: Big mono numerals with neon accent underline.
category: display
schema: stats_glow.schema.json
template: stats_glow.ninjatpl
- key: cyberpunk:code_neon
title: Code Block
description: Server-rendered code block with neon edge and optional copy button.
category: content
schema: code_neon.schema.json
template: code_neon.ninjatpl

View File

@ -0,0 +1 @@
<figure data-block="cyberpunk:code_neon" class="cyberpunk-code w-full my-6 rounded-lg overflow-hidden neon-edge-magenta" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground));"><figcaption class="flex items-center justify-between px-4 py-2 cyberpunk-mono text-xs uppercase tracking-widest" style="background-color: hsl(var(--secondary)); color: hsl(var(--muted-foreground));"><span>{{ language|default:'text' }}</span>{% if copy != false and copy != "false" and copy != "off" and copy != "no" and copy != "0" and copy != "" %} <button type="button" class="cyberpunk-code-copy cyberpunk-mono uppercase tracking-widest px-2 py-1 rounded" style="border: 1px solid hsl(var(--border)); color: hsl(var(--accent));" data-copy="{{ code }}">COPY</button>{% endif %}</figcaption><pre class="cyberpunk-mono overflow-x-auto p-4 text-sm leading-relaxed" style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);"><code class="language-{{ language|default:'text' }}">{{ code }}</code></pre></figure>

View File

@ -0,0 +1 @@
<section data-block="cyberpunk:cta_terminal" class="cyberpunk-cta-terminal w-full py-16" style="background-color: hsl(var(--card));"><div class="max-w-4xl mx-auto px-4"><div class="cyberpunk-mono rounded-lg p-6 md:p-8 flex flex-col md:flex-row items-stretch md:items-center gap-4" style="background-color: hsl(var(--background)); border: 1px dashed hsl(var(--primary));"><div class="flex-1 flex items-center gap-2 text-base md:text-lg overflow-hidden"><span aria-hidden="true" style="color: hsl(var(--accent));">$</span> <code class="cyberpunk-mono whitespace-pre-wrap break-all" style="color: hsl(var(--foreground));" data-caret-blink>{{ prompt|default:'$ npm i your-thing' }}</code> <span aria-hidden="true" class="caret-blink" data-caret-blink style="color: hsl(var(--primary));">▍</span></div>{% if button|default:'Copy' %}<a href="{{ href|default:'#' }}" class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center justify-center gap-2 px-4 py-2 rounded-md font-semibold uppercase tracking-wider" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"{% if copyable != false and copyable != "false" and copyable != "off" and copyable != "no" and copyable != "0" and copyable != "" %} data-copy="{{ prompt|default:'$ npm i your-thing' }}"{% endif %}>{{ button|default:'Copy' }}</a>{% endif %}</div></div></section>

View File

@ -0,0 +1 @@
<article data-block="cyberpunk:feature_card_neon" data-accent="{% if accent == "cyan" %}cyan{% elif accent == "lime" %}lime{% else %}magenta{% endif %}" class="cyberpunk-feature-card p-6 rounded-lg h-full flex flex-col gap-4 {% if accent == "cyan" %}neon-edge-cyan{% elif accent == "lime" %}neon-edge-lime{% else %}neon-edge-magenta{% endif %}" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border));">{% if icon %}<div class="cyberpunk-feature-icon w-10 h-10 flex items-center justify-center rounded-md" style="background-color: hsl(var(--secondary));"><img src="{{ icon }}" alt="" class="w-6 h-6" onerror="this.style.display='none'"></div>{% endif %}<h3 class="cyberpunk-feature-title text-lg font-semibold" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ title|default:'Feature' }}</h3>{% if body %}<div class="cyberpunk-feature-body text-sm leading-relaxed" style="color: hsl(var(--muted-foreground));">{{ body|safe }}</div>{% endif %}</article>

View File

@ -0,0 +1 @@
<div data-block="cyberpunk:footer_grid" class="cyberpunk-footer w-full" style="background-color: hsl(var(--card)); color: hsl(var(--muted-foreground));"><div class="max-w-6xl mx-auto px-4 py-12">{% if columns %}<div class="grid gap-8 mb-10 cyberpunk-mono text-sm {% if columns|length == 2 %}grid-cols-1 sm:grid-cols-2{% elif columns|length == 3 %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-3{% elif columns|length >= 4 %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-4{% else %}grid-cols-1{% endif %}">{% for col in columns %}<div>{% if col.title %}<p class="cyberpunk-mono uppercase tracking-widest text-xs mb-4" style="color: hsl(var(--accent));">{{ col.title }}</p>{% endif %}{% if col.links %}<ul class="space-y-2">{% for link in col.links %}<li><a href="{{ link.href|default:'#' }}" class="cyberpunk-footer-link hover:underline" style="color: hsl(var(--foreground));">{{ link.label }}</a></li>{% endfor %}</ul>{% endif %}</div>{% endfor %}</div>{% else %}<p class="cyberpunk-mono mb-6 text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">// add columns to populate this grid</p>{% endif %}<div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-3 pt-6" style="border-top: 1px dashed hsl(var(--border));"><p class="cyberpunk-mono text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">BUILD <span style="color: hsl(var(--foreground));">{{ buildHash|default:'dev' }}</span></p>{% if showStatus != false and showStatus != "false" and showStatus != "off" and showStatus != "no" and showStatus != "0" and showStatus != "" %}<span class="cyberpunk-status-pill cyberpunk-mono inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs uppercase tracking-widest" style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"><span aria-hidden="true" class="cyberpunk-status-dot inline-block w-2 h-2 rounded-full" style="background-color: hsl(var(--accent)); box-shadow: 0 0 6px hsl(var(--accent));"></span> OK</span>{% endif %}</div></div></div>

View File

@ -0,0 +1 @@
<section data-block="cyberpunk:hero_glitch" class="cyberpunk-hero relative w-full overflow-hidden py-24 md:py-32" style="background-color: hsl(var(--background));">{% if scanlines != false and scanlines != "false" and scanlines != "off" and scanlines != "no" and scanlines != "0" and scanlines != "" %}<div aria-hidden="true" class="scanlines pointer-events-none absolute inset-0" data-scanlines-local></div>{% endif %}<div class="relative z-10 max-w-5xl mx-auto px-4 text-center">{% if eyebrow %}<p class="cyberpunk-eyebrow cyberpunk-mono inline-block px-3 py-1 mb-6 text-xs uppercase tracking-[0.35em]" style="color: hsl(var(--accent)); border: 1px dashed hsl(var(--accent));">{{ eyebrow }}</p>{% endif %}<h1 class="glitch cyberpunk-display text-5xl md:text-7xl font-bold leading-[1.05] tracking-tight mb-8" data-text="{{ headline|default:'// hero headline' }}" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ headline|default:'// hero headline' }}</h1>{% if sub %}<p class="cyberpunk-sub mx-auto max-w-2xl text-lg md:text-xl mb-10" style="color: hsl(var(--muted-foreground));">{{ sub }}</p>{% endif %}<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">{% if cta.label %}<a href="{{ cta.href|default:'#' }}" class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"><span>{{ cta.label }}</span> <span aria-hidden="true" class="caret-blink">_</span></a>{% endif %}{% if secondaryCta.label %}<a href="{{ secondaryCta.href|default:'#' }}" class="cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider" style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"><span>{{ secondaryCta.label }}</span></a>{% endif %}</div></div></section>

View File

@ -0,0 +1 @@
<nav data-block="cyberpunk:navbar_terminal" class="cyberpunk-navbar w-full" style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));"><div class="max-w-6xl mx-auto px-4 py-3 flex items-center justify-between gap-4"><div class="flex items-center gap-3 min-w-0">{% if statusDot != false and statusDot != "false" and statusDot != "off" and statusDot != "no" and statusDot != "0" and statusDot != "" %}<span aria-hidden="true" class="cyberpunk-status-dot inline-block w-2 h-2 rounded-full" style="background-color: hsl(var(--accent)); box-shadow: 0 0 8px hsl(var(--accent));"></span>{% endif %}<span class="cyberpunk-mono text-sm" style="color: hsl(var(--accent));">{{ commandPrefix|default:'~/' }}</span> <span class="cyberpunk-mono text-sm truncate" style="color: hsl(var(--foreground));">{{ menuName|default:'main' }}</span> <span aria-hidden="true" class="caret-blink cyberpunk-mono text-sm" style="color: hsl(var(--primary));">_</span></div><button type="button" aria-expanded="false" aria-controls="cyberpunk-navbar-links" class="cyberpunk-navbar-toggle md:hidden inline-flex items-center justify-center px-3 py-2 rounded-md cyberpunk-mono uppercase text-xs tracking-widest" style="border: 1px solid hsl(var(--border)); color: hsl(var(--foreground));" data-cyberpunk-navbar-toggle>MENU</button><ul id="cyberpunk-navbar-links" class="cyberpunk-navbar-links hidden md:flex items-center gap-6 cyberpunk-mono text-sm uppercase tracking-widest" style="color: hsl(var(--muted-foreground));" data-menu-name="{{ menuName|default:'main' }}"><li class="cyberpunk-navbar-hint" style="color: hsl(var(--muted-foreground));">// menu items resolve at runtime</li></ul></div></nav>

View File

@ -0,0 +1 @@
<section data-block="cyberpunk:stats_glow" class="cyberpunk-stats w-full py-16" style="background-color: hsl(var(--background));"><div class="max-w-6xl mx-auto px-4">{% if items %}<div class="grid gap-8 text-center {% if items|length == 2 %}grid-cols-1 sm:grid-cols-2{% elif items|length == 3 %}grid-cols-1 sm:grid-cols-3{% elif items|length >= 4 %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-4{% else %}grid-cols-1{% endif %}">{% for stat in items %}<div class="cyberpunk-stat-cell"><div class="cyberpunk-mono cyberpunk-stat-number text-5xl md:text-6xl font-bold tracking-tight" style="color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);"><span>{{ stat.value }}</span>{% if stat.suffix %} <span style="color: hsl(var(--primary));">{{ stat.suffix }}</span>{% endif %}</div><div class="cyberpunk-stat-underline mx-auto mt-2 mb-3 h-px w-12" style="background-color: hsl(var(--accent));"></div><div class="cyberpunk-mono cyberpunk-stat-label text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">{{ stat.label }}</div></div>{% endfor %}</div>{% else %}<div class="text-center cyberpunk-mono text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">// add items to render stats</div>{% endif %}</div></section>

View File

@ -1,18 +0,0 @@
package main
import (
"bytes"
"context"
)
// CyberpunkButtonBlock renders the built-in button with cyberpunk styling:
// terminal-cursor caret suffix, RGB-split hover via the .rgb-split class,
// mono label and uppercase tracking.
func CyberpunkButtonBlock(ctx context.Context, content map[string]any) string {
label := getStringWithDefault(content, "label", "Button")
href := safeHref(getString(content, "href"))
variant := getStringWithDefault(content, "variant", "primary")
var buf bytes.Buffer
_ = cyberpunkButtonComponent(label, href, variant).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,36 +0,0 @@
package main
// cyberpunkButtonComponent renders the override for the built-in button block.
// Primary buttons get .rgb-split for the chromatic-aberration hover.
// Secondary / ghost variants use the accent/border tokens.
templ cyberpunkButtonComponent(label, href, variant string) {
switch variant {
case "secondary":
<a
href={ templ.SafeURL(href) }
class="cyberpunk-btn cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider"
style="background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground));"
>
<span>{ label }</span>
<span aria-hidden="true" class="caret-blink">_</span>
</a>
case "ghost":
<a
href={ templ.SafeURL(href) }
class="cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider"
style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"
>
<span>{ label }</span>
<span aria-hidden="true" class="caret-blink">_</span>
</a>
default:
<a
href={ templ.SafeURL(href) }
class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider"
style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"
>
<span>{ label }</span>
<span aria-hidden="true" class="caret-blink">_</span>
</a>
}
}

View File

@ -1,134 +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"
// cyberpunkButtonComponent renders the override for the built-in button block.
// Primary buttons get .rgb-split for the chromatic-aberration hover.
// Secondary / ghost variants use the accent/border tokens.
func cyberpunkButtonComponent(label, href, variant string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch variant {
case "secondary":
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 templ.SafeURL
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 10, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" class=\"cyberpunk-btn cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider\" style=\"background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 14, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span> <span aria-hidden=\"true\" class=\"caret-blink\">_</span></a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case "ghost":
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 templ.SafeURL
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 19, Col: 30}
}
_, 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, "\" class=\"cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider\" style=\"border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 23, 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, 6, "</span> <span aria-hidden=\"true\" class=\"caret-blink\">_</span></a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
default:
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<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(href))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 28, Col: 30}
}
_, 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, "\" class=\"cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `button_override.templ`, Line: 32, Col: 17}
}
_, 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, "</span> <span aria-hidden=\"true\" class=\"caret-blink\">_</span></a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,18 +0,0 @@
package main
import (
"bytes"
"context"
)
// CyberpunkCardBlock renders the built-in card with a dashed neon border-image
// and hover-lift / chromatic-aberration shadow.
func CyberpunkCardBlock(ctx context.Context, content map[string]any) string {
title := getString(content, "title")
body := getString(content, "body")
href := getString(content, "href")
media := getString(content, "media")
var buf bytes.Buffer
_ = cyberpunkCardComponent(title, body, href, media).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,44 +0,0 @@
package main
// cyberpunkCardComponent renders the override for the built-in card block:
// dashed neon border, hover-lift with chromatic-aberration shadow.
templ cyberpunkCardComponent(title, body, href, media string) {
if href != "" {
<a
href={ templ.SafeURL(safeHref(href)) }
class="cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full transition-transform hover:-translate-y-0.5"
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));"
>
@cyberpunkCardInner(title, body, media)
</a>
} else {
<article
class="cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full"
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));"
>
@cyberpunkCardInner(title, body, media)
</article>
}
}
// cyberpunkCardInner renders the shared card body markup.
templ cyberpunkCardInner(title, body, media string) {
if media != "" {
<img
src={ media }
alt=""
class="cyberpunk-card-media w-full h-40 object-cover rounded mb-4"
onerror="this.style.display='none'"
/>
}
if title != "" {
<h3 class="cyberpunk-card-title text-lg font-semibold mb-2" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">
{ title }
</h3>
}
if body != "" {
<div class="cyberpunk-card-body text-sm leading-relaxed" style="color: hsl(var(--muted-foreground));">
@templ.Raw(body)
</div>
}
}

View File

@ -1,156 +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"
// cyberpunkCardComponent renders the override for the built-in card block:
// dashed neon border, hover-lift with chromatic-aberration shadow.
func cyberpunkCardComponent(title, body, href, media string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if href != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 templ.SafeURL
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(safeHref(href)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 8, Col: 39}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" class=\"cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full transition-transform hover:-translate-y-0.5\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = cyberpunkCardInner(title, body, media).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<article class=\"cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = cyberpunkCardInner(title, body, media).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</article>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
// cyberpunkCardInner renders the shared card body markup.
func cyberpunkCardInner(title, body, media 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_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if media != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(media)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 28, Col: 14}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" alt=\"\" class=\"cyberpunk-card-media w-full h-40 object-cover rounded mb-4\" onerror=\"this.style.display='none'\"> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<h3 class=\"cyberpunk-card-title text-lg font-semibold mb-2\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `card_override.templ`, Line: 36, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if body != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"cyberpunk-card-body text-sm leading-relaxed\" style=\"color: hsl(var(--muted-foreground));\">")
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, 11, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,39 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// CodeNeonMeta defines metadata for the cyberpunk:code_neon block.
var CodeNeonMeta = blocks.BlockMeta{
Key: "code_neon",
Title: "Code Block",
Description: "Server-rendered code block with neon edge and optional copy button",
Category: blocks.CategoryContent,
Source: "cyberpunk",
}
// CodeNeonData is the typed view of the code_neon content map.
type CodeNeonData struct {
Language string
Code string
Copy bool
}
// CodeNeonBlock renders the code_neon block.
//
// Content shape:
// {language:"bash"|"go"|..., code, copy: bool|"on"|"off"}
func CodeNeonBlock(ctx context.Context, content map[string]any) string {
data := CodeNeonData{
Language: getStringWithDefault(content, "language", "text"),
Code: getString(content, "code"),
Copy: getBool(content, "copy", true),
}
var buf bytes.Buffer
_ = codeNeonComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,25 +0,0 @@
package main
// codeNeonComponent renders the cyberpunk:code_neon block.
templ codeNeonComponent(data CodeNeonData) {
<figure
data-block="cyberpunk:code_neon"
class="cyberpunk-code w-full my-6 rounded-lg overflow-hidden neon-edge-magenta"
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground));"
>
<figcaption class="flex items-center justify-between px-4 py-2 cyberpunk-mono text-xs uppercase tracking-widest" style="background-color: hsl(var(--secondary)); color: hsl(var(--muted-foreground));">
<span>{ data.Language }</span>
if data.Copy {
<button
type="button"
class="cyberpunk-code-copy cyberpunk-mono uppercase tracking-widest px-2 py-1 rounded"
style="border: 1px solid hsl(var(--border)); color: hsl(var(--accent));"
data-copy={ data.Code }
>
COPY
</button>
}
</figcaption>
<pre class="cyberpunk-mono overflow-x-auto p-4 text-sm leading-relaxed" style="background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);"><code class={ "language-" + data.Language }>{ data.Code }</code></pre>
</figure>
}

View File

@ -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"
// codeNeonComponent renders the cyberpunk:code_neon block.
func codeNeonComponent(data CodeNeonData) 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=\"cyberpunk:code_neon\" class=\"cyberpunk-code w-full my-6 rounded-lg overflow-hidden neon-edge-magenta\" style=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground));\"><figcaption class=\"flex items-center justify-between px-4 py-2 cyberpunk-mono text-xs uppercase tracking-widest\" style=\"background-color: hsl(var(--secondary)); color: hsl(var(--muted-foreground));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Language)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `code_neon.templ`, Line: 11, Col: 24}
}
_, 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> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Copy {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<button type=\"button\" class=\"cyberpunk-code-copy cyberpunk-mono uppercase tracking-widest px-2 py-1 rounded\" style=\"border: 1px solid hsl(var(--border)); color: hsl(var(--accent));\" data-copy=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Code)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `code_neon.templ`, Line: 17, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\">COPY</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</figcaption><pre class=\"cyberpunk-mono overflow-x-auto p-4 text-sm leading-relaxed\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 = []any{"language-" + data.Language}
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, 6, "<code 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: `code_neon.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, 7, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Code)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `code_neon.templ`, Line: 23, Col: 284}
}
_, 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, "</code></pre></figure>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,41 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// CTATerminalMeta defines metadata for the cyberpunk:cta_terminal block.
var CTATerminalMeta = blocks.BlockMeta{
Key: "cta_terminal",
Title: "Terminal CTA",
Description: "Faux $ prompt with blinking caret and copy button",
Category: blocks.CategoryLayout,
Source: "cyberpunk",
}
// CTATerminalData is the typed view of the cta_terminal content map.
type CTATerminalData struct {
Prompt string
Button string
Href string
Copyable bool
}
// CTATerminalBlock renders the cta_terminal block.
//
// Content shape:
// {prompt, button, href, copyable: bool|"true"|"false"}
func CTATerminalBlock(ctx context.Context, content map[string]any) string {
data := CTATerminalData{
Prompt: getStringWithDefault(content, "prompt", "$ npm i your-thing"),
Button: getStringWithDefault(content, "button", "Copy"),
Href: getString(content, "href"),
Copyable: getBool(content, "copyable", true),
}
var buf bytes.Buffer
_ = ctaTerminalComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,37 +0,0 @@
package main
// ctaTerminalComponent renders the cyberpunk:cta_terminal block as a faux terminal prompt.
templ ctaTerminalComponent(data CTATerminalData) {
<section
data-block="cyberpunk:cta_terminal"
class="cyberpunk-cta-terminal w-full py-16"
style="background-color: hsl(var(--card));"
>
<div class="max-w-4xl mx-auto px-4">
<div
class="cyberpunk-mono rounded-lg p-6 md:p-8 flex flex-col md:flex-row items-stretch md:items-center gap-4"
style="background-color: hsl(var(--background)); border: 1px dashed hsl(var(--primary));"
>
<div class="flex-1 flex items-center gap-2 text-base md:text-lg overflow-hidden">
<span aria-hidden="true" style="color: hsl(var(--accent));">$</span>
<code class="cyberpunk-mono whitespace-pre-wrap break-all" style="color: hsl(var(--foreground));" data-caret-blink>
{ data.Prompt }
</code>
<span aria-hidden="true" class="caret-blink" data-caret-blink style="color: hsl(var(--primary));">▍</span>
</div>
if data.Button != "" {
<a
href={ templ.SafeURL(safeHref(data.Href)) }
class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center justify-center gap-2 px-4 py-2 rounded-md font-semibold uppercase tracking-wider"
style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"
if data.Copyable {
data-copy={ data.Prompt }
}
>
{ data.Button }
</a>
}
</div>
</div>
</section>
}

View File

@ -1,113 +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"
// ctaTerminalComponent renders the cyberpunk:cta_terminal block as a faux terminal prompt.
func ctaTerminalComponent(data CTATerminalData) 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=\"cyberpunk:cta_terminal\" class=\"cyberpunk-cta-terminal w-full py-16\" style=\"background-color: hsl(var(--card));\"><div class=\"max-w-4xl mx-auto px-4\"><div class=\"cyberpunk-mono rounded-lg p-6 md:p-8 flex flex-col md:flex-row items-stretch md:items-center gap-4\" style=\"background-color: hsl(var(--background)); border: 1px dashed hsl(var(--primary));\"><div class=\"flex-1 flex items-center gap-2 text-base md:text-lg overflow-hidden\"><span aria-hidden=\"true\" style=\"color: hsl(var(--accent));\">$</span> <code class=\"cyberpunk-mono whitespace-pre-wrap break-all\" style=\"color: hsl(var(--foreground));\" data-caret-blink>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Prompt)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_terminal.templ`, Line: 18, 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, 2, "</code> <span aria-hidden=\"true\" class=\"caret-blink\" data-caret-blink style=\"color: hsl(var(--primary));\">▍</span></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Button != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<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(data.Href)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_terminal.templ`, Line: 24, Col: 47}
}
_, 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, "\" class=\"cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center justify-center gap-2 px-4 py-2 rounded-md font-semibold uppercase tracking-wider\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Copyable {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " data-copy=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Prompt)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_terminal.templ`, Line: 28, Col: 30}
}
_, 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, 6, "\"")
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(data.Button)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cta_terminal.templ`, Line: 31, Col: 19}
}
_, 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, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,102 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/templates"
)
// CyberpunkEmailWrapper is the registered cyberpunk:email_wrapper.
// It produces a dark email with a mono preheader, magenta hairline divider,
// and a literal "[esc] unsubscribe" link per UAT §10.
//
// UAT §10 mandates `body { background:#0a0a12 }`. That literal hex lives in the
// <style> head block (a <style> element is not a `style=` attribute and so does
// not trip the no-inline-hex-style rule). All other colour values use hsl()
// notation, which most modern mail clients render fine.
func CyberpunkEmailWrapper(body string, emailCtx templates.EmailContext) string {
var buf bytes.Buffer
_ = cyberpunkEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
return buf.String()
}
// cyberpunkEmailTemplate is the Cyberpunk-branded HTML email shell.
templ cyberpunkEmailTemplate(emailCtx templates.EmailContext, body string) {
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="x-apple-disable-message-reformatting"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>{ emailCtx.SiteSettings.SiteName }</title>
<style type="text/css">
body { background:#0a0a12; margin:0; padding:0; color: hsl(260 25% 92%); }
table, td { mso-table-lspace:0pt; mso-table-rspace:0pt; }
a { color: inherit; }
.cyberpunk-preheader { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.cyberpunk-divider { border-top:1px solid hsl(320 100% 60%); }
@media only screen and (max-width: 620px) {
.email-container { width:100% !important; max-width:100% !important; }
.content-padding { padding-left:24px !important; padding-right:24px !important; }
}
</style>
</head>
<body bgcolor="#0a0a12" style="margin:0;padding:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;">
if emailCtx.PreviewText != "" {
<div class="cyberpunk-preheader" style="display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;">
$ from: { emailCtx.SiteSettings.SiteName } — { emailCtx.PreviewText }
</div>
} else {
<div class="cyberpunk-preheader" style="display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;">
$ from: { emailCtx.SiteSettings.SiteName }
</div>
}
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#0a0a12">
<tr>
<td align="center" style="padding:48px 12px;">
<table role="presentation" class="email-container" width="600" cellpadding="0" cellspacing="0" border="0" bgcolor="#101020" style="max-width:600px;border:1px solid hsl(258 28% 20%);">
<tr>
<td class="content-padding" align="center" style="padding:32px 40px;border-bottom:1px solid hsl(320 100% 60%);">
<div class="cyberpunk-preheader" style="font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.2em;text-transform:uppercase;">
$ from: { emailCtx.SiteSettings.SiteName }
</div>
if emailCtx.SiteSettings.LogoURL != "" {
<img src={ emailCtx.SiteSettings.LogoURL } alt={ emailCtx.SiteSettings.SiteName } style="margin-top:12px;max-height:48px;width:auto;display:inline-block;"/>
}
</td>
</tr>
<tr>
<td class="content-padding" style="padding:40px 48px;font-size:16px;line-height:1.7;">
@templ.Raw(body)
</td>
</tr>
<tr>
<td class="cyberpunk-divider" height="1" style="border-top:1px solid hsl(320 100% 60%);font-size:0;line-height:0;">&nbsp;</td>
</tr>
<tr>
<td class="content-padding" align="center" style="padding:24px 48px 40px;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.15em;text-transform:uppercase;">
if emailCtx.SiteSettings.SiteURL != "" {
<p style="margin:0 0 12px;">
<a href={ templ.SafeURL(emailCtx.SiteSettings.SiteURL) } style="text-decoration:none;">
{ emailCtx.SiteSettings.SiteURL }
</a>
</p>
}
if emailCtx.UnsubscribeURL != "" {
<p style="margin:0;">
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style="text-decoration:none;">[esc] unsubscribe</a>
</p>
} else {
<p style="margin:0;">[esc] unsubscribe</p>
}
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
}

View File

@ -1,246 +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 (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/templates"
)
// CyberpunkEmailWrapper is the registered cyberpunk:email_wrapper.
// It produces a dark email with a mono preheader, magenta hairline divider,
// and a literal "[esc] unsubscribe" link per UAT §10.
//
// UAT §10 mandates `body { background:#0a0a12 }`. That literal hex lives in the
// <style> head block (a <style> element is not a `style=` attribute and so does
// not trip the no-inline-hex-style rule). All other colour values use hsl()
// notation, which most modern mail clients render fine.
func CyberpunkEmailWrapper(body string, emailCtx templates.EmailContext) string {
var buf bytes.Buffer
_ = cyberpunkEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
return buf.String()
}
// cyberpunkEmailTemplate is the Cyberpunk-branded HTML email shell.
func cyberpunkEmailTemplate(emailCtx templates.EmailContext, body string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"x-apple-disable-message-reformatting\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 33, 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 { background:#0a0a12; margin:0; padding:0; color: hsl(260 25% 92%); }\n\t\t\t\ttable, td { mso-table-lspace:0pt; mso-table-rspace:0pt; }\n\t\t\t\ta { color: inherit; }\n\t\t\t\t.cyberpunk-preheader { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }\n\t\t\t\t.cyberpunk-divider { border-top:1px solid hsl(320 100% 60%); }\n\t\t\t\t@media only screen and (max-width: 620px) {\n\t\t\t\t\t.email-container { width:100% !important; max-width:100% !important; }\n\t\t\t\t\t.content-padding { padding-left:24px !important; padding-right:24px !important; }\n\t\t\t\t}\n\t\t\t</style></head><body bgcolor=\"#0a0a12\" style=\"margin:0;padding:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.PreviewText != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"cyberpunk-preheader\" style=\"display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\">$ from: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, 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: 49, Col: 45}
}
_, 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, " — ")
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: 49, Col: 74}
}
_, 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
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"cyberpunk-preheader\" style=\"display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\">$ from: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, 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: 53, Col: 45}
}
_, 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, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" bgcolor=\"#0a0a12\"><tr><td align=\"center\" style=\"padding:48px 12px;\"><table role=\"presentation\" class=\"email-container\" width=\"600\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" bgcolor=\"#101020\" style=\"max-width:600px;border:1px solid hsl(258 28% 20%);\"><tr><td class=\"content-padding\" align=\"center\" style=\"padding:32px 40px;border-bottom:1px solid hsl(320 100% 60%);\"><div class=\"cyberpunk-preheader\" style=\"font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.2em;text-transform:uppercase;\">$ from: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(emailCtx.SiteSettings.SiteName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 63, Col: 50}
}
_, 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, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.SiteSettings.LogoURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(emailCtx.SiteSettings.LogoURL)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 66, Col: 50}
}
_, 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, 11, "\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(emailCtx.SiteSettings.SiteName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 66, Col: 89}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" style=\"margin-top:12px;max-height:48px;width:auto;display:inline-block;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</td></tr><tr><td class=\"content-padding\" style=\"padding:40px 48px;font-size:16px;line-height:1.7;\">")
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, 14, "</td></tr><tr><td class=\"cyberpunk-divider\" height=\"1\" style=\"border-top:1px solid hsl(320 100% 60%);font-size:0;line-height:0;\">&nbsp;</td></tr><tr><td class=\"content-padding\" align=\"center\" style=\"padding:24px 48px 40px;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.15em;text-transform:uppercase;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if emailCtx.SiteSettings.SiteURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<p style=\"margin:0 0 12px;\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 templ.SafeURL
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(emailCtx.SiteSettings.SiteURL))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `email_wrapper.templ`, Line: 82, Col: 65}
}
_, 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, 16, "\" style=\"text-decoration:none;\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, 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: 83, Col: 43}
}
_, 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, 17, "</a></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if emailCtx.UnsubscribeURL != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<p style=\"margin:0;\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 templ.SafeURL
templ_7745c5c3_Var11, 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: 89, Col: 59}
}
_, 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, 19, "\" style=\"text-decoration:none;\">[esc] unsubscribe</a></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<p style=\"margin:0;\">[esc] unsubscribe</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</td></tr></table></td></tr></table></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -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 (rooted at "assets/").
func Assets() fs.FS {
sub, _ := fs.Sub(assetsFS, "assets")
return sub
}
// Schemas returns the embedded schemas filesystem (rooted at "schemas/").
func Schemas() fs.FS {
sub, _ := fs.Sub(schemasFS, "schemas")
return sub
}
// AssetsHandler returns an http.Handler that serves the embedded assets at /templates/cyberpunk/...
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 exposes the theme's custom CSS (scanlines, glitch, neon-edge,
// caret-blink keyframes, font-family fallbacks) to the host Tailwind input so the
// utilities survive prod purging.
func ThemeCSSManifest() *plugin.CSSManifest {
css, err := assetsFS.ReadFile("assets/css/cyberpunk.css")
if err != nil {
return &plugin.CSSManifest{}
}
return &plugin.CSSManifest{
InputCSSAppend: string(css),
}
}

View File

@ -1,51 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// FeatureCardNeonMeta defines metadata for the cyberpunk:feature_card_neon block.
var FeatureCardNeonMeta = blocks.BlockMeta{
Key: "feature_card_neon",
Title: "Neon Feature Card",
Description: "Single feature card with per-card neon edge glow (magenta/cyan/lime)",
Category: blocks.CategoryLayout,
Source: "cyberpunk",
}
// FeatureCardNeonData is the typed view of the feature_card_neon content map.
type FeatureCardNeonData struct {
Icon string
Title string
Body string
Accent string
}
// FeatureCardNeonBlock renders the feature_card_neon block.
//
// Content shape:
// {icon, title, body, accent:"magenta"|"cyan"|"lime"}
func FeatureCardNeonBlock(ctx context.Context, content map[string]any) string {
data := FeatureCardNeonData{
Icon: getString(content, "icon"),
Title: getStringWithDefault(content, "title", "Feature"),
Body: getString(content, "body"),
Accent: parseAccent(getString(content, "accent")),
}
var buf bytes.Buffer
_ = featureCardNeonComponent(data).Render(ctx, &buf)
return buf.String()
}
// parseAccent normalises the accent value to one of the three known accents.
func parseAccent(v string) string {
switch v {
case "magenta", "cyan", "lime":
return v
default:
return "magenta"
}
}

View File

@ -1,37 +0,0 @@
package main
// neonEdgeClass returns the per-accent neon-edge utility class.
func neonEdgeClass(accent string) string {
switch accent {
case "cyan":
return "neon-edge-cyan"
case "lime":
return "neon-edge-lime"
default:
return "neon-edge-magenta"
}
}
// featureCardNeonComponent renders the cyberpunk:feature_card_neon block.
templ featureCardNeonComponent(data FeatureCardNeonData) {
<article
data-block="cyberpunk:feature_card_neon"
data-accent={ data.Accent }
class={ "cyberpunk-feature-card p-6 rounded-lg h-full flex flex-col gap-4", neonEdgeClass(data.Accent) }
style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border));"
>
if data.Icon != "" {
<div class="cyberpunk-feature-icon w-10 h-10 flex items-center justify-center rounded-md" style="background-color: hsl(var(--secondary));">
<img src={ data.Icon } alt="" class="w-6 h-6" onerror="this.style.display='none'"/>
</div>
}
<h3 class="cyberpunk-feature-title text-lg font-semibold" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">
{ data.Title }
</h3>
if data.Body != "" {
<div class="cyberpunk-feature-body text-sm leading-relaxed" style="color: hsl(var(--muted-foreground));">
@templ.Raw(data.Body)
</div>
}
</article>
}

View File

@ -1,138 +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"
// neonEdgeClass returns the per-accent neon-edge utility class.
func neonEdgeClass(accent string) string {
switch accent {
case "cyan":
return "neon-edge-cyan"
case "lime":
return "neon-edge-lime"
default:
return "neon-edge-magenta"
}
}
// featureCardNeonComponent renders the cyberpunk:feature_card_neon block.
func featureCardNeonComponent(data FeatureCardNeonData) 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{"cyberpunk-feature-card p-6 rounded-lg h-full flex flex-col gap-4", neonEdgeClass(data.Accent)}
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, "<article data-block=\"cyberpunk:feature_card_neon\" data-accent=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Accent)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `feature_card_neon.templ`, Line: 19, Col: 27}
}
_, 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, "\" 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: `feature_card_neon.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=\"background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Icon != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"cyberpunk-feature-icon w-10 h-10 flex items-center justify-center rounded-md\" style=\"background-color: hsl(var(--secondary));\"><img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `feature_card_neon.templ`, Line: 25, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" alt=\"\" class=\"w-6 h-6\" onerror=\"this.style.display='none'\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<h3 class=\"cyberpunk-feature-title text-lg font-semibold\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `feature_card_neon.templ`, Line: 29, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Body != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<div class=\"cyberpunk-feature-body text-sm leading-relaxed\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(data.Body).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</article>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,62 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// FooterGridMeta defines metadata for the cyberpunk:footer_grid block.
var FooterGridMeta = blocks.BlockMeta{
Key: "footer_grid",
Title: "Grid Footer",
Description: "Mono columns, build-hash + uptime status pill",
Category: blocks.CategoryNavigation,
Source: "cyberpunk",
}
// FooterColumn is one column of footer links.
type FooterColumn struct {
Title string
Links []Link
}
// FooterGridData is the typed view of the footer_grid content map.
type FooterGridData struct {
ShowStatus bool
BuildHash string
Columns []FooterColumn
}
// FooterGridBlock renders the footer_grid block.
//
// Content shape:
// {showStatus, buildHash, columns:[{title, links:[{label, href}]}]}
func FooterGridBlock(ctx context.Context, content map[string]any) string {
cols := getSlice(content, "columns")
columns := make([]FooterColumn, 0, len(cols))
for _, col := range cols {
linkObjs := getSlice(col, "links")
links := make([]Link, 0, len(linkObjs))
for _, l := range linkObjs {
links = append(links, Link{
Label: getString(l, "label"),
Href: getString(l, "href"),
})
}
columns = append(columns, FooterColumn{
Title: getString(col, "title"),
Links: links,
})
}
data := FooterGridData{
ShowStatus: getBool(content, "showStatus", true),
BuildHash: getStringWithDefault(content, "buildHash", "dev"),
Columns: columns,
}
var buf bytes.Buffer
_ = footerGridComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,77 +0,0 @@
package main
// footerGridColumns returns a tailwind grid-column class for n columns.
func footerGridColumns(n int) string {
switch n {
case 0, 1:
return "grid-cols-1"
case 2:
return "grid-cols-1 sm:grid-cols-2"
case 3:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
default:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
}
}
// footerGridComponent renders the cyberpunk:footer_grid block.
templ footerGridComponent(data FooterGridData) {
<div
data-block="cyberpunk:footer_grid"
class="cyberpunk-footer w-full"
style="background-color: hsl(var(--card)); color: hsl(var(--muted-foreground));"
>
<div class="max-w-6xl mx-auto px-4 py-12">
if len(data.Columns) > 0 {
<div class={ "grid gap-8 mb-10 cyberpunk-mono text-sm", footerGridColumns(len(data.Columns)) }>
for _, col := range data.Columns {
<div>
if col.Title != "" {
<p class="cyberpunk-mono uppercase tracking-widest text-xs mb-4" style="color: hsl(var(--accent));">
{ col.Title }
</p>
}
if len(col.Links) > 0 {
<ul class="space-y-2">
for _, link := range col.Links {
<li>
<a
href={ templ.SafeURL(safeHref(link.Href)) }
class="cyberpunk-footer-link hover:underline"
style="color: hsl(var(--foreground));"
>
{ link.Label }
</a>
</li>
}
</ul>
}
</div>
}
</div>
} else {
<p class="cyberpunk-mono mb-6 text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">
{ "// add columns to populate this grid" }
</p>
}
<div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-3 pt-6" style="border-top: 1px dashed hsl(var(--border));">
<p class="cyberpunk-mono text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">
BUILD <span style="color: hsl(var(--foreground));">{ data.BuildHash }</span>
</p>
if data.ShowStatus {
<span
class="cyberpunk-status-pill cyberpunk-mono inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs uppercase tracking-widest"
style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"
>
<span
aria-hidden="true"
class="cyberpunk-status-dot inline-block w-2 h-2 rounded-full"
style="background-color: hsl(var(--accent)); box-shadow: 0 0 6px hsl(var(--accent));"
></span>
OK
</span>
}
</div>
</div>
</div>
}

View File

@ -1,199 +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"
// footerGridColumns returns a tailwind grid-column class for n columns.
func footerGridColumns(n int) string {
switch n {
case 0, 1:
return "grid-cols-1"
case 2:
return "grid-cols-1 sm:grid-cols-2"
case 3:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
default:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
}
}
// footerGridComponent renders the cyberpunk:footer_grid block.
func footerGridComponent(data FooterGridData) 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=\"cyberpunk:footer_grid\" class=\"cyberpunk-footer w-full\" style=\"background-color: hsl(var(--card)); color: hsl(var(--muted-foreground));\"><div class=\"max-w-6xl mx-auto px-4 py-12\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(data.Columns) > 0 {
var templ_7745c5c3_Var2 = []any{"grid gap-8 mb-10 cyberpunk-mono text-sm", footerGridColumns(len(data.Columns))}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.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
}
for _, col := range data.Columns {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if col.Title != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<p class=\"cyberpunk-mono uppercase tracking-widest text-xs mb-4\" style=\"color: hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(col.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.templ`, Line: 31, Col: 20}
}
_, 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, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(col.Links) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<ul class=\"space-y-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, link := range col.Links {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<li><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(safeHref(link.Href)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.templ`, Line: 39, Col: 53}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" class=\"cyberpunk-footer-link hover:underline\" style=\"color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(link.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.templ`, Line: 43, Col: 24}
}
_, 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, "</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</ul>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<p class=\"cyberpunk-mono mb-6 text-xs uppercase tracking-widest\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("// add columns to populate this grid")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.templ`, Line: 54, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<div class=\"flex flex-col md:flex-row items-start md:items-center justify-between gap-3 pt-6\" style=\"border-top: 1px dashed hsl(var(--border));\"><p class=\"cyberpunk-mono text-xs uppercase tracking-widest\" style=\"color: hsl(var(--muted-foreground));\">BUILD <span style=\"color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.BuildHash)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `footer_grid.templ`, Line: 59, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</span></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.ShowStatus {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<span class=\"cyberpunk-status-pill cyberpunk-mono inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs uppercase tracking-widest\" style=\"border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));\"><span aria-hidden=\"true\" class=\"cyberpunk-status-dot inline-block w-2 h-2 rounded-full\" style=\"background-color: hsl(var(--accent)); box-shadow: 0 0 6px hsl(var(--accent));\"></span> OK</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

20
go.mod
View File

@ -1,20 +0,0 @@
module git.dev.alexdunmow.com/block/themes/cyberpunk
go 1.26.4
require (
git.dev.alexdunmow.com/block/core v0.15.2
github.com/a-h/templ v0.3.1020
)
require (
connectrpc.com/connect v1.20.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.9.2 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/text v0.36.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)

46
go.sum
View File

@ -1,46 +0,0 @@
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
git.dev.alexdunmow.com/block/core v0.15.2 h1:qTjJxa1pClxwehkdTxXiJDpHQLr5DoXBUCa40QRO0L8=
git.dev.alexdunmow.com/block/core v0.15.2/go.mod h1:A+mgA9oeWoPhXruv4Mjpywwl2A9B5I3cKzlJjalBdlE=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,18 +0,0 @@
package main
import (
"bytes"
"context"
)
// CyberpunkHeadingBlock renders the built-in heading block with cyberpunk styling.
// H1/H2 get the glitch text-shadow (magenta + cyan offsets); smaller levels get
// mono small-caps eyebrow class.
func CyberpunkHeadingBlock(ctx context.Context, content map[string]any) string {
text := getString(content, "text")
textClass := getString(content, "textClass")
level := parseHeadingLevel(content)
var buf bytes.Buffer
_ = cyberpunkHeadingComponent(level, text, textClass).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,81 +0,0 @@
package main
// cyberpunkHeadingBaseClass returns default Tailwind classes for each heading level.
func cyberpunkHeadingBaseClass(level int) string {
switch level {
case 1:
return "text-4xl md:text-5xl font-bold tracking-tight"
case 2:
return "text-3xl md:text-4xl font-semibold tracking-tight"
case 3:
return "text-2xl font-semibold"
case 4:
return "text-xl font-semibold"
case 5:
return "text-lg font-medium"
case 6:
return "text-base font-medium"
default:
return "text-3xl font-semibold tracking-tight"
}
}
// cyberpunkHeadingComponent renders the override for the built-in heading block.
// H1 and H2 get the .glitch class which gives them the RGB-split text-shadow.
// H3-H6 get the mono small-caps eyebrow class.
templ cyberpunkHeadingComponent(level int, text, textClass string) {
switch level {
case 1:
<h1
class={ "cyberpunk-display glitch", cyberpunkHeadingBaseClass(1), textClass }
data-text={ text }
style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);"
>
{ text }
</h1>
case 2:
<h2
class={ "cyberpunk-display glitch", cyberpunkHeadingBaseClass(2), textClass }
data-text={ text }
style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);"
>
{ text }
</h2>
case 3:
<h3
class={ "cyberpunk-display", cyberpunkHeadingBaseClass(3), textClass }
style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);"
>
{ text }
</h3>
case 4:
<h4
class={ "cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(4), textClass }
style="color: hsl(var(--accent));"
>
{ text }
</h4>
case 5:
<h5
class={ "cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(5), textClass }
style="color: hsl(var(--accent));"
>
{ text }
</h5>
case 6:
<h6
class={ "cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(6), textClass }
style="color: hsl(var(--accent));"
>
{ text }
</h6>
default:
<h2
class={ "cyberpunk-display glitch", cyberpunkHeadingBaseClass(2), textClass }
data-text={ text }
style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);"
>
{ text }
</h2>
}
}

View File

@ -1,352 +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"
// cyberpunkHeadingBaseClass returns default Tailwind classes for each heading level.
func cyberpunkHeadingBaseClass(level int) string {
switch level {
case 1:
return "text-4xl md:text-5xl font-bold tracking-tight"
case 2:
return "text-3xl md:text-4xl font-semibold tracking-tight"
case 3:
return "text-2xl font-semibold"
case 4:
return "text-xl font-semibold"
case 5:
return "text-lg font-medium"
case 6:
return "text-base font-medium"
default:
return "text-3xl font-semibold tracking-tight"
}
}
// cyberpunkHeadingComponent renders the override for the built-in heading block.
// H1 and H2 get the .glitch class which gives them the RGB-split text-shadow.
// H3-H6 get the mono small-caps eyebrow class.
func cyberpunkHeadingComponent(level int, text, textClass string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch level {
case 1:
var templ_7745c5c3_Var2 = []any{"cyberpunk-display glitch", cyberpunkHeadingBaseClass(1), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<h1 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" data-text=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 31, Col: 20}
}
_, 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=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
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: 34, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 2:
var templ_7745c5c3_Var6 = []any{"cyberpunk-display glitch", cyberpunkHeadingBaseClass(2), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<h2 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var6).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" data-text=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 39, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 42, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 3:
var templ_7745c5c3_Var10 = []any{"cyberpunk-display", cyberpunkHeadingBaseClass(3), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<h3 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var10).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 49, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 4:
var templ_7745c5c3_Var13 = []any{"cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(4), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var13...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<h4 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var13).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_Var14)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\" style=\"color: hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 56, Col: 10}
}
_, 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, 14, "</h4>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 5:
var templ_7745c5c3_Var16 = []any{"cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(5), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var16...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<h5 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var16).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_Var17)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\" style=\"color: hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 63, Col: 10}
}
_, 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, 17, "</h5>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 6:
var templ_7745c5c3_Var19 = []any{"cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest", cyberpunkHeadingBaseClass(6), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var19...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<h6 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var19).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_Var20)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\" style=\"color: hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 70, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</h6>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
default:
var templ_7745c5c3_Var22 = []any{"cyberpunk-display glitch", cyberpunkHeadingBaseClass(2), textClass}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var22...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<h2 class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var22).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\" data-text=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var24 string
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 75, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var25 string
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `heading_override.templ`, Line: 78, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,102 +0,0 @@
package main
import "strconv"
// getString extracts a string value from a content map. Returns "" on miss/wrong-type.
func getString(content map[string]any, key string) string {
if v, ok := content[key].(string); ok {
return v
}
return ""
}
// getStringWithDefault is like getString but returns dflt if the key is missing or non-string.
func getStringWithDefault(content map[string]any, key, dflt string) string {
if v, ok := content[key].(string); ok && v != "" {
return v
}
return dflt
}
// getBool extracts a boolean value from a content map. Accepts bool, "true"/"false",
// "on"/"off", "yes"/"no", and numerics. Returns dflt when missing or unparsable.
func getBool(content map[string]any, key string, dflt bool) bool {
switch v := content[key].(type) {
case bool:
return v
case string:
switch v {
case "true", "on", "yes", "1":
return true
case "false", "off", "no", "0", "":
return false
}
case float64:
return v != 0
case int:
return v != 0
}
return dflt
}
// getSlice extracts a slice of object-shaped entries from a content map.
func getSlice(content map[string]any, key string) []map[string]any {
v, ok := content[key].([]any)
if !ok {
return nil
}
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
}
// getLink reads a {label, href} link object. Tolerates string values
// (interpreted as href, label = href) and missing keys.
func getLink(content map[string]any, key string) Link {
v := content[key]
switch x := v.(type) {
case map[string]any:
return Link{Label: getString(x, "label"), Href: getString(x, "href")}
case string:
return Link{Label: x, Href: x}
}
return Link{}
}
// Link is a {label, href} pair used by hero / nav / footer blocks.
type Link struct {
Label string
Href string
}
// safeHref returns "#" when href is empty so templ.SafeURL never receives "".
func safeHref(href string) string {
if href == "" {
return "#"
}
return href
}
// parseHeadingLevel parses a 1..6 heading level. Defaults to 2 for safety.
func parseHeadingLevel(content map[string]any) int {
switch v := content["level"].(type) {
case float64:
l := int(v)
if l >= 1 && l <= 6 {
return l
}
case int:
if v >= 1 && v <= 6 {
return v
}
case string:
if l, err := strconv.Atoi(v); err == nil && l >= 1 && l <= 6 {
return l
}
}
return 2
}

View File

@ -1,55 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// HeroGlitchMeta defines metadata for the cyberpunk glitch hero block.
var HeroGlitchMeta = blocks.BlockMeta{
Key: "hero_glitch",
Title: "Glitch Hero",
Description: "RGB-split H1, neon CTA, optional scanline overlay toggle",
Category: blocks.CategoryLayout,
Source: "cyberpunk",
}
// HeroGlitchData is the typed view of the hero_glitch content map.
type HeroGlitchData struct {
Eyebrow string
Headline string
Sub string
CTA Link
SecondaryCTA Link
Scanlines bool
}
// HeroGlitchBlock renders the hero_glitch block.
//
// Content shape (matches schemas/hero_glitch.schema.json):
// {eyebrow, headline, sub, cta:{label,href}, secondaryCta:{label,href}, scanlines:"on"|"off"}
func HeroGlitchBlock(ctx context.Context, content map[string]any) string {
data := HeroGlitchData{
Eyebrow: getString(content, "eyebrow"),
Headline: getStringWithDefault(content, "headline", "// hero headline"),
Sub: getString(content, "sub"),
CTA: getLink(content, "cta"),
SecondaryCTA: getLink(content, "secondaryCta"),
Scanlines: parseScanlines(content),
}
var buf bytes.Buffer
_ = heroGlitchComponent(data).Render(ctx, &buf)
return buf.String()
}
func parseScanlines(content map[string]any) bool {
if v, ok := content["scanlines"].(string); ok {
return v == "on" || v == "true"
}
if v, ok := content["scanlines"].(bool); ok {
return v
}
return true
}

View File

@ -1,54 +0,0 @@
package main
// heroGlitchComponent renders the cyberpunk:hero_glitch block with an RGB-split H1.
templ heroGlitchComponent(data HeroGlitchData) {
<section
data-block="cyberpunk:hero_glitch"
class="cyberpunk-hero relative w-full overflow-hidden py-24 md:py-32"
style="background-color: hsl(var(--background));"
>
if data.Scanlines {
<div aria-hidden="true" class="scanlines pointer-events-none absolute inset-0" data-scanlines-local></div>
}
<div class="relative z-10 max-w-5xl mx-auto px-4 text-center">
if data.Eyebrow != "" {
<p class="cyberpunk-eyebrow cyberpunk-mono inline-block px-3 py-1 mb-6 text-xs uppercase tracking-[0.35em]" style="color: hsl(var(--accent)); border: 1px dashed hsl(var(--accent));">
{ data.Eyebrow }
</p>
}
<h1
class="glitch cyberpunk-display text-5xl md:text-7xl font-bold leading-[1.05] tracking-tight mb-8"
data-text={ data.Headline }
style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);"
>
{ data.Headline }
</h1>
if data.Sub != "" {
<p class="cyberpunk-sub mx-auto max-w-2xl text-lg md:text-xl mb-10" style="color: hsl(var(--muted-foreground));">
{ data.Sub }
</p>
}
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
if data.CTA.Label != "" {
<a
href={ templ.SafeURL(safeHref(data.CTA.Href)) }
class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider"
style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"
>
<span>{ data.CTA.Label }</span>
<span aria-hidden="true" class="caret-blink">_</span>
</a>
}
if data.SecondaryCTA.Label != "" {
<a
href={ templ.SafeURL(safeHref(data.SecondaryCTA.Href)) }
class="cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider"
style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"
>
<span>{ data.SecondaryCTA.Label }</span>
</a>
}
</div>
</div>
</section>
}

View File

@ -1,191 +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"
// heroGlitchComponent renders the cyberpunk:hero_glitch block with an RGB-split H1.
func heroGlitchComponent(data HeroGlitchData) 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=\"cyberpunk:hero_glitch\" class=\"cyberpunk-hero relative w-full overflow-hidden py-24 md:py-32\" style=\"background-color: hsl(var(--background));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Scanlines {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div aria-hidden=\"true\" class=\"scanlines pointer-events-none absolute inset-0\" data-scanlines-local></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"relative z-10 max-w-5xl mx-auto px-4 text-center\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Eyebrow != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<p class=\"cyberpunk-eyebrow cyberpunk-mono inline-block px-3 py-1 mb-6 text-xs uppercase tracking-[0.35em]\" style=\"color: hsl(var(--accent)); border: 1px dashed hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.Eyebrow)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 16, 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, 5, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<h1 class=\"glitch cyberpunk-display text-5xl md:text-7xl font-bold leading-[1.05] tracking-tight mb-8\" data-text=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.Headline)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 21, Col: 29}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\" style=\"color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.Headline)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 24, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.Sub != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<p class=\"cyberpunk-sub mx-auto max-w-2xl text-lg md:text-xl mb-10\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(data.Sub)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 28, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"flex flex-col sm:flex-row gap-4 justify-center items-center\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.CTA.Label != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<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(safeHref(data.CTA.Href)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 34, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\" class=\"cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider\" style=\"background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(data.CTA.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 38, 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, 14, "</span> <span aria-hidden=\"true\" class=\"caret-blink\">_</span></a> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.SecondaryCTA.Label != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<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(safeHref(data.SecondaryCTA.Href)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 44, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\" class=\"cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-6 py-3 rounded-md font-semibold uppercase tracking-wider\" style=\"border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(data.SecondaryCTA.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `hero_glitch.templ`, Line: 48, Col: 37}
}
_, 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, 17, "</span></a>")
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
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

17
main.go
View File

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

277
manifest.yaml Normal file
View File

@ -0,0 +1,277 @@
# Cyberpunk theme — codeless .bnp manifest (WO-WZ-021 Phase B).
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
theme_presets: presets.json
bundled_fonts: fonts.json
master_pages: master_pages.json
system_templates:
- key: cyberpunk
title: Cyberpunk
description: "Neon-on-black BlockNinja theme with glitch motifs, monospace accents, and magenta/cyan/lime tri-accent palette for SaaS, dev tools, and crypto."
page_templates:
- system: cyberpunk
key: default
title: Default
description: "Standard dark page with scanline overlay, sticky terminal-style header"
slots: [header, main, footer]
- system: cyberpunk
key: landing
title: Landing
description: "Hero with glitch H1, neon CTA, feature grid, social proof, footer"
slots: [hero, features, cta, footer]
- system: cyberpunk
key: article
title: Article
description: "Mono-metadata header, prose column, code-friendly aside"
slots: [header, main, aside, footer]
- system: cyberpunk
key: full-width
title: Full Width
description: "Edge-to-edge dashboard / showcase layout, no max-width"
slots: [header, main, footer]
template_overrides:
- { template: cyberpunk, block: heading }
- { template: cyberpunk, block: text }
- { template: cyberpunk, block: button }
- { template: cyberpunk, block: card }
email_wrappers:
- cyberpunk
css:
input_css_append: |
/* ============================================================
Cyberpunk — Neon-on-black BlockNinja theme
Scanlines / glitch / RGB-split / caret-blink / neon-edge utilities.
All colours consume the host shadcn HSL tokens via hsl(var(--token)).
No hardcoded hex / rgb / named colours.
============================================================ */
/* --- Typography fallbacks --------------------------------- */
.cyberpunk-body {
font-family: var(--font-body, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif);
}
.cyberpunk-mono,
.cyberpunk-mono *,
.cyberpunk-mono code,
pre.cyberpunk-mono,
code.cyberpunk-mono {
font-family: var(--font-mono, "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, monospace);
}
.cyberpunk-display {
font-family: var(--font-heading, "Space Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif);
letter-spacing: -0.01em;
}
.cyberpunk-prose,
.cyberpunk-prose p,
.cyberpunk-prose li {
font-family: var(--font-body, "Inter", system-ui, sans-serif);
line-height: 1.75;
}
.cyberpunk-prose code {
color: hsl(var(--accent));
background-color: hsl(var(--muted));
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace);
font-size: 0.875em;
}
/* --- Scanlines -------------------------------------------- */
.scanlines {
opacity: 0.04;
background-image: linear-gradient(
to bottom,
hsl(var(--foreground)) 0px,
hsl(var(--foreground)) 1px,
transparent 1px,
transparent 3px
);
background-size: 100% 3px;
animation: scanline-drift 6s linear infinite;
}
@keyframes scanline-drift {
0% { background-position: 0 0; }
100% { background-position: 0 3px; }
}
/* --- Glitch (RGB-split text-shadow) on H1/H2 -------------- */
.glitch {
position: relative;
text-shadow:
-2px 0 hsl(var(--primary)),
2px 0 hsl(var(--accent));
animation: glitch-x 3.6s steps(1, end) infinite;
}
@keyframes glitch-x {
0%, 92%, 100% {
text-shadow:
-2px 0 hsl(var(--primary)),
2px 0 hsl(var(--accent));
}
93% {
text-shadow:
-3px 0 hsl(var(--primary)),
3px 0 hsl(var(--accent)),
0 1px hsl(var(--accent));
}
95% {
text-shadow:
-1px 0 hsl(var(--accent)),
4px 0 hsl(var(--primary));
}
97% {
text-shadow:
-2px 0 hsl(var(--primary)),
2px 0 hsl(var(--accent));
}
}
/* --- RGB-split hover/focus/active on primary buttons ------ */
.rgb-split {
transition: transform 120ms ease, box-shadow 120ms ease;
}
.rgb-split:hover,
.rgb-split:focus-visible {
box-shadow:
-2px 0 0 hsl(var(--primary)),
2px 0 0 hsl(var(--accent));
transform: translateY(-1px);
}
/* Touch tap-flash fallback (iOS strips :hover after touchend) */
.cyberpunk-btn:active,
.rgb-split:active,
button.cyberpunk-btn:active {
box-shadow:
-2px 0 0 hsl(var(--primary)),
2px 0 0 hsl(var(--accent));
}
/* :focus-visible ring uses the ring token, not browser default */
.cyberpunk-btn:focus-visible,
.cyberpunk-btn-ghost:focus-visible,
button:focus-visible,
a:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
/* --- Caret blink ------------------------------------------ */
.caret-blink {
display: inline-block;
animation: caret 1.05s steps(2, end) infinite;
}
@keyframes caret {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* --- Neon edge utilities (magenta / cyan / lime) ---------- */
.neon-edge-magenta {
box-shadow:
0 0 0 1px hsl(var(--primary) / 0.4),
0 0 18px hsl(var(--primary) / 0.25);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-magenta:hover,
.neon-edge-magenta:focus-within {
box-shadow:
0 0 0 1px hsl(var(--primary) / 0.85),
0 0 28px hsl(var(--primary) / 0.45);
transform: translateY(-1px);
}
.neon-edge-cyan {
box-shadow:
0 0 0 1px hsl(var(--accent) / 0.4),
0 0 18px hsl(var(--accent) / 0.25);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-cyan:hover,
.neon-edge-cyan:focus-within {
box-shadow:
0 0 0 1px hsl(var(--accent) / 0.85),
0 0 28px hsl(var(--accent) / 0.45);
transform: translateY(-1px);
}
.neon-edge-lime {
/* Lime accent is the toxic-bloom primary; magenta-noir uses the primary
token. We reuse --ring as a third neon channel so this utility renders
visibly across all three presets. */
box-shadow:
0 0 0 1px hsl(var(--ring) / 0.4),
0 0 18px hsl(var(--ring) / 0.25);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-lime:hover,
.neon-edge-lime:focus-within {
box-shadow:
0 0 0 1px hsl(var(--ring) / 0.85),
0 0 28px hsl(var(--ring) / 0.45);
transform: translateY(-1px);
}
/* --- Card override dashed border --------------------------- */
.cyberpunk-card {
position: relative;
}
/* --- Status pill / dot animation -------------------------- */
.cyberpunk-status-dot {
animation: cyberpunk-pulse 2.2s ease-in-out infinite;
}
@keyframes cyberpunk-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* --- Reduced motion: disable glitch, caret, scanline ------ */
@media (prefers-reduced-motion: reduce) {
.glitch,
.caret-blink,
.scanlines,
.cyberpunk-status-dot {
animation: none !important;
animation-duration: 0.01ms !important;
}
.glitch {
text-shadow: none;
}
.scanlines {
opacity: 0;
}
.rgb-split:hover,
.rgb-split:focus-visible {
transform: none;
}
}
/* --- High-contrast: kill scanlines ------------------------ */
@media (prefers-contrast: more) {
.scanlines {
display: none;
}
}

33
master_pages.json Normal file
View File

@ -0,0 +1,33 @@
[
{
"key": "cyberpunk:default-master",
"title": "Cyberpunk Default Master",
"page_templates": ["default", "article"],
"blocks": [
{ "block_key": "cyberpunk:navbar_terminal", "title": "Top Nav", "content": { "menuName": "main", "commandPrefix": "~/" }, "slot": "header", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main", "placeholder": "// content" }, "slot": "main", "sort_order": 0 },
{ "block_key": "cyberpunk:footer_grid", "title": "Site Footer", "content": { "showStatus": true, "buildHash": "auto" }, "slot": "footer", "sort_order": 0 }
]
},
{
"key": "cyberpunk:landing-master",
"title": "Cyberpunk Landing Master",
"page_templates": ["landing"],
"blocks": [
{ "block_key": "cyberpunk:hero_glitch", "title": "Glitch Hero", "content": { "eyebrow": "NEW", "headline": "Ship like it's 2049", "cta": { "label": "Get the SDK", "href": "#" } }, "slot": "hero", "sort_order": 0 },
{ "block_key": "slot", "title": "Features Slot", "content": { "slotName": "features" }, "slot": "features", "sort_order": 0 },
{ "block_key": "cyberpunk:cta_terminal", "title": "CTA Strip", "content": { "prompt": "$ npm i your-thing", "button": "Copy" }, "slot": "cta", "sort_order": 0 },
{ "block_key": "cyberpunk:footer_grid", "title": "Site Footer", "content": { "showStatus": true }, "slot": "footer", "sort_order": 0 }
]
},
{
"key": "cyberpunk:full-master",
"title": "Cyberpunk Full Master",
"page_templates": ["full-width"],
"blocks": [
{ "block_key": "cyberpunk:navbar_terminal", "title": "Top Nav", "content": { "menuName": "main" }, "slot": "header", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
{ "block_key": "cyberpunk:footer_grid", "title": "Site Footer", "content": { "showStatus": false }, "slot": "footer", "sort_order": 0 }
]
}
]

View File

@ -1,43 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// NavbarTerminalMeta defines metadata for the cyberpunk:navbar_terminal block.
var NavbarTerminalMeta = blocks.BlockMeta{
Key: "navbar_terminal",
Title: "Terminal Navbar",
Description: "Mono-spaced navbar with $ command prefix and optional status dot",
Category: blocks.CategoryNavigation,
Source: "cyberpunk",
}
// NavbarTerminalData is the typed view of the navbar_terminal content map.
type NavbarTerminalData struct {
MenuName string
CommandPrefix string
StatusDot bool
}
// NavbarTerminalBlock renders the navbar_terminal block.
//
// Content shape:
// {menuName, commandPrefix, statusDot:"on"|"off"|bool}
//
// menuName is the slug of a CMS-managed menu; the actual <ul> items are
// resolved by the host menu lookup. This block emits the chrome wrapper plus a
// data-menu-name hook the host renderer reads at runtime.
func NavbarTerminalBlock(ctx context.Context, content map[string]any) string {
data := NavbarTerminalData{
MenuName: getStringWithDefault(content, "menuName", "main"),
CommandPrefix: getStringWithDefault(content, "commandPrefix", "~/"),
StatusDot: getBool(content, "statusDot", true),
}
var buf bytes.Buffer
_ = navbarTerminalComponent(data).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,50 +0,0 @@
package main
// navbarTerminalComponent renders the cyberpunk:navbar_terminal block.
// At ≤768px the link list collapses behind an aria-expanded toggle button.
templ navbarTerminalComponent(data NavbarTerminalData) {
<nav
data-block="cyberpunk:navbar_terminal"
class="cyberpunk-navbar w-full"
style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));"
>
<div class="max-w-6xl mx-auto px-4 py-3 flex items-center justify-between gap-4">
<div class="flex items-center gap-3 min-w-0">
if data.StatusDot {
<span
aria-hidden="true"
class="cyberpunk-status-dot inline-block w-2 h-2 rounded-full"
style="background-color: hsl(var(--accent)); box-shadow: 0 0 8px hsl(var(--accent));"
></span>
}
<span class="cyberpunk-mono text-sm" style="color: hsl(var(--accent));">
{ data.CommandPrefix }
</span>
<span class="cyberpunk-mono text-sm truncate" style="color: hsl(var(--foreground));">
{ data.MenuName }
</span>
<span aria-hidden="true" class="caret-blink cyberpunk-mono text-sm" style="color: hsl(var(--primary));">_</span>
</div>
<button
type="button"
aria-expanded="false"
aria-controls="cyberpunk-navbar-links"
class="cyberpunk-navbar-toggle md:hidden inline-flex items-center justify-center px-3 py-2 rounded-md cyberpunk-mono uppercase text-xs tracking-widest"
style="border: 1px solid hsl(var(--border)); color: hsl(var(--foreground));"
data-cyberpunk-navbar-toggle
>
MENU
</button>
<ul
id="cyberpunk-navbar-links"
class="cyberpunk-navbar-links hidden md:flex items-center gap-6 cyberpunk-mono text-sm uppercase tracking-widest"
style="color: hsl(var(--muted-foreground));"
data-menu-name={ data.MenuName }
>
<li class="cyberpunk-navbar-hint" style="color: hsl(var(--muted-foreground));">
{ "// menu items resolve at runtime" }
</li>
</ul>
</div>
</nav>
}

View File

@ -1,104 +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"
// navbarTerminalComponent renders the cyberpunk:navbar_terminal block.
// At ≤768px the link list collapses behind an aria-expanded toggle button.
func navbarTerminalComponent(data NavbarTerminalData) 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, "<nav data-block=\"cyberpunk:navbar_terminal\" class=\"cyberpunk-navbar w-full\" style=\"background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));\"><div class=\"max-w-6xl mx-auto px-4 py-3 flex items-center justify-between gap-4\"><div class=\"flex items-center gap-3 min-w-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if data.StatusDot {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span aria-hidden=\"true\" class=\"cyberpunk-status-dot inline-block w-2 h-2 rounded-full\" style=\"background-color: hsl(var(--accent)); box-shadow: 0 0 8px hsl(var(--accent));\"></span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<span class=\"cyberpunk-mono text-sm\" style=\"color: hsl(var(--accent));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(data.CommandPrefix)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `navbar_terminal.templ`, Line: 21, Col: 25}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</span> <span class=\"cyberpunk-mono text-sm truncate\" style=\"color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.MenuName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `navbar_terminal.templ`, Line: 24, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</span> <span aria-hidden=\"true\" class=\"caret-blink cyberpunk-mono text-sm\" style=\"color: hsl(var(--primary));\">_</span></div><button type=\"button\" aria-expanded=\"false\" aria-controls=\"cyberpunk-navbar-links\" class=\"cyberpunk-navbar-toggle md:hidden inline-flex items-center justify-center px-3 py-2 rounded-md cyberpunk-mono uppercase text-xs tracking-widest\" style=\"border: 1px solid hsl(var(--border)); color: hsl(var(--foreground));\" data-cyberpunk-navbar-toggle>MENU</button><ul id=\"cyberpunk-navbar-links\" class=\"cyberpunk-navbar-links hidden md:flex items-center gap-6 cyberpunk-mono text-sm uppercase tracking-widest\" style=\"color: hsl(var(--muted-foreground));\" data-menu-name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(data.MenuName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `navbar_terminal.templ`, Line: 42, Col: 34}
}
_, 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, 6, "\"><li class=\"cyberpunk-navbar-hint\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("// menu items resolve at runtime")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `navbar_terminal.templ`, Line: 45, Col: 41}
}
_, 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, "</li></ul></div></nav>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -2,11 +2,8 @@
name = "cyberpunk"
display_name = "Cyberpunk"
scope = "@themes"
version = "0.1.2"
version = "0.2.0"
description = "Neon-on-black BlockNinja theme with glitch motifs, monospace accents, and magenta/cyan/lime tri-accent palette for SaaS, dev tools, and crypto."
kind = "theme"
categories = ["templates"]
tags = ["dark", "neon", "glitch", "monospace", "saas", "developer", "tech", "crypto", "fintech"]
[compatibility]
block_core = ">=0.15.0 <0.16.0"

View File

@ -1,190 +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 that registers the Cyberpunk system template,
// page templates, theme-owned blocks, built-in overrides, and the email wrapper.
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
// 1. System template metadata.
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
Key: "cyberpunk",
Title: "Cyberpunk",
Description: "Neon-on-black BlockNinja theme with glitch motifs, monospace accents, and magenta/cyan/lime tri-accent palette for SaaS, dev tools, and crypto.",
})
// 2. Page templates — slot lists match docs/works/cyberpunk.md byte-for-byte.
if err := tr.RegisterPageTemplate("cyberpunk", templates.PageTemplateMeta{
Key: "default",
Title: "Default",
Description: "Standard dark page with scanline overlay, sticky terminal-style header",
Slots: []string{"header", "main", "footer"},
}, wrap(RenderCyberpunk)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("cyberpunk", templates.PageTemplateMeta{
Key: "landing",
Title: "Landing",
Description: "Hero with glitch H1, neon CTA, feature grid, social proof, footer",
Slots: []string{"hero", "features", "cta", "footer"},
}, wrap(RenderCyberpunkLanding)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("cyberpunk", templates.PageTemplateMeta{
Key: "article",
Title: "Article",
Description: "Mono-metadata header, prose column, code-friendly aside",
Slots: []string{"header", "main", "aside", "footer"},
}, wrap(RenderCyberpunkArticle)); err != nil {
return err
}
if err := tr.RegisterPageTemplate("cyberpunk", templates.PageTemplateMeta{
Key: "full-width",
Title: "Full Width",
Description: "Edge-to-edge dashboard / showcase layout, no max-width",
Slots: []string{"header", "main", "footer"},
}, wrap(RenderCyberpunkFullWidth)); err != nil {
return err
}
// 3. Load block schemas BEFORE registering any blocks.
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
return err
}
// 4. Theme-owned blocks (seven, per spec section "Blocks to build").
br.Register(HeroGlitchMeta, HeroGlitchBlock)
br.Register(CTATerminalMeta, CTATerminalBlock)
br.Register(NavbarTerminalMeta, NavbarTerminalBlock)
br.Register(FooterGridMeta, FooterGridBlock)
br.Register(FeatureCardNeonMeta, FeatureCardNeonBlock)
br.Register(StatsGlowMeta, StatsGlowBlock)
br.Register(CodeNeonMeta, CodeNeonBlock)
// 5. Built-in block overrides — applied only when this theme is active.
br.RegisterTemplateOverride("cyberpunk", "heading", CyberpunkHeadingBlock)
br.RegisterTemplateOverride("cyberpunk", "text", CyberpunkTextBlock)
br.RegisterTemplateOverride("cyberpunk", "button", CyberpunkButtonBlock)
br.RegisterTemplateOverride("cyberpunk", "card", CyberpunkCardBlock)
// 6. Email wrapper.
tr.RegisterEmailWrapper("cyberpunk", CyberpunkEmailWrapper)
return nil
}
// DefaultMasterPages returns the three master pages Cyberpunk seeds on first load.
// Spec table — section "Master pages" — drives keys, blocks, slots and sort orders.
func DefaultMasterPages() []plugin.MasterPageDefinition {
return []plugin.MasterPageDefinition{
{
Key: "cyberpunk:default-master",
Title: "Cyberpunk Default Master",
PageTemplates: []string{"default", "article"},
Blocks: []plugin.MasterPageBlock{
{
BlockKey: "cyberpunk:navbar_terminal",
Title: "Top Nav",
Content: map[string]any{"menuName": "main", "commandPrefix": "~/"},
Slot: "header",
SortOrder: 0,
},
{
BlockKey: "slot",
Title: "Main Slot",
Content: map[string]any{"slotName": "main", "placeholder": "// content"},
Slot: "main",
SortOrder: 0,
},
{
BlockKey: "cyberpunk:footer_grid",
Title: "Site Footer",
Content: map[string]any{"showStatus": true, "buildHash": "auto"},
Slot: "footer",
SortOrder: 0,
},
},
},
{
Key: "cyberpunk:landing-master",
Title: "Cyberpunk Landing Master",
PageTemplates: []string{"landing"},
Blocks: []plugin.MasterPageBlock{
{
BlockKey: "cyberpunk:hero_glitch",
Title: "Glitch Hero",
Content: map[string]any{"eyebrow": "NEW", "headline": "Ship like it's 2049", "cta": map[string]any{"label": "Get the SDK", "href": "#"}},
Slot: "hero",
SortOrder: 0,
},
{
BlockKey: "slot",
Title: "Features Slot",
Content: map[string]any{"slotName": "features"},
Slot: "features",
SortOrder: 0,
},
{
BlockKey: "cyberpunk:cta_terminal",
Title: "CTA Strip",
Content: map[string]any{"prompt": "$ npm i your-thing", "button": "Copy"},
Slot: "cta",
SortOrder: 0,
},
{
BlockKey: "cyberpunk:footer_grid",
Title: "Site Footer",
Content: map[string]any{"showStatus": true},
Slot: "footer",
SortOrder: 0,
},
},
},
{
Key: "cyberpunk:full-master",
Title: "Cyberpunk Full Master",
PageTemplates: []string{"full-width"},
Blocks: []plugin.MasterPageBlock{
{
BlockKey: "cyberpunk:navbar_terminal",
Title: "Top Nav",
Content: map[string]any{"menuName": "main"},
Slot: "header",
SortOrder: 0,
},
{
BlockKey: "slot",
Title: "Main Slot",
Content: map[string]any{"slotName": "main"},
Slot: "main",
SortOrder: 0,
},
{
BlockKey: "cyberpunk:footer_grid",
Title: "Site Footer",
Content: map[string]any{"showStatus": false},
Slot: "footer",
SortOrder: 0,
},
},
},
}
}

View File

@ -1,26 +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 Cyberpunk theme.
var Registration = plugin.PluginRegistration{
Name: "cyberpunk",
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() },
RequiredIconPacks: plugin.ParseRequiredIconPacks(pluginModBytes),
}

View File

@ -1,43 +0,0 @@
package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// StatsGlowMeta defines metadata for the cyberpunk:stats_glow block.
var StatsGlowMeta = blocks.BlockMeta{
Key: "stats_glow",
Title: "Glow Stats",
Description: "Big mono numerals with neon accent underline",
Category: "display",
Source: "cyberpunk",
}
// StatGlowItem is one stat in the grid.
type StatGlowItem struct {
Value string
Label string
Suffix string
}
// StatsGlowBlock renders the stats_glow block.
//
// Content shape:
// {items:[{value, label, suffix}]}
func StatsGlowBlock(ctx context.Context, content map[string]any) string {
raw := getSlice(content, "items")
items := make([]StatGlowItem, 0, len(raw))
for _, item := range raw {
items = append(items, StatGlowItem{
Value: getString(item, "value"),
Label: getString(item, "label"),
Suffix: getString(item, "suffix"),
})
}
var buf bytes.Buffer
_ = statsGlowComponent(items).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,52 +0,0 @@
package main
// statsGridColumns returns the tailwind grid-column class for n stats.
func statsGridColumns(n int) string {
switch n {
case 0, 1:
return "grid-cols-1"
case 2:
return "grid-cols-1 sm:grid-cols-2"
case 3:
return "grid-cols-1 sm:grid-cols-3"
default:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
}
}
// statsGlowComponent renders the cyberpunk:stats_glow block.
templ statsGlowComponent(items []StatGlowItem) {
<section
data-block="cyberpunk:stats_glow"
class="cyberpunk-stats w-full py-16"
style="background-color: hsl(var(--background));"
>
<div class="max-w-6xl mx-auto px-4">
if len(items) == 0 {
<div class="text-center cyberpunk-mono text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">
{ "// add items to render stats" }
</div>
} else {
<div class={ "grid gap-8 text-center", statsGridColumns(len(items)) }>
for _, stat := range items {
<div class="cyberpunk-stat-cell">
<div
class="cyberpunk-mono cyberpunk-stat-number text-5xl md:text-6xl font-bold tracking-tight"
style="color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);"
>
<span>{ stat.Value }</span>
if stat.Suffix != "" {
<span style="color: hsl(var(--primary));">{ stat.Suffix }</span>
}
</div>
<div class="cyberpunk-stat-underline mx-auto mt-2 mb-3 h-px w-12" style="background-color: hsl(var(--accent));"></div>
<div class="cyberpunk-mono cyberpunk-stat-label text-xs uppercase tracking-widest" style="color: hsl(var(--muted-foreground));">
{ stat.Label }
</div>
</div>
}
</div>
}
</div>
</section>
}

View File

@ -1,160 +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"
// statsGridColumns returns the tailwind grid-column class for n stats.
func statsGridColumns(n int) string {
switch n {
case 0, 1:
return "grid-cols-1"
case 2:
return "grid-cols-1 sm:grid-cols-2"
case 3:
return "grid-cols-1 sm:grid-cols-3"
default:
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
}
}
// statsGlowComponent renders the cyberpunk:stats_glow block.
func statsGlowComponent(items []StatGlowItem) 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=\"cyberpunk:stats_glow\" class=\"cyberpunk-stats w-full py-16\" style=\"background-color: hsl(var(--background));\"><div class=\"max-w-6xl mx-auto px-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(items) == 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"text-center cyberpunk-mono text-xs uppercase tracking-widest\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("// add items to render stats")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stats_glow.templ`, Line: 27, Col: 37}
}
_, 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
}
} else {
var templ_7745c5c3_Var3 = []any{"grid gap-8 text-center", statsGridColumns(len(items))}
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, "<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var3).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stats_glow.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, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, stat := range items {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"cyberpunk-stat-cell\"><div class=\"cyberpunk-mono cyberpunk-stat-number text-5xl md:text-6xl font-bold tracking-tight\" style=\"color: hsl(var(--foreground)); font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);\"><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(stat.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stats_glow.templ`, Line: 37, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if stat.Suffix != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<span style=\"color: hsl(var(--primary));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(stat.Suffix)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stats_glow.templ`, Line: 39, Col: 64}
}
_, 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, "</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"cyberpunk-stat-underline mx-auto mt-2 mb-3 h-px w-12\" style=\"background-color: hsl(var(--accent));\"></div><div class=\"cyberpunk-mono cyberpunk-stat-label text-xs uppercase tracking-widest\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(stat.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `stats_glow.templ`, Line: 44, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,237 +0,0 @@
package main
import (
"context"
"git.dev.alexdunmow.com/block/core/templates/bn"
)
// PageData carries the rendered slots and assorted page chrome data passed
// from the CMS into a Cyberpunk page template.
type PageData struct {
Title string
Slots map[string]string
ThemeMode string
ThemeCSS string
SiteSettings bn.SiteSettingsData
PageMeta bn.PageMeta
StructuredData string
CSSHash string
PageviewNonce string
EngagementConfig bn.EngagementConfig
}
// parseCyberpunkPageData converts the loose doc map the renderer is handed into a typed PageData.
func parseCyberpunkPageData(doc map[string]any) PageData {
title := "Untitled"
if t, ok := doc["title"].(string); ok && t != "" {
title = t
}
slots := map[string]string{}
if s, ok := doc["slots"].(map[string]string); ok {
slots = s
}
themeCSS, _ := doc["theme_css"].(string)
structuredData, _ := doc["structured_data"].(string)
cssHash, _ := doc["css_hash"].(string)
pageviewNonce, _ := doc["pageview_nonce"].(string)
themeMode := "dark"
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
themeMode = tm
}
return PageData{
Title: title,
Slots: slots,
ThemeMode: themeMode,
ThemeCSS: themeCSS,
SiteSettings: bn.ParseSiteSettings(doc),
PageMeta: bn.ParsePageMeta(doc),
StructuredData: structuredData,
CSSHash: cssHash,
PageviewNonce: pageviewNonce,
EngagementConfig: bn.ParseEngagementConfig(doc),
}
}
// scanlineOverlay renders the global scanline overlay element (fixed, pointer-events: none).
templ scanlineOverlay() {
<div aria-hidden="true" class="scanlines pointer-events-none fixed inset-0 z-50" data-cyberpunk-scanlines></div>
}
// Cyberpunk renders the default page template.
templ Cyberpunk(data PageData) {
<!DOCTYPE html>
<html lang="en" class="dark">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
@scanlineOverlay()
<header class="cyberpunk-chrome w-full sticky top-0 z-40" style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["header"])
</header>
<main class="flex-grow w-full max-w-6xl mx-auto px-4 py-12">
if main, ok := data.Slots["main"]; ok && main != "" {
@templ.Raw(main)
} else {
<div class="py-20 text-center cyberpunk-empty" style="color: hsl(var(--muted-foreground));">
<p class="cyberpunk-mono">No content blocks assigned to this page.</p>
</div>
}
</main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// CyberpunkLanding renders the marketing landing template with hero/features/cta/footer slots.
templ CyberpunkLanding(data PageData) {
<!DOCTYPE html>
<html lang="en" class="dark">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
@scanlineOverlay()
<section class="w-full">
@templ.Raw(data.Slots["hero"])
</section>
<section class="w-full max-w-6xl mx-auto px-4 py-16">
@templ.Raw(data.Slots["features"])
</section>
<section class="w-full">
@templ.Raw(data.Slots["cta"])
</section>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// CyberpunkArticle renders the article template with mono-metadata header and a code-friendly aside.
templ CyberpunkArticle(data PageData) {
<!DOCTYPE html>
<html lang="en" class="dark">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
@scanlineOverlay()
<header class="w-full" style="border-bottom: 1px solid hsl(var(--border));">
<div class="max-w-4xl mx-auto px-4 py-6 cyberpunk-mono text-xs uppercase tracking-widest">
@templ.Raw(data.Slots["header"])
</div>
</header>
<main class="flex-grow w-full max-w-4xl mx-auto px-4 py-12 grid gap-10 lg:grid-cols-[1fr_240px]">
<article class="cyberpunk-prose prose prose-invert max-w-none">
@templ.Raw(data.Slots["main"])
</article>
<aside class="cyberpunk-aside cyberpunk-mono text-sm" style="color: hsl(var(--muted-foreground));">
@templ.Raw(data.Slots["aside"])
</aside>
</main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// CyberpunkFullWidth renders the edge-to-edge template (no max-width clamping on main).
templ CyberpunkFullWidth(data PageData) {
<!DOCTYPE html>
<html lang="en" class="dark">
@bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
})
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
@bn.AdminBypassBanner(data.SiteSettings)
@scanlineOverlay()
<header class="cyberpunk-chrome w-full sticky top-0 z-40" style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["header"])
</header>
<main class="flex-grow w-full">
if main, ok := data.Slots["main"]; ok && main != "" {
@templ.Raw(main)
} else {
<div class="py-20 text-center cyberpunk-mono" style="color: hsl(var(--muted-foreground));">
<p>No content blocks assigned to this page.</p>
</div>
}
</main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">
@templ.Raw(data.Slots["footer"])
</footer>
@bn.BodyEnd(data.SiteSettings)
</body>
</html>
}
// RenderCyberpunk renders the default Cyberpunk page template.
func RenderCyberpunk(ctx context.Context, doc map[string]any) templ.Component {
return Cyberpunk(parseCyberpunkPageData(doc))
}
// RenderCyberpunkLanding renders the Cyberpunk landing page template.
func RenderCyberpunkLanding(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkLanding(parseCyberpunkPageData(doc))
}
// RenderCyberpunkArticle renders the Cyberpunk article page template.
func RenderCyberpunkArticle(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkArticle(parseCyberpunkPageData(doc))
}
// RenderCyberpunkFullWidth renders the Cyberpunk full-width page template.
func RenderCyberpunkFullWidth(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkFullWidth(parseCyberpunkPageData(doc))
}

View File

@ -1,520 +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 carries the rendered slots and assorted page chrome data passed
// from the CMS into a Cyberpunk page template.
type PageData struct {
Title string
Slots map[string]string
ThemeMode string
ThemeCSS string
SiteSettings bn.SiteSettingsData
PageMeta bn.PageMeta
StructuredData string
CSSHash string
PageviewNonce string
EngagementConfig bn.EngagementConfig
}
// parseCyberpunkPageData converts the loose doc map the renderer is handed into a typed PageData.
func parseCyberpunkPageData(doc map[string]any) PageData {
title := "Untitled"
if t, ok := doc["title"].(string); ok && t != "" {
title = t
}
slots := map[string]string{}
if s, ok := doc["slots"].(map[string]string); ok {
slots = s
}
themeCSS, _ := doc["theme_css"].(string)
structuredData, _ := doc["structured_data"].(string)
cssHash, _ := doc["css_hash"].(string)
pageviewNonce, _ := doc["pageview_nonce"].(string)
themeMode := "dark"
if tm, ok := doc["theme_mode"].(string); ok && tm != "" {
themeMode = tm
}
return PageData{
Title: title,
Slots: slots,
ThemeMode: themeMode,
ThemeCSS: themeCSS,
SiteSettings: bn.ParseSiteSettings(doc),
PageMeta: bn.ParsePageMeta(doc),
StructuredData: structuredData,
CSSHash: cssHash,
PageviewNonce: pageviewNonce,
EngagementConfig: bn.ParseEngagementConfig(doc),
}
}
// scanlineOverlay renders the global scanline overlay element (fixed, pointer-events: none).
func scanlineOverlay() 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 aria-hidden=\"true\" class=\"scanlines pointer-events-none fixed inset-0 z-50\" data-cyberpunk-scanlines></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Cyberpunk renders the default page template.
func Cyberpunk(data PageData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<!doctype html><html lang=\"en\" class=\"dark\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<body class=\"cyberpunk-body min-h-screen flex flex-col antialiased\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = scanlineOverlay().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<header class=\"cyberpunk-chrome w-full sticky top-0 z-40\" style=\"background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));\">")
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, 5, "</header><main class=\"flex-grow w-full max-w-6xl mx-auto px-4 py-12\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if main, ok := data.Slots["main"]; ok && main != "" {
templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"py-20 text-center cyberpunk-empty\" style=\"color: hsl(var(--muted-foreground));\"><p class=\"cyberpunk-mono\">No content blocks assigned to this page.</p></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</main><footer class=\"w-full mt-auto\" style=\"border-top: 1px solid hsl(var(--border));\">")
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, 8, "</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, 9, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// CyberpunkLanding renders the marketing landing template with hero/features/cta/footer slots.
func CyberpunkLanding(data PageData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<!doctype html><html lang=\"en\" class=\"dark\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<body class=\"cyberpunk-body min-h-screen flex flex-col antialiased\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = scanlineOverlay().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<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, 13, "</section><section class=\"w-full max-w-6xl mx-auto px-4 py-16\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(data.Slots["features"]).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</section><section class=\"w-full\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(data.Slots["cta"]).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</section><footer class=\"w-full mt-auto\" style=\"border-top: 1px solid hsl(var(--border));\">")
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, 16, "</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, 17, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// CyberpunkArticle renders the article template with mono-metadata header and a code-friendly aside.
func CyberpunkArticle(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, 18, "<!doctype html><html lang=\"en\" class=\"dark\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<body class=\"cyberpunk-body min-h-screen flex flex-col antialiased\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = scanlineOverlay().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<header class=\"w-full\" style=\"border-bottom: 1px solid hsl(var(--border));\"><div class=\"max-w-4xl mx-auto px-4 py-6 cyberpunk-mono text-xs uppercase tracking-widest\">")
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, 21, "</div></header><main class=\"flex-grow w-full max-w-4xl mx-auto px-4 py-12 grid gap-10 lg:grid-cols-[1fr_240px]\"><article class=\"cyberpunk-prose prose prose-invert max-w-none\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(data.Slots["main"]).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</article><aside class=\"cyberpunk-aside cyberpunk-mono text-sm\" style=\"color: hsl(var(--muted-foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(data.Slots["aside"]).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</aside></main><footer class=\"w-full mt-auto\" style=\"border-top: 1px solid hsl(var(--border));\">")
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, 24, "</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, 25, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// CyberpunkFullWidth renders the edge-to-edge template (no max-width clamping on main).
func CyberpunkFullWidth(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_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<!doctype html><html lang=\"en\" class=\"dark\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.Head(bn.HeadData{
Title: data.Title,
Settings: data.SiteSettings,
PageMeta: data.PageMeta,
ThemeMode: data.ThemeMode,
ThemeCSS: data.ThemeCSS,
PluginStyles: []string{"/templates/cyberpunk/css/cyberpunk.css"},
StructuredData: data.StructuredData,
CSSHash: data.CSSHash,
PageviewNonce: data.PageviewNonce,
EngagementConfig: data.EngagementConfig,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<body class=\"cyberpunk-body min-h-screen flex flex-col antialiased\" style=\"background-color: hsl(var(--background)); color: hsl(var(--foreground));\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = bn.AdminBypassBanner(data.SiteSettings).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = scanlineOverlay().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<header class=\"cyberpunk-chrome w-full sticky top-0 z-40\" style=\"background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));\">")
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, 29, "</header><main class=\"flex-grow w-full\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if main, ok := data.Slots["main"]; ok && main != "" {
templ_7745c5c3_Err = templ.Raw(main).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<div class=\"py-20 text-center cyberpunk-mono\" style=\"color: hsl(var(--muted-foreground));\"><p>No content blocks assigned to this page.</p></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</main><footer class=\"w-full mt-auto\" style=\"border-top: 1px solid hsl(var(--border));\">")
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, 32, "</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, 33, "</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// RenderCyberpunk renders the default Cyberpunk page template.
func RenderCyberpunk(ctx context.Context, doc map[string]any) templ.Component {
return Cyberpunk(parseCyberpunkPageData(doc))
}
// RenderCyberpunkLanding renders the Cyberpunk landing page template.
func RenderCyberpunkLanding(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkLanding(parseCyberpunkPageData(doc))
}
// RenderCyberpunkArticle renders the Cyberpunk article page template.
func RenderCyberpunkArticle(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkArticle(parseCyberpunkPageData(doc))
}
// RenderCyberpunkFullWidth renders the Cyberpunk full-width page template.
func RenderCyberpunkFullWidth(ctx context.Context, doc map[string]any) templ.Component {
return CyberpunkFullWidth(parseCyberpunkPageData(doc))
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en" class="dark">
{{ head_html|safe }}
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<div aria-hidden="true" class="scanlines pointer-events-none fixed inset-0 z-50" data-cyberpunk-scanlines></div>
<header class="w-full" style="border-bottom: 1px solid hsl(var(--border));"><div class="max-w-4xl mx-auto px-4 py-6 cyberpunk-mono text-xs uppercase tracking-widest">{{ slots.header|safe }}</div></header>
<main class="flex-grow w-full max-w-4xl mx-auto px-4 py-12 grid gap-10 lg:grid-cols-[1fr_240px]"><article class="cyberpunk-prose prose prose-invert max-w-none">{{ slots.main|safe }}</article><aside class="cyberpunk-aside cyberpunk-mono text-sm" style="color: hsl(var(--muted-foreground));">{{ slots.aside|safe }}</aside></main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en" class="dark">
{{ head_html|safe }}
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<div aria-hidden="true" class="scanlines pointer-events-none fixed inset-0 z-50" data-cyberpunk-scanlines></div>
<header class="cyberpunk-chrome w-full sticky top-0 z-40" style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));">{{ slots.header|safe }}</header>
<main class="flex-grow w-full max-w-6xl mx-auto px-4 py-12">{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center cyberpunk-empty" style="color: hsl(var(--muted-foreground));"><p class="cyberpunk-mono">No content blocks assigned to this page.</p></div>{% endif %}</main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en" class="dark">
{{ head_html|safe }}
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<div aria-hidden="true" class="scanlines pointer-events-none fixed inset-0 z-50" data-cyberpunk-scanlines></div>
<header class="cyberpunk-chrome w-full sticky top-0 z-40" style="background-color: hsl(var(--background) / 0.85); border-bottom: 1px solid hsl(var(--border));">{{ slots.header|safe }}</header>
<main class="flex-grow w-full">{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center cyberpunk-mono" style="color: hsl(var(--muted-foreground));"><p>No content blocks assigned to this page.</p></div>{% endif %}</main>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en" class="dark">
{{ head_html|safe }}
<body class="cyberpunk-body min-h-screen flex flex-col antialiased" style="background-color: hsl(var(--background)); color: hsl(var(--foreground));">
{{ admin_banner_html|safe }}
<div aria-hidden="true" class="scanlines pointer-events-none fixed inset-0 z-50" data-cyberpunk-scanlines></div>
<section class="w-full">{{ slots.hero|safe }}</section>
<section class="w-full max-w-6xl mx-auto px-4 py-16">{{ slots.features|safe }}</section>
<section class="w-full">{{ slots.cta|safe }}</section>
<footer class="w-full mt-auto" style="border-top: 1px solid hsl(var(--border));">{{ slots.footer|safe }}</footer>
{{ body_end_html|safe }}
</body>
</html>

View File

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{ site_name }}</title>
<style type="text/css">
body { background:#0a0a12; margin:0; padding:0; color: hsl(260 25% 92%); }
table, td { mso-table-lspace:0pt; mso-table-rspace:0pt; }
a { color: inherit; }
.cyberpunk-preheader { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.cyberpunk-divider { border-top:1px solid hsl(320 100% 60%); }
@media only screen and (max-width: 620px) {
.email-container { width:100% !important; max-width:100% !important; }
.content-padding { padding-left:24px !important; padding-right:24px !important; }
}
</style>
</head>
<body bgcolor="#0a0a12" style="margin:0;padding:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;">
{% if preview_text %}<div class="cyberpunk-preheader" style="display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;">$ from: {{ site_name }} — {{ preview_text }}</div>{% else %}<div class="cyberpunk-preheader" style="display:none;max-height:0;overflow:hidden;mso-hide:all;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;">$ from: {{ site_name }}</div>{% endif %}
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#0a0a12">
<tr>
<td align="center" style="padding:48px 12px;">
<table role="presentation" class="email-container" width="600" cellpadding="0" cellspacing="0" border="0" bgcolor="#101020" style="max-width:600px;border:1px solid hsl(258 28% 20%);">
<tr>
<td class="content-padding" align="center" style="padding:32px 40px;border-bottom:1px solid hsl(320 100% 60%);">
<div class="cyberpunk-preheader" style="font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.2em;text-transform:uppercase;">$ from: {{ site_name }}</div>
{% if logo_url %}<img src="{{ logo_url }}" alt="{{ site_name }}" style="margin-top:12px;max-height:48px;width:auto;display:inline-block;">{% endif %}
</td>
</tr>
<tr>
<td class="content-padding" style="padding:40px 48px;font-size:16px;line-height:1.7;">{{ body|safe }}</td>
</tr>
<tr>
<td class="cyberpunk-divider" height="1" style="border-top:1px solid hsl(320 100% 60%);font-size:0;line-height:0;">&nbsp;</td>
</tr>
<tr>
<td class="content-padding" align="center" style="padding:24px 48px 40px;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size:12px;letter-spacing:0.15em;text-transform:uppercase;">
{% if site_url %}<p style="margin:0 0 12px;"><a href="{{ site_url }}" style="text-decoration:none;">{{ site_url }}</a></p>{% endif %}
{% if unsubscribe_url %}<p style="margin:0;"><a href="{{ unsubscribe_url }}" style="text-decoration:none;">[esc] unsubscribe</a></p>{% else %}<p style="margin:0;">[esc] unsubscribe</p>{% endif %}
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1 @@
{% if variant == "secondary" %}<a href="{{ href|default:'#' }}" class="cyberpunk-btn cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider" style="background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground));"><span>{{ label|default:'Button' }}</span> <span aria-hidden="true" class="caret-blink">_</span></a>{% elif variant == "ghost" %}<a href="{{ href|default:'#' }}" class="cyberpunk-btn-ghost cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider" style="border: 1px solid hsl(var(--accent)); color: hsl(var(--accent));"><span>{{ label|default:'Button' }}</span> <span aria-hidden="true" class="caret-blink">_</span></a>{% else %}<a href="{{ href|default:'#' }}" class="cyberpunk-btn rgb-split cyberpunk-mono inline-flex items-center gap-2 px-5 py-2.5 rounded-md font-semibold uppercase tracking-wider" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));"><span>{{ label|default:'Button' }}</span> <span aria-hidden="true" class="caret-blink">_</span></a>{% endif %}

View File

@ -0,0 +1 @@
{% if href %}<a href="{{ href|default:'#' }}" class="cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full transition-transform hover:-translate-y-0.5" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));">{% if media %}<img src="{{ media }}" alt="" class="cyberpunk-card-media w-full h-40 object-cover rounded mb-4" onerror="this.style.display='none'">{% endif %}{% if title %}<h3 class="cyberpunk-card-title text-lg font-semibold mb-2" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ title }}</h3>{% endif %}{% if body %}<div class="cyberpunk-card-body text-sm leading-relaxed" style="color: hsl(var(--muted-foreground));">{{ body|safe }}</div>{% endif %}</a>{% else %}<article class="cyberpunk-card neon-edge-magenta block p-6 rounded-lg h-full" style="background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px dashed hsl(var(--primary));">{% if media %}<img src="{{ media }}" alt="" class="cyberpunk-card-media w-full h-40 object-cover rounded mb-4" onerror="this.style.display='none'">{% endif %}{% if title %}<h3 class="cyberpunk-card-title text-lg font-semibold mb-2" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ title }}</h3>{% endif %}{% if body %}<div class="cyberpunk-card-body text-sm leading-relaxed" style="color: hsl(var(--muted-foreground));">{{ body|safe }}</div>{% endif %}</article>{% endif %}

View File

@ -0,0 +1 @@
{% if level|integer == 1 %}<h1 class="cyberpunk-display glitch text-4xl md:text-5xl font-bold tracking-tight {{ textClass }}" data-text="{{ text }}" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ text }}</h1>{% elif level|integer == 2 %}<h2 class="cyberpunk-display glitch text-3xl md:text-4xl font-semibold tracking-tight {{ textClass }}" data-text="{{ text }}" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ text }}</h2>{% elif level|integer == 3 %}<h3 class="cyberpunk-display text-2xl font-semibold {{ textClass }}" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ text }}</h3>{% elif level|integer == 4 %}<h4 class="cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest text-xl font-semibold {{ textClass }}" style="color: hsl(var(--accent));">{{ text }}</h4>{% elif level|integer == 5 %}<h5 class="cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest text-lg font-medium {{ textClass }}" style="color: hsl(var(--accent));">{{ text }}</h5>{% elif level|integer == 6 %}<h6 class="cyberpunk-eyebrow cyberpunk-mono uppercase tracking-widest text-base font-medium {{ textClass }}" style="color: hsl(var(--accent));">{{ text }}</h6>{% else %}<h2 class="cyberpunk-display glitch text-3xl md:text-4xl font-semibold tracking-tight {{ textClass }}" data-text="{{ text }}" style="color: hsl(var(--foreground)); font-family: var(--font-heading, 'Space Grotesk', system-ui, sans-serif);">{{ text }}</h2>{% endif %}

View File

@ -0,0 +1 @@
<div class="cyberpunk-prose prose prose-invert max-w-none leading-relaxed {{ class }}" style="color: hsl(var(--foreground)); font-family: var(--font-body, 'Inter', system-ui, sans-serif);">{{ text|safe }}</div>

View File

@ -1,16 +0,0 @@
package main
import (
"bytes"
"context"
)
// CyberpunkTextBlock renders the built-in text block with cyberpunk styling:
// scanline-friendly leading and accent-coloured <code> inline spans.
func CyberpunkTextBlock(ctx context.Context, content map[string]any) string {
text := getString(content, "text")
class := getString(content, "class")
var buf bytes.Buffer
_ = cyberpunkTextComponent(text, class).Render(ctx, &buf)
return buf.String()
}

View File

@ -1,12 +0,0 @@
package main
// cyberpunkTextComponent renders the override for the built-in text block:
// shadcn `prose` invert with cyberpunk leading and accent inline code.
templ cyberpunkTextComponent(text, class string) {
<div
class={ "cyberpunk-prose prose prose-invert max-w-none leading-relaxed", class }
style="color: hsl(var(--foreground)); font-family: var(--font-body, 'Inter', system-ui, sans-serif);"
>
@templ.Raw(text)
</div>
}

View File

@ -1,68 +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"
// cyberpunkTextComponent renders the override for the built-in text block:
// shadcn `prose` invert with cyberpunk leading and accent inline code.
func cyberpunkTextComponent(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{"cyberpunk-prose prose prose-invert max-w-none leading-relaxed", 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=\"color: hsl(var(--foreground)); font-family: var(--font-body, 'Inter', system-ui, sans-serif);\">")
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