mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-23 01:48:47 +03:00
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:
@ -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
|
||||||
|
}
|
||||||
|
208
modules/badge/badge_glyph_width.go
Normal file
208
modules/badge/badge_glyph_width.go
Normal file
@ -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)
|
||||||
})
|
})
|
||||||
|
18
templates/devtest/badge-actions-svg.tmpl
Normal file
18
templates/devtest/badge-actions-svg.tmpl
Normal file
@ -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 |
Reference in New Issue
Block a user