mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 05:11:41 +01: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:
		
							parent
							
								
									0d2607a303
								
							
						
					
					
						commit
						bf9500b3f2
					
				| @ -4,6 +4,9 @@ | ||||
| package badge | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 
 | ||||
| 	actions_model "code.gitea.io/gitea/models/actions" | ||||
| ) | ||||
| 
 | ||||
| @ -11,54 +14,35 @@ import ( | ||||
| // We use 10x scale to calculate more precisely | ||||
| // Then scale down to normal size in tmpl file | ||||
| 
 | ||||
| type Label 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 { | ||||
| type Text struct { | ||||
| 	text  string | ||||
| 	width int | ||||
| 	x     int | ||||
| } | ||||
| 
 | ||||
| func (m Message) Text() string { | ||||
| 	return m.text | ||||
| func (t Text) Text() string { | ||||
| 	return t.text | ||||
| } | ||||
| 
 | ||||
| func (m Message) Width() int { | ||||
| 	return m.width | ||||
| func (t Text) Width() int { | ||||
| 	return t.width | ||||
| } | ||||
| 
 | ||||
| func (m Message) X() int { | ||||
| 	return m.x | ||||
| func (t Text) X() int { | ||||
| 	return t.x | ||||
| } | ||||
| 
 | ||||
| func (m Message) TextLength() int { | ||||
| 	return int(float64(m.width-defaultOffset) * 9.5) | ||||
| func (t Text) TextLength() int { | ||||
| 	return int(float64(t.width-defaultOffset) * 10) | ||||
| } | ||||
| 
 | ||||
| type Badge struct { | ||||
| 	Color    string | ||||
| 	FontSize int | ||||
| 	Label    Label | ||||
| 	Message  Message | ||||
| 	IDPrefix   string | ||||
| 	FontFamily string | ||||
| 	Color      string | ||||
| 	FontSize   int | ||||
| 	Label      Text | ||||
| 	Message    Text | ||||
| } | ||||
| 
 | ||||
| func (b Badge) Width() int { | ||||
| @ -66,10 +50,10 @@ func (b Badge) Width() int { | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	defaultOffset    = 9 | ||||
| 	defaultFontSize  = 11 | ||||
| 	DefaultColor     = "#9f9f9f" // Grey | ||||
| 	defaultFontWidth = 7         // approximate speculation | ||||
| 	defaultOffset     = 10 | ||||
| 	defaultFontSize   = 11 | ||||
| 	DefaultColor      = "#9f9f9f" // Grey | ||||
| 	DefaultFontFamily = "DejaVu Sans,Verdana,Geneva,sans-serif" | ||||
| ) | ||||
| 
 | ||||
| var StatusColorMap = map[actions_model.Status]string{ | ||||
| @ -85,20 +69,43 @@ var StatusColorMap = map[actions_model.Status]string{ | ||||
| 
 | ||||
| // GenerateBadge generates badge with given template | ||||
| func GenerateBadge(label, message, color string) Badge { | ||||
| 	lw := defaultFontWidth*len(label) + defaultOffset | ||||
| 	mw := defaultFontWidth*len(message) + defaultOffset | ||||
| 	x := lw*10 + mw*5 - 10 | ||||
| 	lw := calculateTextWidth(label) + defaultOffset | ||||
| 	mw := calculateTextWidth(message) + defaultOffset | ||||
| 
 | ||||
| 	lx := lw * 5 | ||||
| 	mx := lw*10 + mw*5 - 10 | ||||
| 	return Badge{ | ||||
| 		Label: Label{ | ||||
| 		FontFamily: DefaultFontFamily, | ||||
| 		Label: Text{ | ||||
| 			text:  label, | ||||
| 			width: lw, | ||||
| 			x:     lx, | ||||
| 		}, | ||||
| 		Message: Message{ | ||||
| 		Message: Text{ | ||||
| 			text:  message, | ||||
| 			width: mw, | ||||
| 			x:     x, | ||||
| 			x:     mx, | ||||
| 		}, | ||||
| 		FontSize: defaultFontSize * 10, | ||||
| 		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 | ||||
| 
 | ||||
| import ( | ||||
| 	"html/template" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"unicode" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models/asymkey" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	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/templates" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| 	"code.gitea.io/gitea/services/context" | ||||
| ) | ||||
| 
 | ||||
| @ -45,84 +50,121 @@ func FetchActionTest(ctx *context.Context) { | ||||
| 	ctx.JSONRedirect("") | ||||
| } | ||||
| 
 | ||||
| func prepareMockData(ctx *context.Context) { | ||||
| 	if ctx.Req.URL.Path == "/devtest/gitea-ui" { | ||||
| 		now := time.Now() | ||||
| 		ctx.Data["TimeNow"] = now | ||||
| 		ctx.Data["TimePast5s"] = now.Add(-5 * time.Second) | ||||
| 		ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second) | ||||
| 		ctx.Data["TimePast2m"] = 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["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second) | ||||
| func prepareMockDataGiteaUI(ctx *context.Context) { | ||||
| 	now := time.Now() | ||||
| 	ctx.Data["TimeNow"] = now | ||||
| 	ctx.Data["TimePast5s"] = now.Add(-5 * time.Second) | ||||
| 	ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second) | ||||
| 	ctx.Data["TimePast2m"] = 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["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 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()}, | ||||
| 			}, | ||||
| 		}) | ||||
| 	var badgeSVGs []template.HTML | ||||
| 	for i, b := range badges { | ||||
| 		b.IDPrefix = "devtest-" + strconv.FormatInt(int64(i), 10) + "-" | ||||
| 		b.FontFamily = selectedFontFamilyName | ||||
| 		h, err := ctx.RenderToHTML("shared/actions/runner_badge", map[string]any{"Badge": b}) | ||||
| 		if err != nil { | ||||
| 			ctx.ServerError("RenderToHTML", err) | ||||
| 			return | ||||
| 		} | ||||
| 		badgeSVGs = append(badgeSVGs, h) | ||||
| 	} | ||||
| 	ctx.Data["BadgeSVGs"] = badgeSVGs | ||||
| 	ctx.Data["BadgeFontFamilyNames"] = fontFamilyNames | ||||
| 	ctx.Data["SelectedFontFamilyName"] = selectedFontFamilyName | ||||
| } | ||||
| 
 | ||||
| 		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) | ||||
| 	if ctx.Req.Method == "POST" { | ||||
| 		_ = ctx.Req.ParseForm() | ||||
|  | ||||
| @ -1639,7 +1639,7 @@ func registerRoutes(m *web.Router) { | ||||
| 		m.Group("/devtest", func() { | ||||
| 			m.Any("", devtest.List) | ||||
| 			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.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}}"> | ||||
| 	<title>{{.Badge.Label.Text}}: {{.Badge.Message.Text}}</title> | ||||
| 	<linearGradient id="s" x2="0" y2="100%"> | ||||
| 		<stop offset="0" stop-color="#fff" stop-opacity=".7" /> | ||||
| 		<stop offset=".1" stop-color="#aaa" stop-opacity=".1" /> | ||||
| 		<stop offset=".9" stop-color="#000" stop-opacity=".3" /> | ||||
| 		<stop offset="1" stop-color="#000" stop-opacity=".5" /> | ||||
| 	<linearGradient id="{{.Badge.IDPrefix}}s" x2="0" y2="100%"> | ||||
| 		<stop offset="0" stop-color="#bbb" stop-opacity=".1" /> | ||||
| 		<stop offset="1" stop-opacity=".1" /> | ||||
| 	</linearGradient> | ||||
| 	<clipPath id="r"> | ||||
| 		<rect width="{{.Badge.Width}}" height="18" rx="4" fill="#fff" /> | ||||
| 	<clipPath id="{{.Badge.IDPrefix}}r"> | ||||
| 		<rect width="{{.Badge.Width}}" height="20" rx="3" fill="#fff" /> | ||||
| 	</clipPath> | ||||
| 	<g clip-path="url(#r)"> | ||||
| 		<rect width="{{.Badge.Label.Width}}" height="18" fill="#555" /> | ||||
| 		<rect x="{{.Badge.Label.Width}}" width="{{.Badge.Message.Width}}" height="18" fill="{{.Badge.Color}}" /> | ||||
| 		<rect width="{{.Badge.Width}}" height="18" fill="url(#s)" /> | ||||
| 	<g clip-path="url(#{{.Badge.IDPrefix}}r)"> | ||||
| 		<rect width="{{.Badge.Label.Width}}" height="20" fill="#555" /> | ||||
| 		<rect x="{{.Badge.Label.Width}}" width="{{.Badge.Message.Width}}" height="20" fill="{{.Badge.Color}}" /> | ||||
| 		<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 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> | ||||
|  | ||||
| Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user