Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/pastel-dream. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
188 lines
5.7 KiB
Go
188 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/a-h/templ"
|
|
|
|
"git.dev.alexdunmow.com/block/core/blocks"
|
|
"git.dev.alexdunmow.com/block/core/plugin"
|
|
"git.dev.alexdunmow.com/block/core/templates"
|
|
)
|
|
|
|
// wrap adapts a templ-returning render function to templates.TemplateFunc.
|
|
// templ.Component already implements templates.HTMLComponent via Render.
|
|
func wrap(f func(ctx context.Context, doc map[string]any) templ.Component) templates.TemplateFunc {
|
|
return func(ctx context.Context, doc map[string]any) templates.HTMLComponent {
|
|
return f(ctx, doc)
|
|
}
|
|
}
|
|
|
|
// Register is the plugin entry point. It registers the system template, page
|
|
// templates, theme-owned blocks, built-in overrides, and the email wrapper.
|
|
//
|
|
// Order of operations matters: br.LoadSchemasFromFS MUST run before any
|
|
// br.Register call so schema binding sees the blocks as they register.
|
|
func Register(tr templates.TemplateRegistry, br blocks.BlockRegistry) error {
|
|
// System template registration.
|
|
tr.RegisterSystemTemplate(templates.SystemTemplateMeta{
|
|
Key: "pastel-dream",
|
|
Title: "Pastel Dream",
|
|
Description: "Soft watercolor theme with blush, mint, and butter palettes for wellness, parenting, and spa brands.",
|
|
})
|
|
|
|
// Page templates per spec §"Page templates".
|
|
if err := tr.RegisterPageTemplate("pastel-dream", templates.PageTemplateMeta{
|
|
Key: "default",
|
|
Title: "Default",
|
|
Description: "Soft layered hero, masthead nav, footer with newsletter.",
|
|
Slots: []string{"header", "main", "footer"},
|
|
}, wrap(RenderPastelDefault)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("pastel-dream", templates.PageTemplateMeta{
|
|
Key: "landing",
|
|
Title: "Soft Landing",
|
|
Description: "Watercolor hero, affirmation strip, CTA, footer.",
|
|
Slots: []string{"hero", "main", "cta", "footer"},
|
|
}, wrap(RenderPastelLanding)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("pastel-dream", templates.PageTemplateMeta{
|
|
Key: "article",
|
|
Title: "Reading Room",
|
|
Description: "Narrow, centered editorial column with side rail.",
|
|
Slots: []string{"header", "main", "footer"},
|
|
}, wrap(RenderPastelArticle)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tr.RegisterPageTemplate("pastel-dream", templates.PageTemplateMeta{
|
|
Key: "full-width",
|
|
Title: "Open Air",
|
|
Description: "Edge-to-edge sections for galleries and seasonal looks.",
|
|
Slots: []string{"header", "main", "footer"},
|
|
}, wrap(RenderPastelFullWidth)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Schemas MUST load before blocks register so editor metadata binds.
|
|
if err := br.LoadSchemasFromFS(Schemas()); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Theme-owned blocks.
|
|
br.Register(SoftNavbarMeta, SoftNavbarBlock)
|
|
br.Register(WatercolorHeroMeta, WatercolorHeroBlock)
|
|
br.Register(AffirmationMeta, AffirmationBlock)
|
|
br.Register(TestimonialSoftMeta, TestimonialSoftBlock)
|
|
br.Register(FeatureGridSoftMeta, FeatureGridSoftBlock)
|
|
br.Register(CozyFooterMeta, CozyFooterBlock)
|
|
|
|
// Overrides for built-ins, only when this theme is active.
|
|
br.RegisterTemplateOverride("pastel-dream", "heading", PastelHeadingBlock)
|
|
br.RegisterTemplateOverride("pastel-dream", "text", PastelTextBlock)
|
|
br.RegisterTemplateOverride("pastel-dream", "button", PastelButtonBlock)
|
|
br.RegisterTemplateOverride("pastel-dream", "card", PastelCardBlock)
|
|
|
|
// Email wrapper.
|
|
tr.RegisterEmailWrapper("pastel-dream", PastelEmailWrapper)
|
|
|
|
return nil
|
|
}
|
|
|
|
// DefaultMasterPages returns the master pages seeded on first plugin load.
|
|
// Two definitions per spec §"Master pages":
|
|
// - pastel-dream:default-master — used by default and article page templates
|
|
// - pastel-dream:landing-master — used by the landing page template
|
|
func DefaultMasterPages() []plugin.MasterPageDefinition {
|
|
return []plugin.MasterPageDefinition{
|
|
{
|
|
Key: "pastel-dream:default-master",
|
|
Title: "Pastel Dream Default Master",
|
|
PageTemplates: []string{"default", "article"},
|
|
Blocks: []plugin.MasterPageBlock{
|
|
{
|
|
BlockKey: "pastel-dream:soft-navbar",
|
|
Title: "Soft Nav",
|
|
Content: map[string]any{
|
|
"menuName": "main",
|
|
"logo": "Pastel Dream",
|
|
},
|
|
Slot: "header",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "slot",
|
|
Title: "Main Slot",
|
|
Content: map[string]any{
|
|
"slotName": "main",
|
|
"placeholder": "Page content",
|
|
},
|
|
Slot: "main",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "pastel-dream:cozy-footer",
|
|
Title: "Cozy Footer",
|
|
Content: map[string]any{
|
|
"showSignup": "yes",
|
|
"affirmation": "Be gentle with yourself today.",
|
|
},
|
|
Slot: "footer",
|
|
SortOrder: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Key: "pastel-dream:landing-master",
|
|
Title: "Pastel Dream Landing Master",
|
|
PageTemplates: []string{"landing"},
|
|
Blocks: []plugin.MasterPageBlock{
|
|
{
|
|
BlockKey: "pastel-dream:watercolor-hero",
|
|
Title: "Watercolor Hero",
|
|
Content: map[string]any{
|
|
"eyebrow": "new",
|
|
"headline": "Soft starts",
|
|
"body": "A gentle place to begin.",
|
|
"ctaText": "Begin",
|
|
},
|
|
Slot: "hero",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "slot",
|
|
Title: "Main Slot",
|
|
Content: map[string]any{
|
|
"slotName": "main",
|
|
},
|
|
Slot: "main",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "pastel-dream:affirmation",
|
|
Title: "Affirmation Strip",
|
|
Content: map[string]any{
|
|
"quote": "You are doing enough.",
|
|
"author": "Pastel Dream",
|
|
},
|
|
Slot: "cta",
|
|
SortOrder: 0,
|
|
},
|
|
{
|
|
BlockKey: "pastel-dream:cozy-footer",
|
|
Title: "Cozy Footer",
|
|
Content: map[string]any{
|
|
"showSignup": "yes",
|
|
},
|
|
Slot: "footer",
|
|
SortOrder: 0,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|