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, }, }, }, } }