package templates import ( "bytes" "embed" "encoding/json" "html/template" "time" ) //go:embed *.html var templateFS embed.FS var funcMap = template.FuncMap{ "safeHTML": func(s string) template.HTML { return template.HTML(s) }, "json": func(v any) string { b, _ := json.Marshal(v); return string(b) }, "or": func(a, b any) any { if a != nil && a != "" { return a } return b }, } var fontURLs = map[string]string{ "system": "", "inter": "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap", "georgia": "", "merriweather": "https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap", "source-serif": "https://fonts.googleapis.com/css2?family=Source+Serif+4:wght@400;600;700&display=swap", "jetbrains-mono": "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap", } var fontFamilies = map[string]string{ "system": "system-ui, -apple-system, sans-serif", "inter": "'Inter', system-ui, sans-serif", "georgia": "Georgia, 'Times New Roman', serif", "merriweather": "'Merriweather', Georgia, serif", "source-serif": "'Source Serif 4', Georgia, serif", "jetbrains-mono": "'JetBrains Mono', 'Fira Code', monospace", } func GetFontURL(fontKey string) string { if url, ok := fontURLs[fontKey]; ok { return url } return "" } func GetFontFamily(fontKey string) string { if family, ok := fontFamilies[fontKey]; ok { return family } return fontFamilies["system"] } var homeTemplate, blogTemplate, postTemplate *template.Template func init() { homeTemplate = template.Must(template.New("").Funcs(funcMap).ParseFS(templateFS, "base.html", "home.html")) blogTemplate = template.Must(template.New("").Funcs(funcMap).ParseFS(templateFS, "base.html", "blog.html")) postTemplate = template.Must(template.New("").Funcs(funcMap).ParseFS(templateFS, "base.html", "post.html")) } type PageData struct { Title string Description string CanonicalURL string OGType string OGImage string NoIndex bool SiteName string Year int FontURL string FontFamily string StructuredData template.JS Settings map[string]any ShowBadge bool } type HomeData struct { PageData Posts []PostSummary HasMore bool } type BlogData struct { PageData Posts []PostSummary PrevPage string NextPage string } type PostData struct { PageData Post PostDetail ContentHTML template.HTML InteractionConfig map[string]any } type PostSummary struct { Slug string Title string Description string Date time.Time } type PostDetail struct { Slug string Title string Description string CoverImage string Date time.Time Tags []string } func RenderHome(data HomeData) ([]byte, error) { var buf bytes.Buffer if err := homeTemplate.ExecuteTemplate(&buf, "base.html", data); err != nil { return nil, err } return buf.Bytes(), nil } func RenderBlog(data BlogData) ([]byte, error) { var buf bytes.Buffer if err := blogTemplate.ExecuteTemplate(&buf, "base.html", data); err != nil { return nil, err } return buf.Bytes(), nil } func RenderPost(data PostData) ([]byte, error) { var buf bytes.Buffer if err := postTemplate.ExecuteTemplate(&buf, "base.html", data); err != nil { return nil, err } return buf.Bytes(), nil }