mirror of https://github.com/go-gitea/gitea.git
Update action status badge layout (#34018)
The current action status badge are looking different from most other badges renders, which is especially noticeable when using them along with other badges. This PR updates the action badges to match the commonly used badges from other providers. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
0d2607a303
commit
bf9500b3f2
|
|
@ -4,6 +4,9 @@
|
||||||
package badge
|
package badge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -11,54 +14,35 @@ import (
|
||||||
// We use 10x scale to calculate more precisely
|
// We use 10x scale to calculate more precisely
|
||||||
// Then scale down to normal size in tmpl file
|
// Then scale down to normal size in tmpl file
|
||||||
|
|
||||||
type Label struct {
|
type Text struct {
|
||||||
text string
|
|
||||||
width int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l Label) Text() string {
|
|
||||||
return l.text
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l Label) Width() int {
|
|
||||||
return l.width
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l Label) TextLength() int {
|
|
||||||
return int(float64(l.width-defaultOffset) * 9.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l Label) X() int {
|
|
||||||
return l.width*5 + 10
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
text string
|
text string
|
||||||
width int
|
width int
|
||||||
x int
|
x int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) Text() string {
|
func (t Text) Text() string {
|
||||||
return m.text
|
return t.text
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) Width() int {
|
func (t Text) Width() int {
|
||||||
return m.width
|
return t.width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) X() int {
|
func (t Text) X() int {
|
||||||
return m.x
|
return t.x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) TextLength() int {
|
func (t Text) TextLength() int {
|
||||||
return int(float64(m.width-defaultOffset) * 9.5)
|
return int(float64(t.width-defaultOffset) * 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Badge struct {
|
type Badge struct {
|
||||||
Color string
|
IDPrefix string
|
||||||
FontSize int
|
FontFamily string
|
||||||
Label Label
|
Color string
|
||||||
Message Message
|
FontSize int
|
||||||
|
Label Text
|
||||||
|
Message Text
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Badge) Width() int {
|
func (b Badge) Width() int {
|
||||||
|
|
@ -66,10 +50,10 @@ func (b Badge) Width() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultOffset = 9
|
defaultOffset = 10
|
||||||
defaultFontSize = 11
|
defaultFontSize = 11
|
||||||
DefaultColor = "#9f9f9f" // Grey
|
DefaultColor = "#9f9f9f" // Grey
|
||||||
defaultFontWidth = 7 // approximate speculation
|
DefaultFontFamily = "DejaVu Sans,Verdana,Geneva,sans-serif"
|
||||||
)
|
)
|
||||||
|
|
||||||
var StatusColorMap = map[actions_model.Status]string{
|
var StatusColorMap = map[actions_model.Status]string{
|
||||||
|
|
@ -85,20 +69,43 @@ var StatusColorMap = map[actions_model.Status]string{
|
||||||
|
|
||||||
// GenerateBadge generates badge with given template
|
// GenerateBadge generates badge with given template
|
||||||
func GenerateBadge(label, message, color string) Badge {
|
func GenerateBadge(label, message, color string) Badge {
|
||||||
lw := defaultFontWidth*len(label) + defaultOffset
|
lw := calculateTextWidth(label) + defaultOffset
|
||||||
mw := defaultFontWidth*len(message) + defaultOffset
|
mw := calculateTextWidth(message) + defaultOffset
|
||||||
x := lw*10 + mw*5 - 10
|
|
||||||
|
lx := lw * 5
|
||||||
|
mx := lw*10 + mw*5 - 10
|
||||||
return Badge{
|
return Badge{
|
||||||
Label: Label{
|
FontFamily: DefaultFontFamily,
|
||||||
|
Label: Text{
|
||||||
text: label,
|
text: label,
|
||||||
width: lw,
|
width: lw,
|
||||||
|
x: lx,
|
||||||
},
|
},
|
||||||
Message: Message{
|
Message: Text{
|
||||||
text: message,
|
text: message,
|
||||||
width: mw,
|
width: mw,
|
||||||
x: x,
|
x: mx,
|
||||||
},
|
},
|
||||||
FontSize: defaultFontSize * 10,
|
FontSize: defaultFontSize * 10,
|
||||||
Color: color,
|
Color: color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateTextWidth(text string) int {
|
||||||
|
width := 0
|
||||||
|
widthData := 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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package badge
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
var DejaVuGlyphWidthData = sync.OnceValue(func() 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,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -4,16 +4,21 @@
|
||||||
package devtest
|
package devtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/asymkey"
|
"code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/badge"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -45,84 +50,121 @@ func FetchActionTest(ctx *context.Context) {
|
||||||
ctx.JSONRedirect("")
|
ctx.JSONRedirect("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareMockData(ctx *context.Context) {
|
func prepareMockDataGiteaUI(ctx *context.Context) {
|
||||||
if ctx.Req.URL.Path == "/devtest/gitea-ui" {
|
now := time.Now()
|
||||||
now := time.Now()
|
ctx.Data["TimeNow"] = now
|
||||||
ctx.Data["TimeNow"] = now
|
ctx.Data["TimePast5s"] = now.Add(-5 * time.Second)
|
||||||
ctx.Data["TimePast5s"] = now.Add(-5 * time.Second)
|
ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second)
|
||||||
ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second)
|
ctx.Data["TimePast2m"] = now.Add(-2 * time.Minute)
|
||||||
ctx.Data["TimePast2m"] = now.Add(-2 * time.Minute)
|
ctx.Data["TimeFuture2m"] = now.Add(2 * time.Minute)
|
||||||
ctx.Data["TimeFuture2m"] = now.Add(2 * time.Minute)
|
ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
|
||||||
ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
|
ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
|
||||||
ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
|
}
|
||||||
|
|
||||||
|
func prepareMockDataBadgeCommitSign(ctx *context.Context) {
|
||||||
|
var commits []*asymkey.SignCommit
|
||||||
|
mockUsers, _ := db.Find[user_model.User](ctx, user_model.SearchUserOptions{ListOptions: db.ListOptions{PageSize: 1}})
|
||||||
|
mockUser := mockUsers[0]
|
||||||
|
commits = append(commits, &asymkey.SignCommit{
|
||||||
|
Verification: &asymkey.CommitVerification{},
|
||||||
|
UserCommit: &user_model.UserCommit{
|
||||||
|
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
commits = append(commits, &asymkey.SignCommit{
|
||||||
|
Verification: &asymkey.CommitVerification{
|
||||||
|
Verified: true,
|
||||||
|
Reason: "name / key-id",
|
||||||
|
SigningUser: mockUser,
|
||||||
|
SigningKey: &asymkey.GPGKey{KeyID: "12345678"},
|
||||||
|
TrustStatus: "trusted",
|
||||||
|
},
|
||||||
|
UserCommit: &user_model.UserCommit{
|
||||||
|
User: mockUser,
|
||||||
|
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
commits = append(commits, &asymkey.SignCommit{
|
||||||
|
Verification: &asymkey.CommitVerification{
|
||||||
|
Verified: true,
|
||||||
|
Reason: "name / key-id",
|
||||||
|
SigningUser: mockUser,
|
||||||
|
SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
|
||||||
|
TrustStatus: "untrusted",
|
||||||
|
},
|
||||||
|
UserCommit: &user_model.UserCommit{
|
||||||
|
User: mockUser,
|
||||||
|
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
commits = append(commits, &asymkey.SignCommit{
|
||||||
|
Verification: &asymkey.CommitVerification{
|
||||||
|
Verified: true,
|
||||||
|
Reason: "name / key-id",
|
||||||
|
SigningUser: mockUser,
|
||||||
|
SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
|
||||||
|
TrustStatus: "other(unmatch)",
|
||||||
|
},
|
||||||
|
UserCommit: &user_model.UserCommit{
|
||||||
|
User: mockUser,
|
||||||
|
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
commits = append(commits, &asymkey.SignCommit{
|
||||||
|
Verification: &asymkey.CommitVerification{
|
||||||
|
Warning: true,
|
||||||
|
Reason: "gpg.error",
|
||||||
|
SigningEmail: "test@example.com",
|
||||||
|
},
|
||||||
|
UserCommit: &user_model.UserCommit{
|
||||||
|
User: mockUser,
|
||||||
|
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.Data["MockCommits"] = commits
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareMockDataBadgeActionsSvg(ctx *context.Context) {
|
||||||
|
fontFamilyNames := strings.Split(badge.DefaultFontFamily, ",")
|
||||||
|
selectedFontFamilyName := ctx.FormString("font", fontFamilyNames[0])
|
||||||
|
var badges []badge.Badge
|
||||||
|
badges = append(badges, badge.GenerateBadge("啊啊啊啊啊啊啊啊啊啊啊啊", "🌞🌞🌞🌞🌞", "green"))
|
||||||
|
for r := rune(0); r < 256; r++ {
|
||||||
|
if unicode.IsPrint(r) {
|
||||||
|
s := strings.Repeat(string(r), 15)
|
||||||
|
badges = append(badges, badge.GenerateBadge(s, util.TruncateRunes(s, 7), "green"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Req.URL.Path == "/devtest/commit-sign-badge" {
|
var badgeSVGs []template.HTML
|
||||||
var commits []*asymkey.SignCommit
|
for i, b := range badges {
|
||||||
mockUsers, _ := db.Find[user_model.User](ctx, user_model.SearchUserOptions{ListOptions: db.ListOptions{PageSize: 1}})
|
b.IDPrefix = "devtest-" + strconv.FormatInt(int64(i), 10) + "-"
|
||||||
mockUser := mockUsers[0]
|
b.FontFamily = selectedFontFamilyName
|
||||||
commits = append(commits, &asymkey.SignCommit{
|
h, err := ctx.RenderToHTML("shared/actions/runner_badge", map[string]any{"Badge": b})
|
||||||
Verification: &asymkey.CommitVerification{},
|
if err != nil {
|
||||||
UserCommit: &user_model.UserCommit{
|
ctx.ServerError("RenderToHTML", err)
|
||||||
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
return
|
||||||
},
|
}
|
||||||
})
|
badgeSVGs = append(badgeSVGs, h)
|
||||||
commits = append(commits, &asymkey.SignCommit{
|
}
|
||||||
Verification: &asymkey.CommitVerification{
|
ctx.Data["BadgeSVGs"] = badgeSVGs
|
||||||
Verified: true,
|
ctx.Data["BadgeFontFamilyNames"] = fontFamilyNames
|
||||||
Reason: "name / key-id",
|
ctx.Data["SelectedFontFamilyName"] = selectedFontFamilyName
|
||||||
SigningUser: mockUser,
|
}
|
||||||
SigningKey: &asymkey.GPGKey{KeyID: "12345678"},
|
|
||||||
TrustStatus: "trusted",
|
|
||||||
},
|
|
||||||
UserCommit: &user_model.UserCommit{
|
|
||||||
User: mockUser,
|
|
||||||
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
commits = append(commits, &asymkey.SignCommit{
|
|
||||||
Verification: &asymkey.CommitVerification{
|
|
||||||
Verified: true,
|
|
||||||
Reason: "name / key-id",
|
|
||||||
SigningUser: mockUser,
|
|
||||||
SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
|
|
||||||
TrustStatus: "untrusted",
|
|
||||||
},
|
|
||||||
UserCommit: &user_model.UserCommit{
|
|
||||||
User: mockUser,
|
|
||||||
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
commits = append(commits, &asymkey.SignCommit{
|
|
||||||
Verification: &asymkey.CommitVerification{
|
|
||||||
Verified: true,
|
|
||||||
Reason: "name / key-id",
|
|
||||||
SigningUser: mockUser,
|
|
||||||
SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
|
|
||||||
TrustStatus: "other(unmatch)",
|
|
||||||
},
|
|
||||||
UserCommit: &user_model.UserCommit{
|
|
||||||
User: mockUser,
|
|
||||||
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
commits = append(commits, &asymkey.SignCommit{
|
|
||||||
Verification: &asymkey.CommitVerification{
|
|
||||||
Warning: true,
|
|
||||||
Reason: "gpg.error",
|
|
||||||
SigningEmail: "test@example.com",
|
|
||||||
},
|
|
||||||
UserCommit: &user_model.UserCommit{
|
|
||||||
User: mockUser,
|
|
||||||
Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.Data["MockCommits"] = commits
|
func prepareMockData(ctx *context.Context) {
|
||||||
|
switch ctx.Req.URL.Path {
|
||||||
|
case "/devtest/gitea-ui":
|
||||||
|
prepareMockDataGiteaUI(ctx)
|
||||||
|
case "/devtest/badge-commit-sign":
|
||||||
|
prepareMockDataBadgeCommitSign(ctx)
|
||||||
|
case "/devtest/badge-actions-svg":
|
||||||
|
prepareMockDataBadgeActionsSvg(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Tmpl(ctx *context.Context) {
|
func TmplCommon(ctx *context.Context) {
|
||||||
prepareMockData(ctx)
|
prepareMockData(ctx)
|
||||||
if ctx.Req.Method == "POST" {
|
if ctx.Req.Method == "POST" {
|
||||||
_ = ctx.Req.ParseForm()
|
_ = ctx.Req.ParseForm()
|
||||||
|
|
|
||||||
|
|
@ -1639,7 +1639,7 @@ func registerRoutes(m *web.Router) {
|
||||||
m.Group("/devtest", func() {
|
m.Group("/devtest", func() {
|
||||||
m.Any("", devtest.List)
|
m.Any("", devtest.List)
|
||||||
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
||||||
m.Any("/{sub}", devtest.Tmpl)
|
m.Any("/{sub}", devtest.TmplCommon)
|
||||||
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
|
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
|
||||||
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{{template "devtest/devtest-header"}}
|
||||||
|
<div class="page-content devtest ui container">
|
||||||
|
<div>
|
||||||
|
<h1>Actions SVG</h1>
|
||||||
|
<form class="tw-my-3">
|
||||||
|
{{range $fontName := .BadgeFontFamilyNames}}
|
||||||
|
<label><input name="font" type="radio" value="{{$fontName}}" {{Iif (eq $.SelectedFontFamilyName $fontName) "checked"}}>{{$fontName}}</label>
|
||||||
|
{{end}}
|
||||||
|
<button>submit</button>
|
||||||
|
</form>
|
||||||
|
<div class="flex-text-block tw-flex-wrap">
|
||||||
|
{{range $badgeSVG := .BadgeSVGs}}
|
||||||
|
<div>{{$badgeSVG}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "devtest/devtest-footer"}}
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{.Badge.Width}}" height="18"
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{.Badge.Width}}" height="20"
|
||||||
role="img" aria-label="{{.Badge.Label.Text}}: {{.Badge.Message.Text}}">
|
role="img" aria-label="{{.Badge.Label.Text}}: {{.Badge.Message.Text}}">
|
||||||
<title>{{.Badge.Label.Text}}: {{.Badge.Message.Text}}</title>
|
<title>{{.Badge.Label.Text}}: {{.Badge.Message.Text}}</title>
|
||||||
<linearGradient id="s" x2="0" y2="100%">
|
<linearGradient id="{{.Badge.IDPrefix}}s" x2="0" y2="100%">
|
||||||
<stop offset="0" stop-color="#fff" stop-opacity=".7" />
|
<stop offset="0" stop-color="#bbb" stop-opacity=".1" />
|
||||||
<stop offset=".1" stop-color="#aaa" stop-opacity=".1" />
|
<stop offset="1" stop-opacity=".1" />
|
||||||
<stop offset=".9" stop-color="#000" stop-opacity=".3" />
|
|
||||||
<stop offset="1" stop-color="#000" stop-opacity=".5" />
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<clipPath id="r">
|
<clipPath id="{{.Badge.IDPrefix}}r">
|
||||||
<rect width="{{.Badge.Width}}" height="18" rx="4" fill="#fff" />
|
<rect width="{{.Badge.Width}}" height="20" rx="3" fill="#fff" />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<g clip-path="url(#r)">
|
<g clip-path="url(#{{.Badge.IDPrefix}}r)">
|
||||||
<rect width="{{.Badge.Label.Width}}" height="18" fill="#555" />
|
<rect width="{{.Badge.Label.Width}}" height="20" fill="#555" />
|
||||||
<rect x="{{.Badge.Label.Width}}" width="{{.Badge.Message.Width}}" height="18" fill="{{.Badge.Color}}" />
|
<rect x="{{.Badge.Label.Width}}" width="{{.Badge.Message.Width}}" height="20" fill="{{.Badge.Color}}" />
|
||||||
<rect width="{{.Badge.Width}}" height="18" fill="url(#s)" />
|
<rect width="{{.Badge.Width}}" height="20" fill="url(#{{.Badge.IDPrefix}}s)" />
|
||||||
|
</g>
|
||||||
|
<g fill="#fff" text-anchor="middle" font-family="{{.Badge.FontFamily}}"
|
||||||
|
text-rendering="geometricPrecision" font-size="{{.Badge.FontSize}}">
|
||||||
|
<text aria-hidden="true" x="{{.Badge.Label.X}}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)"
|
||||||
|
textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text>
|
||||||
|
<text x="{{.Badge.Label.X}}" y="140"
|
||||||
|
transform="scale(.1)" fill="#fff" textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text>
|
||||||
|
<text aria-hidden="true" x="{{.Badge.Message.X}}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)"
|
||||||
|
textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text>
|
||||||
|
<text x="{{.Badge.Message.X}}" y="140" transform="scale(.1)" fill="#fff"
|
||||||
|
textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text>
|
||||||
</g>
|
</g>
|
||||||
<g fill="#fff" text-anchor="middle" font-family="Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision"
|
|
||||||
font-size="{{.Badge.FontSize}}"><text aria-hidden="true" x="{{.Badge.Label.X}}" y="140" fill="#010101" fill-opacity=".3"
|
|
||||||
transform="scale(.1)" textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text><text x="{{.Badge.Label.X}}" y="130"
|
|
||||||
transform="scale(.1)" fill="#fff" textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text><text aria-hidden="true"
|
|
||||||
x="{{.Badge.Message.X}}" y="140" fill="#010101" fill-opacity=".3" transform="scale(.1)"
|
|
||||||
textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text><text x="{{.Badge.Message.X}}" y="130" transform="scale(.1)"
|
|
||||||
fill="#fff" textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text></g>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in New Issue