refactor(card): add octicon labels to stats card

Replace the 2x3 grid with one row per stat: icon + label + right-aligned
value. Icons (star, commit, PR, issue, code-review, repos) mirror the
Octicons used by github-profile-summary-cards' stats card.
This commit is contained in:
2026-04-18 21:09:46 +07:00
parent a12a331b57
commit 442da96f99
2 changed files with 35 additions and 19 deletions
+5
View File
@@ -10,4 +10,9 @@ const (
iconClock = `<path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.75a.75.75 0 00-1.5 0v3.5a.75.75 0 00.471.696l2.5 1a.75.75 0 00.557-1.392L8.5 7.742V4.75z"/>`
iconLink = `<path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"/>`
iconPeople = `<path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"/>`
iconStar = `<path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"/>`
iconCommit = `<path fill-rule="evenodd" d="M10.5 7.75a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm1.43.75a4.002 4.002 0 01-7.86 0H.75a.75.75 0 110-1.5h3.32a4.001 4.001 0 017.86 0h3.32a.75.75 0 110 1.5h-3.32z"/>`
iconPR = `<path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"/>`
iconIssue = `<path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"/>`
iconReview = `<path fill-rule="evenodd" d="M1.5 2.75a.25.25 0 01.25-.25h12.5a.25.25 0 01.25.25v8.5a.25.25 0 01-.25.25h-6.5a.75.75 0 00-.53.22L4.5 14.44v-2.19a.75.75 0 00-.75-.75h-2a.25.25 0 01-.25-.25v-8.5zM1.75 1A1.75 1.75 0 000 2.75v8.5C0 12.216.784 13 1.75 13H3v1.543a1.457 1.457 0 002.487 1.03L8.061 13h6.189A1.75 1.75 0 0016 11.25v-8.5A1.75 1.75 0 0014.25 1H1.75zm5.03 3.47a.75.75 0 010 1.06L5.31 7l1.47 1.47a.75.75 0 01-1.06 1.06l-2-2a.75.75 0 010-1.06l2-2a.75.75 0 011.06 0zm2.44 0a.75.75 0 000 1.06L10.69 7 9.22 8.47a.75.75 0 001.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0z"/>`
)
+30 -19
View File
@@ -12,35 +12,46 @@ type statsCard struct{}
func (statsCard) Filename() string { return "3-stats.svg" }
// statRow is one labeled-by-icon line in the stats card.
type statRow struct {
icon string
label string
value string
}
func (statsCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
const (
width = 500
height = 220
width = 500
height = 220
rowX = 25
rowY0 = 70
rowDY = 24
iconSize = 14
valueX = 475 // right-aligned x anchor
)
items := []struct{ label, value string }{
{"Total Stars", formatInt(p.TotalStars)},
{"Total Commits (last year)", formatInt(p.TotalCommits)},
{"Total PRs", formatInt(p.TotalPRs)},
{"Total Issues", formatInt(p.TotalIssues)},
{"Total PR Reviews", formatInt(p.TotalReviews)},
{"Contributed to (non-fork)", formatInt(p.TotalContributedTo)},
rows := []statRow{
{iconStar, "Total Stars", formatInt(p.TotalStars)},
{iconCommit, "Total Commits (last year)", formatInt(p.TotalCommits)},
{iconPR, "Total PRs", formatInt(p.TotalPRs)},
{iconIssue, "Total Issues", formatInt(p.TotalIssues)},
{iconReview, "Total PR Reviews", formatInt(p.TotalReviews)},
{iconRepos, "Contributed to (non-fork)", formatInt(p.TotalContributedTo)},
}
var b strings.Builder
b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, "Stats"))
// 2×3 grid: columns at 25 and 265, rows every 42px starting at y=80.
for i, it := range items {
col := i % 2
row := i / 2
x := 25 + col*240
y := 80 + row*42
scale := float64(iconSize) / 16.0
for i, r := range rows {
y := rowY0 + i*rowDY
fmt.Fprintf(&b, `
<text x="%d" y="%d" font-size="12" fill="%s">%s</text>
<text x="%d" y="%d" font-size="18" font-weight="600" fill="%s">%s</text>`,
x, y, t.Muted, escapeXML(it.label),
x, y+22, t.Accent, escapeXML(it.value))
<g transform="translate(%d,%.2f) scale(%.3f)" fill="%s">%s</g>
<text x="%d" y="%d" font-size="13" fill="%s">%s</text>
<text x="%d" y="%d" font-size="13" font-weight="600" fill="%s" text-anchor="end">%s</text>`,
rowX, float64(y-iconSize+2), scale, t.Muted, r.icon,
rowX+iconSize+10, y, t.Text, escapeXML(r.label),
valueX, y, t.Accent, escapeXML(r.value))
}
b.WriteString(footer)