package card
import (
"fmt"
"strings"
"github.com/tiennm99/ghglance/internal/github"
"github.com/tiennm99/ghglance/internal/theme"
)
type topStarredReposCard struct{}
func (topStarredReposCard) Filename() string { return "top-starred-repos.svg" }
// maxTopRepoRows is how many repos we show. Matches the row count the stats
// and records cards fit in the shared 340x200 frame.
const maxTopRepoRows = 7
func (topStarredReposCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) {
const (
width = 340
height = 200
rowX = 20
rowY0 = 55
rowDY = 20
barX = 150
barW = 120 // max bar width; the top repo fills this
barH = 10
valueX = 334 // right-aligned anchor for the star count
nameMax = 17 // truncate long repo names at this many characters
)
repos := ownedNonForkRepos(p.TopRepos)
if len(repos) > maxTopRepoRows {
repos = repos[:maxTopRepoRows]
}
var b strings.Builder
b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, "Top Starred Repos"))
if len(repos) == 0 {
fmt.Fprintf(&b, `
No public repos with stars.`, t.Muted)
b.WriteString(footer)
return []byte(b.String()), nil
}
maxStars := repos[0].Stars
if maxStars <= 0 {
maxStars = 1
}
// Row layout: language swatch + name on the left, a proportional bar in
// the middle, star count right-anchored at valueX. The card title already
// says "Top Starred Repos", so the per-row star icon would just be noise.
for i, r := range repos {
y := rowY0 + i*rowDY
langColor := r.PrimaryColor
if langColor == "" {
langColor = t.Accent
}
name := truncate(r.Name, nameMax)
fmt.Fprintf(&b, `
%s`,
rowX+4, y-4, langColor,
rowX+14, y, t.Text, escapeXML(name))
bw := float64(barW) * float64(r.Stars) / float64(maxStars)
fmt.Fprintf(&b, `
`,
barX, y-barH+2, barW, barH, t.Accent,
barX, y-barH+2, bw, barH, t.Accent)
fmt.Fprintf(&b, `
%s ★`,
valueX, y, t.Accent, escapeXML(formatInt(r.Stars)))
}
b.WriteString(footer)
return []byte(b.String()), nil
}
// ownedNonForkRepos filters out forks so the card highlights the user's own
// work. TopRepos is already sorted by stargazer count desc at fetch time, so
// we just skim the prefix.
func ownedNonForkRepos(repos []github.RepoInfo) []github.RepoInfo {
out := make([]github.RepoInfo, 0, len(repos))
for _, r := range repos {
if r.IsFork {
continue
}
if r.Stars <= 0 {
continue
}
out = append(out, r)
}
return out
}