docs: resync with current state across all project docs

- design-guidelines: every dimension was stale — card frame 340x200
  (was 500x220), corner radius 6, title 15px at (20,30), row y0/dy,
  donut centre (250,110) r=55/30, topN=5, legend y0=55 dy=20, bar chart
  area [35,325]x[45,155], area chart [28,312]x[45,150], icon scale 0.75.
- code-standards: FetchContributionsAllTime signature now ctx-first,
  viewbox 500x220 → 340x200.
- codebase-summary: test coverage lists main_test.go +
  TestDonutSingleSlice/Empty; filename convention says plain kebab-case
  (no numeric prefix).
- project-overview-pdr: forks/private defaults now on, not off.
- project-roadmap: add Phase 7 (Marketplace polish — resize, numeric-
  prefix drop, v1 floating tag, rename-rollback). Renumber planned
  phases 8-11. Fix "hard width 500 px" limitation.
- deployment-guide: document update-major-tag job; note
  Marketplace listing name is `ghstats-cards`.
This commit is contained in:
tiennm99 committed 2026-04-19 00:09:00 +07:00
1 parent d7659129a5
commit e5b6daae5a
6 files changed
+59 -40

No files matched your search

+26 -26
View File
@@ -1,17 +1,17 @@
# Design Guidelines
Visual conventions for ghstats SVG cards. All cards share a single frame shape so they stack cleanly in a README.
Visual conventions for ghstats SVG cards. All cards share a single frame shape so they stack cleanly in a README — two cards sit side-by-side inside GitHub's ~816 px content column.
## Card frame
| Property | Value |
| --- | --- |
| Width × Height | **500 × 220** |
| Corner radius | 8 px |
| Width × Height | **340 × 200** (matches github-profile-summary-cards) |
| Corner radius | 6 px |
| Stroke | `theme.Stroke` at `theme.StrokeOpacity` |
| Fill | `theme.Background` |
| Font family | `'Segoe UI', Ubuntu, Sans-Serif` |
| Title | 18 px, weight 600, `theme.Title`, anchored at `(25, 35)` |
| Title | 15 px, weight 600, `theme.Title`, anchored at `(20, 30)` |
Generated by `header(width, height, bg, stroke, strokeOpacity, titleColor, title)` in `internal/card/svg.go`.
@@ -32,30 +32,30 @@ Cards MUST NOT hardcode colors outside these fields. If a new visual needs a sha
Single-column rows of `icon + label` or `icon + label + value`.
| Metric | Value |
| --- | --- |
| First row baseline (y) | 70 |
| Row spacing | 24 px |
| Icon scale | `14/16 = 0.875` from 16×16 Octicon viewBox |
| Icon color | `theme.Muted` |
| Right-aligned value anchor (stats) | `x = 475`, `text-anchor="end"` |
| Value font weight | 600 |
| Value color | `theme.Accent` |
| Metric | Profile | Stats |
| --- | --- | --- |
| First row baseline (y) | 60 | 55 |
| Row spacing | 20 px | 20 px |
| Row x padding | 20 | 20 |
| Icon scale | `12/16 = 0.75` from 16×16 Octicon viewBox | same |
| Icon color | `theme.Muted` | same |
| Value font | 12 px, `theme.Text` | 12 px, weight 600, `theme.Accent`, right-anchored at `x = 320` |
Cap rows at what fits: 7 for profile, 7 for stats (commits row splits into lifetime + last-year).
Cap rows at what fits: up to 7 rows per card. Stats splits commits into lifetime + last-year rows.
## Donut cards (language breakdowns)
| Metric | Value |
| --- | --- |
| Donut centre | `(380, 120)` |
| Outer radius | 70 |
| Inner radius | 38 |
| Top-N entries shown | 6 (overflow collapses into "Other") |
| Donut centre | `(250, 110)` |
| Outer radius | 55 |
| Inner radius | 30 |
| Top-N entries shown | 5 (overflow collapses into "Other") |
| Slice stroke | `theme.Background`, 1.5 px (gap between slices) |
| Legend origin | `(30, 70)` |
| Legend row height | 22 px |
| Swatch size | 12 × 12 |
| Legend origin | `(20, 55)` |
| Legend row height | 20 px |
| Swatch size | 10 × 10 |
| Legend font | 11 px |
Language colors come from linguist via GraphQL (`repo.languages.edges[].node.color`). Missing colors fall back to `theme.Accent`.
@@ -65,8 +65,8 @@ When there's **exactly one slice** (one language at 100%), the renderer emits tw
| Metric | Value |
| --- | --- |
| Chart area | `x ∈ [50, 475]`, `y ∈ [60, 170]` (110 tall) |
| Bars | 24 bars, 2 px gap |
| Chart area | `x ∈ [35, 325]`, `y ∈ [45, 155]` (110 tall) |
| Bars | 24 bars, 1 px gap |
| Bar fill | `theme.Accent` |
| Y-axis ticks | `niceTicks(max, 5)` — 1/2/5 × 10^k ladder |
| X-axis labels | Hours 0, 6, 12, 18, 23 |
@@ -78,7 +78,7 @@ When there's **exactly one slice** (one language at 100%), the renderer emits tw
| Metric | Value |
| --- | --- |
| Chart area | `x ∈ [35, 465]`, `y ∈ [60, 180]` (120 tall) |
| Chart area | `x ∈ [28, 312]`, `y ∈ [45, 150]` (105 tall) |
| Curve | Catmull-Rom → cubic Bezier (tension 0.5) |
| Fill | `theme.Accent` at 25% opacity |
| Stroke | `theme.Accent`, 2 px |
@@ -93,7 +93,7 @@ Missing months in the `[first, last]` range are inserted as zero-count rows to k
- Sourced from [Primer Octicons](https://primer.style/octicons/) 16×16 set.
- Stored as raw `<path d="…"/>` strings in `internal/card/icons.go`.
- Rendered inside `<g transform="translate(x,y) scale(0.875)" fill="muted">…</g>`.
- Rendered inside `<g transform="translate(x,y) scale(0.75)" fill="muted">…</g>` (scaled to fit the 12 px box).
- Used: `iconRepos`, `iconCompany`, `iconLocation`, `iconClock`, `iconLink`, `iconPeople`, `iconStar`, `iconCommit`, `iconPR`, `iconIssue`, `iconReview`.
Add new icons by copying the `<path>` from Octicons and appending to `icons.go`. Keep them to the same 16×16 viewBox so the existing scale math applies.
@@ -107,4 +107,4 @@ Add new icons by copying the `<path>` from Octicons and appending to `icons.go`.
## Text overflow
- Long strings (bio, repo names) are **not truncated**; they're XML-escaped and printed as-is.
- If a card looks crowded at 500 px width, that's a card design problem — fix the layout, not the data.
- If a card looks crowded at 340 px width, that's a card design problem — fix the layout, not the data.