Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package campaigns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TemplateKey is a seasonal or custom campaign template identifier.
|
||||
type TemplateKey string
|
||||
|
||||
const (
|
||||
TemplateChristmas TemplateKey = "christmas"
|
||||
TemplateBlackFriday TemplateKey = "black_friday"
|
||||
TemplateSpring TemplateKey = "spring"
|
||||
TemplateCustom TemplateKey = "custom"
|
||||
)
|
||||
|
||||
type Template struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Season string `json:"season"`
|
||||
DefaultSubject string `json:"default_subject"`
|
||||
DefaultPrompt string `json:"default_prompt"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
var builtInTemplates = []Template{
|
||||
{
|
||||
Key: string(TemplateChristmas),
|
||||
Name: "Christmas",
|
||||
Season: "christmas",
|
||||
DefaultSubject: "Holiday picks from {{brand}}",
|
||||
DefaultPrompt: "Warm Christmas email for these products. Festive, concise, clear CTA. JSON only.",
|
||||
Description: "Festive seasonal campaign for holiday shoppers.",
|
||||
},
|
||||
{
|
||||
Key: string(TemplateBlackFriday),
|
||||
Name: "Black Friday",
|
||||
Season: "black_friday",
|
||||
DefaultSubject: "Black Friday deals from {{brand}}",
|
||||
DefaultPrompt: "Urgent Black Friday email for these products. Limited-time value, no false claims, strong CTA. JSON only.",
|
||||
Description: "Deal-focused Black Friday / Cyber Week campaign.",
|
||||
},
|
||||
{
|
||||
Key: string(TemplateSpring),
|
||||
Name: "Spring",
|
||||
Season: "spring",
|
||||
DefaultSubject: "Fresh for spring — {{brand}}",
|
||||
DefaultPrompt: "Light spring email for these products. Renewal + practical benefits, clear CTA. JSON only.",
|
||||
Description: "Seasonal spring refresh campaign.",
|
||||
},
|
||||
{
|
||||
Key: string(TemplateCustom),
|
||||
Name: "Custom",
|
||||
Season: "custom",
|
||||
DefaultSubject: "News from {{brand}}",
|
||||
DefaultPrompt: "Clear marketing email for these products. Short subject, scannable body, CTA. JSON only.",
|
||||
Description: "Blank slate with sensible defaults.",
|
||||
},
|
||||
}
|
||||
|
||||
func ListTemplates() []Template {
|
||||
out := make([]Template, len(builtInTemplates))
|
||||
copy(out, builtInTemplates)
|
||||
return out
|
||||
}
|
||||
|
||||
func GetTemplate(key string) (Template, error) {
|
||||
key = strings.TrimSpace(strings.ToLower(key))
|
||||
if key == "" {
|
||||
key = string(TemplateCustom)
|
||||
}
|
||||
for _, t := range builtInTemplates {
|
||||
if t.Key == key {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return Template{}, ErrInvalidTemplate
|
||||
}
|
||||
|
||||
func ValidTemplateKey(key string) bool {
|
||||
_, err := GetTemplate(key)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func renderSubject(tpl Template, brand string) string {
|
||||
if brand == "" {
|
||||
brand = "our store"
|
||||
}
|
||||
return strings.ReplaceAll(tpl.DefaultSubject, "{{brand}}", brand)
|
||||
}
|
||||
|
||||
func templateHTML(subject, intro, productBlock, ctaURL, logoURL string) string {
|
||||
if ctaURL == "" {
|
||||
ctaURL = "#"
|
||||
}
|
||||
logoBlock := ""
|
||||
if strings.TrimSpace(logoURL) != "" {
|
||||
logoBlock = fmt.Sprintf(
|
||||
`<p style="margin:0 0 16px"><img src="%s" alt="" width="120" style="max-width:160px;height:auto;border:0" /></p>`,
|
||||
escapeAttr(logoURL),
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(`<!DOCTYPE html><html><body style="font-family:Arial,sans-serif;color:#222;line-height:1.5">
|
||||
%s<h1 style="font-size:22px;margin:0 0 12px">%s</h1>
|
||||
<p>%s</p>
|
||||
%s
|
||||
<p style="margin:24px 0"><a href="%s" style="background:#2d1b4e;color:#fff;padding:10px 16px;text-decoration:none;border-radius:4px">Shop now</a></p>
|
||||
</body></html>`, logoBlock, escapeHTML(subject), escapeHTML(intro), productBlock, escapeAttr(ctaURL))
|
||||
}
|
||||
|
||||
func escapeHTML(s string) string {
|
||||
r := strings.NewReplacer("&", "&", "<", "<", ">", ">", `"`, """)
|
||||
return r.Replace(s)
|
||||
}
|
||||
|
||||
func escapeAttr(s string) string {
|
||||
return escapeHTML(s)
|
||||
}
|
||||
Reference in New Issue
Block a user