mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
130 lines
2.8 KiB
Go
130 lines
2.8 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package badge
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"unicode"
|
|
|
|
actions_model "github.com/hanzoai/git/models/actions"
|
|
)
|
|
|
|
// The Badge layout: |offset|label|message|
|
|
// We use 10x scale to calculate more precisely
|
|
// Then scale down to normal size in tmpl file
|
|
|
|
type Text struct {
|
|
text string
|
|
width int
|
|
x int
|
|
}
|
|
|
|
func (t Text) Text() string {
|
|
return t.text
|
|
}
|
|
|
|
func (t Text) Width() int {
|
|
return t.width
|
|
}
|
|
|
|
func (t Text) X() int {
|
|
return t.x
|
|
}
|
|
|
|
func (t Text) TextLength() int {
|
|
return int(float64(t.width-defaultOffset) * 10)
|
|
}
|
|
|
|
type Badge struct {
|
|
IDPrefix string
|
|
FontFamily string
|
|
Color string
|
|
FontSize int
|
|
Label Text
|
|
Message Text
|
|
}
|
|
|
|
func (b Badge) Width() int {
|
|
return b.Label.width + b.Message.width
|
|
}
|
|
|
|
// Style follows https://shields.io/badges
|
|
const (
|
|
StyleFlat = "flat"
|
|
StyleFlatSquare = "flat-square"
|
|
)
|
|
|
|
const (
|
|
defaultOffset = 10
|
|
defaultFontSize = 11
|
|
DefaultColor = "#9f9f9f" // Grey
|
|
DefaultFontFamily = "DejaVu Sans,Verdana,Geneva,sans-serif"
|
|
DefaultStyle = StyleFlat
|
|
)
|
|
|
|
var GlobalVars = sync.OnceValue(func() (ret struct {
|
|
StatusColorMap map[actions_model.Status]string
|
|
DejaVuGlyphWidthData map[rune]uint8
|
|
AllStyles []string
|
|
},
|
|
) {
|
|
ret.StatusColorMap = map[actions_model.Status]string{
|
|
actions_model.StatusSuccess: "#4c1", // Green
|
|
actions_model.StatusSkipped: "#dfb317", // Yellow
|
|
actions_model.StatusUnknown: "#97ca00", // Light Green
|
|
actions_model.StatusFailure: "#e05d44", // Red
|
|
actions_model.StatusCancelled: "#fe7d37", // Orange
|
|
actions_model.StatusWaiting: "#dfb317", // Yellow
|
|
actions_model.StatusRunning: "#dfb317", // Yellow
|
|
actions_model.StatusBlocked: "#dfb317", // Yellow
|
|
}
|
|
ret.DejaVuGlyphWidthData = dejaVuGlyphWidthDataFunc()
|
|
ret.AllStyles = []string{StyleFlat, StyleFlatSquare}
|
|
return ret
|
|
})
|
|
|
|
// GenerateBadge generates badge with given template
|
|
func GenerateBadge(label, message, color string) Badge {
|
|
lw := calculateTextWidth(label) + defaultOffset
|
|
mw := calculateTextWidth(message) + defaultOffset
|
|
|
|
lx := lw * 5
|
|
mx := lw*10 + mw*5 - 10
|
|
return Badge{
|
|
FontFamily: DefaultFontFamily,
|
|
Label: Text{
|
|
text: label,
|
|
width: lw,
|
|
x: lx,
|
|
},
|
|
Message: Text{
|
|
text: message,
|
|
width: mw,
|
|
x: mx,
|
|
},
|
|
FontSize: defaultFontSize * 10,
|
|
Color: color,
|
|
}
|
|
}
|
|
|
|
func calculateTextWidth(text string) int {
|
|
width := 0
|
|
widthData := GlobalVars().DejaVuGlyphWidthData
|
|
for _, char := range strings.TrimSpace(text) {
|
|
charWidth, ok := widthData[char]
|
|
if !ok {
|
|
// use the width of 'm' in case of missing glyph width data for a printable character
|
|
if unicode.IsPrint(char) {
|
|
charWidth = widthData['m']
|
|
} else {
|
|
charWidth = 0
|
|
}
|
|
}
|
|
width += int(charWidth)
|
|
}
|
|
|
|
return width
|
|
}
|