Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/cyberpunk. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package main
|
|
|
|
import "strconv"
|
|
|
|
// getString extracts a string value from a content map. Returns "" on miss/wrong-type.
|
|
func getString(content map[string]any, key string) string {
|
|
if v, ok := content[key].(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// getStringWithDefault is like getString but returns dflt if the key is missing or non-string.
|
|
func getStringWithDefault(content map[string]any, key, dflt string) string {
|
|
if v, ok := content[key].(string); ok && v != "" {
|
|
return v
|
|
}
|
|
return dflt
|
|
}
|
|
|
|
// getBool extracts a boolean value from a content map. Accepts bool, "true"/"false",
|
|
// "on"/"off", "yes"/"no", and numerics. Returns dflt when missing or unparsable.
|
|
func getBool(content map[string]any, key string, dflt bool) bool {
|
|
switch v := content[key].(type) {
|
|
case bool:
|
|
return v
|
|
case string:
|
|
switch v {
|
|
case "true", "on", "yes", "1":
|
|
return true
|
|
case "false", "off", "no", "0", "":
|
|
return false
|
|
}
|
|
case float64:
|
|
return v != 0
|
|
case int:
|
|
return v != 0
|
|
}
|
|
return dflt
|
|
}
|
|
|
|
// getSlice extracts a slice of object-shaped entries from a content map.
|
|
func getSlice(content map[string]any, key string) []map[string]any {
|
|
v, ok := content[key].([]any)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
out := make([]map[string]any, 0, len(v))
|
|
for _, item := range v {
|
|
if m, ok := item.(map[string]any); ok {
|
|
out = append(out, m)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// getLink reads a {label, href} link object. Tolerates string values
|
|
// (interpreted as href, label = href) and missing keys.
|
|
func getLink(content map[string]any, key string) Link {
|
|
v := content[key]
|
|
switch x := v.(type) {
|
|
case map[string]any:
|
|
return Link{Label: getString(x, "label"), Href: getString(x, "href")}
|
|
case string:
|
|
return Link{Label: x, Href: x}
|
|
}
|
|
return Link{}
|
|
}
|
|
|
|
// Link is a {label, href} pair used by hero / nav / footer blocks.
|
|
type Link struct {
|
|
Label string
|
|
Href string
|
|
}
|
|
|
|
// safeHref returns "#" when href is empty so templ.SafeURL never receives "".
|
|
func safeHref(href string) string {
|
|
if href == "" {
|
|
return "#"
|
|
}
|
|
return href
|
|
}
|
|
|
|
// parseHeadingLevel parses a 1..6 heading level. Defaults to 2 for safety.
|
|
func parseHeadingLevel(content map[string]any) int {
|
|
switch v := content["level"].(type) {
|
|
case float64:
|
|
l := int(v)
|
|
if l >= 1 && l <= 6 {
|
|
return l
|
|
}
|
|
case int:
|
|
if v >= 1 && v <= 6 {
|
|
return v
|
|
}
|
|
case string:
|
|
if l, err := strconv.Atoi(v); err == nil && l >= 1 && l <= 6 {
|
|
return l
|
|
}
|
|
}
|
|
return 2
|
|
}
|