mirror of
https://github.com/tiennm99/ghglance.git
synced 2026-10-15 20:15:50 +00:00
`ghglance -serve :8080` runs a web UI from the same binary: submit a username, a background job renders every card in every theme, and /u/<user> shows them again with a theme picker and embed URLs. - Cards are stored on disk with atomic symlink publishing and deleted after -retention (default 24h); -cooldown limits token-less regeneration. - Token-less jobs use a public-only server token with private and org scope forced off; a submitter's own token is used for that job only and never stored or logged. The form links to GitHub's new-token page with the needed scopes pre-ticked. - The CLI and web share one fetch helper; CLI output is unchanged. - compose.yml deploys to Coolify with a data volume and /healthz check.
69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
// Package card renders Profile data into SVG cards on disk.
|
|
package card
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/tiennm99/ghglance/internal/github"
|
|
"github.com/tiennm99/ghglance/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{},
|
|
recordsCard{},
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// Filenames lists every card's on-disk basename in render order.
|
|
func Filenames() []string {
|
|
out := make([]string, len(allCards))
|
|
for i, c := range allCards {
|
|
out[i] = c.Filename()
|
|
}
|
|
return out
|
|
}
|