diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md
index 378875d1..229dc5b3 100644
--- a/docs/deployment-guide.md
+++ b/docs/deployment-guide.md
@@ -110,7 +110,12 @@ runs:
3. On green, GHCR push + cross-platform binary artifacts happen automatically.
4. Docker base images and third-party actions are SHA-pinned (with version
comments) so mutable-tag changes upstream can't rewrite a released image.
-5. Update any public Actions marketplace metadata if the major version changed.
+5. **Marketplace publishing (one-time per repo):** GitHub only exposes the
+ "Publish this Action to the GitHub Marketplace" toggle on the Release
+ web UI — there is no CLI flag. Open the newly created release at
+ `https://github.com/tiennm99/ghstats/releases/tag/vX.Y.Z/edit`, tick the
+ marketplace checkbox, accept the terms, and re-publish. Subsequent
+ releases inherit marketplace visibility automatically.
## Rollback
diff --git a/internal/card/contributions.go b/internal/card/contributions.go
index 257f95fa..9f3dc0d7 100644
--- a/internal/card/contributions.go
+++ b/internal/card/contributions.go
@@ -37,12 +37,12 @@ type monthBucket struct {
// contribution cards; only title + data differ.
func renderContributions(title string, days []github.DailyContribution, t theme.Theme) []byte {
const (
- width = 500
- height = 220
- leftPad = 35
- rightPad = 35
- topPad = 60
- chartH = 120
+ width = 340
+ height = 200
+ leftPad = 28
+ rightPad = 28
+ topPad = 45
+ chartH = 105
)
chartW := width - leftPad - rightPad
diff --git a/internal/card/donut_chart.go b/internal/card/donut_chart.go
index 2723cce7..0c2aaa9d 100644
--- a/internal/card/donut_chart.go
+++ b/internal/card/donut_chart.go
@@ -14,17 +14,17 @@ import (
// shown; smaller slices are grouped into "Other".
func renderDonutCard(title string, stats []github.LangStat, t theme.Theme) []byte {
const (
- width = 500
- height = 220
- topN = 6
- cx = 380 // donut centre x
- cy = 120 // donut centre y
- outerR = 70.0 // donut outer radius
- innerR = 38.0 // donut hole
- legendX = 30
- legendY0 = 70
- legendDY = 22
- swatchSz = 12
+ width = 340
+ height = 200
+ topN = 5
+ cx = 250 // donut centre x
+ cy = 110 // donut centre y
+ outerR = 55.0 // donut outer radius
+ innerR = 30.0 // donut hole
+ legendX = 20
+ legendY0 = 55
+ legendDY = 20
+ swatchSz = 10
)
stats = collapseOther(stats, topN)
@@ -50,10 +50,10 @@ func renderDonutCard(title string, stats []github.LangStat, t theme.Theme) []byt
y := legendY0 + i*legendDY
fmt.Fprintf(&b, `
- %s %.2f%%`,
+ %s %.2f%%`,
legendX, y-swatchSz+2, swatchSz, swatchSz,
colorOrAccent(s.Color, t.Accent), t.Background,
- legendX+swatchSz+8, y, t.Text,
+ legendX+swatchSz+6, y, t.Text,
escapeXML(s.Name), pct)
}
diff --git a/internal/card/productive.go b/internal/card/productive.go
index dfaa93de..cc0a5bc0 100644
--- a/internal/card/productive.go
+++ b/internal/card/productive.go
@@ -40,13 +40,13 @@ var xTickHours = [...]int{0, 6, 12, 18, 23}
// hover titles. Shared by the last-year and all-time productive-time cards.
func renderProductiveTime(title string, data [24]int, t theme.Theme) []byte {
const (
- width = 500
- height = 220
- leftAxis = 50
- rightPad = 25
- topPad = 60
+ width = 340
+ height = 200
+ leftAxis = 35
+ rightPad = 15
+ topPad = 45
chartH = 110
- barGap = 2
+ barGap = 1
)
chartW := width - leftAxis - rightPad
barW := float64(chartW-barGap*23) / 24.0
diff --git a/internal/card/profile.go b/internal/card/profile.go
index 8f4e83ec..d330d7a1 100644
--- a/internal/card/profile.go
+++ b/internal/card/profile.go
@@ -21,12 +21,12 @@ type profileRow struct {
func (profileCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
const (
- width = 500
- height = 220
- rowX = 25
- rowY0 = 70
- rowDY = 24
- iconSize = 14
+ width = 340
+ height = 200
+ rowX = 20
+ rowY0 = 60
+ rowDY = 20
+ iconSize = 12
maxRows = 7
)
@@ -46,9 +46,9 @@ func (profileCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
// icon glyph: translate to row position, scale down, fill with muted.
fmt.Fprintf(&b, `
%s
- %s`,
+ %s`,
rowX, float64(y-iconSize+2), scale, t.Muted, r.icon,
- rowX+iconSize+10, y, t.Text, escapeXML(r.value))
+ rowX+iconSize+8, y, t.Text, escapeXML(r.value))
}
b.WriteString(footer)
diff --git a/internal/card/stats.go b/internal/card/stats.go
index e0a81832..40435eca 100644
--- a/internal/card/stats.go
+++ b/internal/card/stats.go
@@ -21,13 +21,13 @@ type statRow struct {
func (statsCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
const (
- width = 500
- height = 220
- rowX = 25
- rowY0 = 70
- rowDY = 24
- iconSize = 14
- valueX = 475 // right-aligned x anchor
+ width = 340
+ height = 200
+ rowX = 20
+ rowY0 = 55
+ rowDY = 20
+ iconSize = 12
+ valueX = 320 // right-aligned x anchor
)
rows := []statRow{
@@ -48,10 +48,10 @@ func (statsCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
y := rowY0 + i*rowDY
fmt.Fprintf(&b, `
%s
- %s
- %s`,
+ %s
+ %s`,
rowX, float64(y-iconSize+2), scale, t.Muted, r.icon,
- rowX+iconSize+10, y, t.Text, escapeXML(r.label),
+ rowX+iconSize+8, y, t.Text, escapeXML(r.label),
valueX, y, t.Accent, escapeXML(r.value))
}
diff --git a/internal/card/svg.go b/internal/card/svg.go
index 21c4c5dc..839bfb16 100644
--- a/internal/card/svg.go
+++ b/internal/card/svg.go
@@ -55,8 +55,8 @@ func formatInt(n int) string {
// header returns the opening