Files
ghglance/internal/card/card.go
T
tiennm99 fd4c70e53e feat(card): add S-tier cards — heatmap, streak, by-year, weekday, top-starred (#3)
Five new cards, all derived from data FetchProductive / FetchProfile already
pull, so zero additional API calls:

- contributions-heatmap: 7×53 calendar grid with a 5-bucket intensity ramp
  mixed from each theme's Background→Accent so palettes with no dedicated
  heat ramp still render sensibly.
- streak: current streak, longest streak with date ranges, active/total days.
- contributions-by-year: one bar per active year, peak year highlighted.
- productive-weekday + -all-time: 7-bar day-of-week mirror of the hour-of-day
  cards; FetchProductive now also fills Weekday / WeekdayAllTime histograms
  during the same commit-history pass.
- top-starred-repos: top 5 owned non-fork repos by stargazer count; threads
  Stars through RepoInfo.

Card count: 9 → 14. Registered in allCards grouped by recency (last-year
block, then all-time block). Render test extended to cover all new files
and realistic daily-series inputs.
2026-04-19 08:58:59 +07:00

59 lines
1.6 KiB
Go

// Package card renders Profile data into SVG cards on disk.
package card
import (
"fmt"
"os"
"path/filepath"
"github.com/tiennm99/ghstats/internal/github"
"github.com/tiennm99/ghstats/internal/theme"
)
// Card renders one SVG for a Profile under the given theme.
type Card interface {
// Filename is the on-disk basename (e.g. "profile-details.svg").
Filename() string
// SVG returns the rendered SVG bytes.
SVG(p *github.Profile, t theme.Theme) ([]byte, error)
}
// allCards is the ordered list rendered by RenderAll. Filenames are plain
// kebab-case — README authors embed them by name, not by lexicographic order.
var allCards = []Card{
profileCard{},
reposPerLanguageCard{},
mostCommitLanguageCard{},
statsCard{},
productiveCard{},
productiveWeekdayCard{},
contributionsCard{},
contributionsHeatmapCard{},
topStarredReposCard{},
streakCard{},
mostCommitLanguageAllTimeCard{},
productiveAllTimeCard{},
productiveWeekdayAllTimeCard{},
contributionsAllTimeCard{},
contributionsByYearCard{},
}
// RenderAll writes every card into outDir/<themeID>/.
func RenderAll(p *github.Profile, t theme.Theme, outDir string) error {
dir := filepath.Join(outDir, t.ID)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("mkdir %s: %w", dir, err)
}
for _, c := range allCards {
data, err := c.SVG(p, t)
if err != nil {
return fmt.Errorf("render %s: %w", c.Filename(), err)
}
path := filepath.Join(dir, c.Filename())
if err := os.WriteFile(path, data, 0o644); err != nil {
return fmt.Errorf("write %s: %w", path, err)
}
}
return nil
}