themes-earthen/impact_metrics.templ
Alex Dunmow 49401f1b41 initial: theme plugin earthen
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/earthen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:11:27 +08:00

83 lines
2.5 KiB
Plaintext

package main
// impactMetricsComponent renders a row of impact metrics with optional botanical illustration.
templ impactMetricsComponent(data ImpactMetricsData) {
<section
data-block="earthen:impact_metrics"
data-empty?={ data.Empty }
class="earthen-impact-metrics py-16 px-4"
style="background-color: hsl(var(--background)); color: hsl(var(--foreground));"
>
<div class="max-w-5xl mx-auto">
if data.Title != "" {
<h2
class="earthen-display text-3xl md:text-4xl text-center mb-12"
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--primary));" }
>
{ data.Title }
</h2>
}
if data.Illustration != "" {
<div class="flex justify-center mb-8">
<img src={ resolveMedia(data.Illustration) } alt="" class="max-h-40 object-contain"/>
</div>
} else if data.Title != "" || len(data.Metrics) > 0 {
<div class="flex justify-center mb-8">
@botanicalGlyph("fern", 64)
</div>
}
if len(data.Metrics) > 0 {
<div class={ "grid gap-8", metricGridCols(len(data.Metrics)) }>
for _, m := range data.Metrics {
<div class="text-center px-4">
<div
class="earthen-display text-5xl font-semibold mb-2"
style={ "font-family: var(--font-heading, \"Fraunces\", \"Playfair Display\", Georgia, serif); color: hsl(var(--accent));" }
>
{ m.Value }{ m.Suffix }
</div>
<div
class="earthen-body uppercase tracking-wider text-sm"
style={ "font-family: var(--font-body, \"Spectral\", Georgia, serif); color: hsl(var(--muted-foreground));" }
>
{ m.Label }
</div>
</div>
}
</div>
} else {
<p
class="text-center"
style="color: hsl(var(--muted-foreground));"
>
Add impact metrics to bring this section to life.
</p>
}
</div>
</section>
}
// metricGridCols returns the responsive grid class for metric count.
func metricGridCols(count int) string {
switch count {
case 1:
return "grid-cols-1"
case 2:
return "grid-cols-1 sm:grid-cols-2"
case 3:
return "grid-cols-1 sm:grid-cols-3"
default:
return "grid-cols-2 lg:grid-cols-4"
}
}
// resolveMedia rewrites a media reference to its served URL. The wave-1
// implementation passes the path through verbatim and is wired so admins
// can drop in their own media adapter later without touching templates.
func resolveMedia(path string) string {
if path == "" {
return ""
}
return path
}