first-commit
This commit is contained in:
129
modules/badge/badge.go
Normal file
129
modules/badge/badge.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package badge
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
actions_model "code.gitea.io/gitea/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
|
||||
}
|
206
modules/badge/badge_glyph_width.go
Normal file
206
modules/badge/badge_glyph_width.go
Normal file
@@ -0,0 +1,206 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package badge
|
||||
|
||||
// DejaVuGlyphWidthData is generated by `sfnt.Face.GlyphAdvance(nil, <rune>, 11, font.HintingNone)` with DejaVu Sans
|
||||
// v2.37 (https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_2_37/dejavu-sans-ttf-2.37.zip).
|
||||
//
|
||||
// Fonts defined in "DefaultFontFamily" all have similar widths (including "DejaVu Sans"),
|
||||
// and these widths are fixed and don't seem to change.
|
||||
//
|
||||
// A devtest page "/devtest/badge-actions-svg" could be used to check the rendered images.
|
||||
|
||||
func dejaVuGlyphWidthDataFunc() map[rune]uint8 {
|
||||
return map[rune]uint8{
|
||||
32: 3,
|
||||
33: 4,
|
||||
34: 5,
|
||||
35: 9,
|
||||
36: 7,
|
||||
37: 10,
|
||||
38: 9,
|
||||
39: 3,
|
||||
40: 4,
|
||||
41: 4,
|
||||
42: 6,
|
||||
43: 9,
|
||||
44: 3,
|
||||
45: 4,
|
||||
46: 3,
|
||||
47: 4,
|
||||
48: 7,
|
||||
49: 7,
|
||||
50: 7,
|
||||
51: 7,
|
||||
52: 7,
|
||||
53: 7,
|
||||
54: 7,
|
||||
55: 7,
|
||||
56: 7,
|
||||
57: 7,
|
||||
58: 4,
|
||||
59: 4,
|
||||
60: 9,
|
||||
61: 9,
|
||||
62: 9,
|
||||
63: 6,
|
||||
64: 11,
|
||||
65: 8,
|
||||
66: 8,
|
||||
67: 8,
|
||||
68: 8,
|
||||
69: 7,
|
||||
70: 6,
|
||||
71: 9,
|
||||
72: 8,
|
||||
73: 3,
|
||||
74: 3,
|
||||
75: 7,
|
||||
76: 6,
|
||||
77: 9,
|
||||
78: 8,
|
||||
79: 9,
|
||||
80: 7,
|
||||
81: 9,
|
||||
82: 8,
|
||||
83: 7,
|
||||
84: 7,
|
||||
85: 8,
|
||||
86: 8,
|
||||
87: 11,
|
||||
88: 8,
|
||||
89: 7,
|
||||
90: 8,
|
||||
91: 4,
|
||||
92: 4,
|
||||
93: 4,
|
||||
94: 9,
|
||||
95: 6,
|
||||
96: 6,
|
||||
97: 7,
|
||||
98: 7,
|
||||
99: 6,
|
||||
100: 7,
|
||||
101: 7,
|
||||
102: 4,
|
||||
103: 7,
|
||||
104: 7,
|
||||
105: 3,
|
||||
106: 3,
|
||||
107: 6,
|
||||
108: 3,
|
||||
109: 11,
|
||||
110: 7,
|
||||
111: 7,
|
||||
112: 7,
|
||||
113: 7,
|
||||
114: 5,
|
||||
115: 6,
|
||||
116: 4,
|
||||
117: 7,
|
||||
118: 7,
|
||||
119: 9,
|
||||
120: 7,
|
||||
121: 7,
|
||||
122: 6,
|
||||
123: 7,
|
||||
124: 4,
|
||||
125: 7,
|
||||
126: 9,
|
||||
161: 4,
|
||||
162: 7,
|
||||
163: 7,
|
||||
164: 7,
|
||||
165: 7,
|
||||
166: 4,
|
||||
167: 6,
|
||||
168: 6,
|
||||
169: 11,
|
||||
170: 5,
|
||||
171: 7,
|
||||
172: 9,
|
||||
174: 11,
|
||||
175: 6,
|
||||
176: 6,
|
||||
177: 9,
|
||||
178: 4,
|
||||
179: 4,
|
||||
180: 6,
|
||||
181: 7,
|
||||
182: 7,
|
||||
183: 3,
|
||||
184: 6,
|
||||
185: 4,
|
||||
186: 5,
|
||||
187: 7,
|
||||
188: 11,
|
||||
189: 11,
|
||||
190: 11,
|
||||
191: 6,
|
||||
192: 8,
|
||||
193: 8,
|
||||
194: 8,
|
||||
195: 8,
|
||||
196: 8,
|
||||
197: 8,
|
||||
198: 11,
|
||||
199: 8,
|
||||
200: 7,
|
||||
201: 7,
|
||||
202: 7,
|
||||
203: 7,
|
||||
204: 3,
|
||||
205: 3,
|
||||
206: 3,
|
||||
207: 3,
|
||||
208: 9,
|
||||
209: 8,
|
||||
210: 9,
|
||||
211: 9,
|
||||
212: 9,
|
||||
213: 9,
|
||||
214: 9,
|
||||
215: 9,
|
||||
216: 9,
|
||||
217: 8,
|
||||
218: 8,
|
||||
219: 8,
|
||||
220: 8,
|
||||
221: 7,
|
||||
222: 7,
|
||||
223: 7,
|
||||
224: 7,
|
||||
225: 7,
|
||||
226: 7,
|
||||
227: 7,
|
||||
228: 7,
|
||||
229: 7,
|
||||
230: 11,
|
||||
231: 6,
|
||||
232: 7,
|
||||
233: 7,
|
||||
234: 7,
|
||||
235: 7,
|
||||
236: 3,
|
||||
237: 3,
|
||||
238: 3,
|
||||
239: 3,
|
||||
240: 7,
|
||||
241: 7,
|
||||
242: 7,
|
||||
243: 7,
|
||||
244: 7,
|
||||
245: 7,
|
||||
246: 7,
|
||||
247: 9,
|
||||
248: 7,
|
||||
249: 7,
|
||||
250: 7,
|
||||
251: 7,
|
||||
252: 7,
|
||||
253: 7,
|
||||
254: 7,
|
||||
255: 7,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user