package badge import ( "crypto/sha256" "encoding/hex" "fmt" "html" "strings" "unicode/utf8" ) type Options struct { Label string Message string Extent string Style string Theme string Link string LeftColor string RightColor string } var extentColors = map[string]string{ "none": "#2f855a", "assisted": "#2b6cb0", "partial": "#b7791f", "mostly": "#c05621", "full": "#c53030", } func Render(o Options) ([]byte, string) { label := truncate(strings.TrimSpace(o.Label), 40) if label == "" { label = "UCNG" } message := truncate(strings.TrimSpace(o.Message), 80) if message == "" { message = o.Extent } style := o.Style if style != "flat-square" { style = "flat" } leftWidth := textWidth(label) rightWidth := textWidth(message) total := leftWidth + rightWidth radius := 3 if style == "flat-square" { radius = 0 } leftColor, rightColor := "#555555", extentColors[o.Extent] if rightColor == "" { rightColor = "#4a5568" } if o.Theme == "mono" { leftColor, rightColor = "#262626", "#666666" } if isHexColor(o.LeftColor) { leftColor = o.LeftColor } if isHexColor(o.RightColor) { rightColor = o.RightColor } title := html.EscapeString(label + ": " + message) labelEsc := html.EscapeString(label) messageEsc := html.EscapeString(message) openLink, closeLink := "", "" if strings.HasPrefix(o.Link, "https://") || strings.HasPrefix(o.Link, "http://") { openLink = `` closeLink = `` } svg := fmt.Sprintf(`%s%s%s%s%s%s%s`, title, total, total, title, openLink, total, radius, leftWidth, leftColor, leftWidth, rightWidth, rightColor, total, leftWidth/2, labelEsc, leftWidth/2, labelEsc, leftWidth+rightWidth/2, messageEsc, leftWidth+rightWidth/2, messageEsc, closeLink) data := []byte(svg) hash := sha256.Sum256(data) return data, `"` + hex.EncodeToString(hash[:12]) + `"` } func textWidth(s string) int { runes := utf8.RuneCountInString(s) width := runes*7 + 12 if width < 40 { width = 40 } return width } func truncate(s string, max int) string { r := []rune(s) if len(r) <= max { return s } return string(r[:max-1]) + "…" } func isHexColor(s string) bool { if len(s) != 7 || s[0] != '#' { return false } for _, r := range s[1:] { if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) { return false } } return true }