@shiinasaku/github-card 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -98
- package/dist/lib.d.ts +1 -1
- package/dist/lib.js +258 -120
- package/dist/utils/font.d.ts +3 -1
- package/dist/utils/format.d.ts +7 -0
- package/dist/utils/icons.d.ts +3 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +8 -9
- package/src/card.ts +307 -404
- package/src/github.ts +107 -49
- package/src/index.ts +7 -6
- package/src/lib.ts +1 -1
- package/src/utils/font.ts +4 -2
- package/src/utils/format.ts +41 -3
- package/src/utils/github-client.ts +13 -8
- package/src/utils/icons.ts +26 -9
- package/src/utils/index.ts +1 -1
- package/fonts/Roboto-subset.woff2 +0 -0
package/README.md
CHANGED
|
@@ -1,46 +1,102 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/logo.svg" alt="GitHub Card" width="
|
|
3
|
+
<img src="assets/logo.svg" alt="GitHub Card" width="520" />
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Beautiful, blazing-fast GitHub profile cards
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Drop one line in your README — get a live, auto-updating stats card.
|
|
7
|
+
Live SVG cards for your README — stars, commits, languages, all auto-updating. One line, zero config, edge-cached.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/@shiinasaku/github-card)
|
|
12
|
+
[](https://bun.sh)
|
|
13
|
+
[](https://elysiajs.com)
|
|
12
14
|
[](https://www.typescriptlang.org)
|
|
13
15
|
[](LICENSE)
|
|
14
16
|
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
15
17
|
|
|
16
|
-
<
|
|
18
|
+
<a href="https://card.shiina.xyz/card/shiinasaku?theme=shiina">
|
|
19
|
+
<img src="https://card.shiina.xyz/card/shiinasaku?theme=shiina" alt="Live demo — shiinasaku" width="520" />
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
<sub>Live instance · <code>shiinasaku</code> · theme <code>shiina</code> — updates itself as you code</sub>
|
|
17
23
|
|
|
18
24
|
</div>
|
|
19
25
|
|
|
20
26
|
---
|
|
21
27
|
|
|
28
|
+
### ✨ What's new in 4.2
|
|
29
|
+
|
|
30
|
+
> System-font only · no shipped `.woff2` · crisper text (`geometricPrecision`, tabular numbers) · new 24 px icons (MingCute / Huge / Tabler) · airy stat stack with 7 px gaps, no boxes · default `affiliations=owner` — org stars excluded unless `?affiliations=affiliated` · fully typed `github.ts` & `github-client`, cache v8.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
22
34
|
## Quickstart
|
|
23
35
|
|
|
24
|
-
Paste
|
|
36
|
+
Paste into your profile README — replace `shiinasaku` with your username:
|
|
25
37
|
|
|
26
38
|
```md
|
|
27
39
|
[](https://github.com/shiinasaku)
|
|
28
40
|
```
|
|
29
41
|
|
|
30
|
-
That's it. No sign-up, no build
|
|
42
|
+
That's it. No sign-up, no build — the card refreshes on every push.
|
|
43
|
+
|
|
44
|
+
<details>
|
|
45
|
+
<summary><b>Self-host / local dev</b></summary>
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bun install
|
|
49
|
+
cp .env.example .env # add GITHUB_TOKEN
|
|
50
|
+
bun dev # http://localhost:3000
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Command | Action |
|
|
54
|
+
| ------------------- | --------------------- |
|
|
55
|
+
| `bun test` | Run 51 tests |
|
|
56
|
+
| `bun run typecheck` | Strict `tsc --noEmit` |
|
|
57
|
+
| `bun run lint` | oxlint |
|
|
58
|
+
| `bun run fmt` | oxfmt |
|
|
59
|
+
|
|
60
|
+
</details>
|
|
61
|
+
|
|
62
|
+
---
|
|
31
63
|
|
|
32
64
|
## Why GitHub Card?
|
|
33
65
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
66
|
+
<table>
|
|
67
|
+
<tr>
|
|
68
|
+
<td width="50%">
|
|
69
|
+
|
|
70
|
+
**One line, zero config**<br/>
|
|
71
|
+
An `<img>` tag is the entire integration. No OAuth, no action.
|
|
72
|
+
|
|
73
|
+
**Edge-fast**<br/>
|
|
74
|
+
L1 memory + L2 Redis SWR, `s-maxage=1800`, `stale-while-revalidate`, `ETag`/`304`. Warm hits render in microseconds.
|
|
75
|
+
|
|
76
|
+
**Retina avatars**<br/>
|
|
77
|
+
Profile images inlined as Base64 at 2×, clipped + ringed in pure SVG.
|
|
78
|
+
|
|
79
|
+
</td>
|
|
80
|
+
<td width="50%">
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
**Adaptive layout**<br/>
|
|
83
|
+
Width, wrapping, and legends measured with per-glyph metrics — nothing ever overlaps or clips.
|
|
84
|
+
|
|
85
|
+
**Users _and_ orgs**<br/>
|
|
86
|
+
`GET /card/:login` works for users and organizations.
|
|
87
|
+
|
|
88
|
+
**Glassmorphic depth**<br/>
|
|
89
|
+
Radial + linear ambient gradients track your accent for volumetric light at zero runtime cost.
|
|
90
|
+
|
|
91
|
+
</td>
|
|
92
|
+
</tr>
|
|
93
|
+
</table>
|
|
94
|
+
|
|
95
|
+
OpenAPI docs live at [`/openapi`](https://card.shiina.xyz/openapi). Pure ESM lib, zero server dep for `renderCard`.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Themes — 21 hand-tuned
|
|
44
100
|
|
|
45
101
|
Preview **every** theme with your own data:
|
|
46
102
|
|
|
@@ -54,31 +110,33 @@ Preview **every** theme with your own data:
|
|
|
54
110
|
| `github_dark` · `dark` · `nord` · `dracula` | `forest` · `rose` · `cobalt` |
|
|
55
111
|
| `tokyonight` · `synthwave` · `radical` · `monokai` | `gruvbox` · `merko` · `onedark` · `highcontrast` |
|
|
56
112
|
|
|
113
|
+
Add `?theme=tokyonight` or override any slot with hex or Tailwind tokens: `pink-400`, `#ff79c6`, `ff79c6`.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
57
117
|
## Customization
|
|
58
118
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
### Examples
|
|
119
|
+
| Parameter | Type | Description |
|
|
120
|
+
| -------------- | :--------: | ----------------------------------------------------------------- |
|
|
121
|
+
| `theme` | `string` | Built-in theme (table above) |
|
|
122
|
+
| `bg_color` | `string` | Background fill |
|
|
123
|
+
| `title_color` | `string` | Name / title |
|
|
124
|
+
| `text_color` | `string` | Stats, labels, body |
|
|
125
|
+
| `icon_color` | `string` | Icons + ambient glow |
|
|
126
|
+
| `border_color` | `string` | Card outline |
|
|
127
|
+
| `hide_border` | `boolean` | Remove outline |
|
|
128
|
+
| `compact` | `boolean` | Slim — hides bio/pronouns/Twitter/legend |
|
|
129
|
+
| `animate` | `boolean` | Fade-in stats + animated language bar |
|
|
130
|
+
| `hide` | `string[]` | Hide stats: `stars`, `commits`, `issues`, `repos`, `prs` |
|
|
131
|
+
| `hide_langs` | `string[]` | Exclude `hide_langs=html,css` |
|
|
132
|
+
| `show_langs` | `string[]` | Only `show_langs=typescript,rust` |
|
|
133
|
+
| `lang_count` | `1–10` | Top languages (default `5`) |
|
|
134
|
+
| `scope` | `string` | `personal` (default), `org`, `all` |
|
|
135
|
+
| `orgs` | `string[]` | Restrict org stats to `orgs=vercel,elysiajs` |
|
|
136
|
+
| `affiliations` | `string` | `owner` (default) or `affiliated` — org stars excluded by default |
|
|
137
|
+
| `fields` | `string[]` | Fetch only `fields=stats` for speed |
|
|
138
|
+
|
|
139
|
+
#### Examples
|
|
82
140
|
|
|
83
141
|
```md
|
|
84
142
|
<!-- Dracula, no border, animated -->
|
|
@@ -89,107 +147,106 @@ Every visual slot is overridable. Colors accept hex (`ff79c6` or `#ff79c6`) and
|
|
|
89
147
|
|
|
90
148
|

|
|
91
149
|
|
|
92
|
-
<!-- Compact,
|
|
150
|
+
<!-- Compact, no issues/prs -->
|
|
93
151
|
|
|
94
152
|

|
|
95
153
|
|
|
96
|
-
<!--
|
|
154
|
+
<!-- Include org stars explicitly -->
|
|
155
|
+
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
<!-- Organization -->
|
|
97
159
|
|
|
98
160
|

|
|
99
161
|
```
|
|
100
162
|
|
|
163
|
+
---
|
|
164
|
+
|
|
101
165
|
## Deploy your own
|
|
102
166
|
|
|
103
167
|
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
104
168
|
|
|
105
|
-
1. Click the button
|
|
106
|
-
2. Add
|
|
169
|
+
1. Click the button (or fork + import).
|
|
170
|
+
2. Add env vars:
|
|
171
|
+
|
|
172
|
+
| Variable | Required | Purpose |
|
|
173
|
+
| :------------: | :------: | ----------------------------------- |
|
|
174
|
+
| `GITHUB_TOKEN` | ✅ | GitHub PAT — read-only is enough |
|
|
175
|
+
| `REDIS_URL` | ➖ | Redis / Upstash for shared L2 cache |
|
|
107
176
|
|
|
108
|
-
|
|
109
|
-
| -------------- | -------- | ----------------------------------------- |
|
|
110
|
-
| `GITHUB_TOKEN` | ✅ | GitHub PAT (read-only is enough) |
|
|
111
|
-
| `REDIS_URL` | ➖ | Redis/Upstash URL for the shared L2 cache |
|
|
177
|
+
3. Done — serves `/card/:username` on Vercel CDN `s-maxage=1800, stale-while-revalidate=1800`.
|
|
112
178
|
|
|
113
|
-
|
|
179
|
+
> Without Redis, in-memory LRU (1000 entries, SWR 30 min) still keeps warm instances fast.
|
|
114
180
|
|
|
115
|
-
|
|
181
|
+
---
|
|
116
182
|
|
|
117
183
|
## API
|
|
118
184
|
|
|
119
185
|
| Endpoint | Description |
|
|
120
186
|
| ----------------------- | ------------------------------------------- |
|
|
121
|
-
| `GET /card/:username` | SVG card
|
|
122
|
-
| `GET /:username/themes` | One SVG
|
|
187
|
+
| `GET /card/:username` | SVG card — all params above |
|
|
188
|
+
| `GET /:username/themes` | One SVG with **all themes** for a user |
|
|
123
189
|
| `GET /meta` | Service metadata + theme list |
|
|
124
190
|
| `GET /health` | Uptime, cache telemetry, Redis reachability |
|
|
125
191
|
| `GET /openapi` | Interactive OpenAPI docs |
|
|
126
192
|
|
|
127
|
-
Responses
|
|
193
|
+
Responses: `image/svg+xml`, `ETag` + `CDN-Cache-Control` + CORS `*`. Conditional `If-None-Match` → `304`.
|
|
194
|
+
|
|
195
|
+
---
|
|
128
196
|
|
|
129
197
|
## Use as a library
|
|
130
198
|
|
|
131
199
|
```bash
|
|
132
200
|
bun add @shiinasaku/github-card # Bun
|
|
133
|
-
npm install @shiinasaku/github-card # Node / Next
|
|
201
|
+
npm install @shiinasaku/github-card # Node / Next / Vite
|
|
134
202
|
```
|
|
135
203
|
|
|
136
204
|
```ts
|
|
137
205
|
import { renderCard, themes } from "@shiinasaku/github-card";
|
|
138
206
|
|
|
139
207
|
const svg = renderCard(user, stats, languages, { theme: "tokyonight" });
|
|
208
|
+
// → string of SVG, zero deps, any runtime
|
|
140
209
|
```
|
|
141
210
|
|
|
142
|
-
|
|
211
|
+
Prebuilt `dist/lib.js` + `.d.ts`; Bun resolves raw TS via `bun` export condition. Pure renderer — no network, no server.
|
|
143
212
|
|
|
144
|
-
|
|
213
|
+
---
|
|
145
214
|
|
|
146
|
-
|
|
215
|
+
## Architecture
|
|
147
216
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
217
|
+
```mermaid
|
|
218
|
+
flowchart LR
|
|
219
|
+
A[GET /card/:username] --> B[Elysia<br/>validation · CORS · OpenAPI · timing]
|
|
220
|
+
B --> C{L1 memory<br/>SWR 30m}
|
|
221
|
+
C -- hit --> G[render SVG<br/>ETag/304 → CDN]
|
|
222
|
+
C -- miss --> D{L2 Redis<br/>SWR 30m}
|
|
223
|
+
D -- hit --> G
|
|
224
|
+
D -- miss --> E[GitHub GraphQL<br/>100/page, 5 pages, 6s timeout]
|
|
225
|
+
E --> F[typed fetch<br/>+ avatar 150px]
|
|
226
|
+
F --> G
|
|
227
|
+
G --> H[Pure SVG<br/>system fonts · measured layout · glass]
|
|
228
|
+
```
|
|
151
229
|
|
|
152
|
-
|
|
230
|
+
- **Bun + Elysia** — one of the fastest HTTP stacks.
|
|
231
|
+
- **Two-tier SWR** — stale served instantly + background refresh, request coalescing via `inFlight`.
|
|
232
|
+
- **Typed upstream** — `RepoNode`/`ContributionEntry` generics, `T=unknown`, `TimeoutError`/`RateLimitError` mapping.
|
|
153
233
|
|
|
154
|
-
|
|
155
|
-
bun install
|
|
156
|
-
cp .env.example .env # add your GITHUB_TOKEN
|
|
157
|
-
bun dev # http://localhost:3000
|
|
158
|
-
```
|
|
234
|
+
---
|
|
159
235
|
|
|
160
|
-
|
|
161
|
-
| ------------------- | --------------------- |
|
|
162
|
-
| `bun test` | Run the test suite |
|
|
163
|
-
| `bun run typecheck` | Strict `tsc --noEmit` |
|
|
164
|
-
| `bun run lint` | oxlint |
|
|
165
|
-
| `bun run fmt` | oxfmt |
|
|
236
|
+
## Releasing
|
|
166
237
|
|
|
167
|
-
|
|
238
|
+
Fully automated:
|
|
168
239
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
L1 in-memory cache ──hit──► render SVG ──► ETag/304 ──► CDN
|
|
177
|
-
│miss ▲
|
|
178
|
-
▼ │ stale-while-revalidate
|
|
179
|
-
L2 Redis (SWR) ──hit──► serve stale + background refresh
|
|
180
|
-
│miss
|
|
181
|
-
▼
|
|
182
|
-
GitHub GraphQL (batched, paginated 100/page, 6s timeout)
|
|
183
|
-
│
|
|
184
|
-
▼
|
|
185
|
-
Pure SVG renderer (zero-dependency, dynamic layout engine)
|
|
186
|
-
```
|
|
240
|
+
1. **Actions → Bump** → `patch` / `minor` / `major`.
|
|
241
|
+
2. Workflow bumps `package.json`, commits, tags `vX.Y.Z`.
|
|
242
|
+
3. Tag triggers **Release**: `oxfmt` · `oxlint` · `typecheck` · `tests` · `dist` build · tag↔version guard · `npm pack` verify → publish with [provenance](https://docs.npmjs.com/generating-provenance-statements) + GitHub Release.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
<div align="center">
|
|
187
247
|
|
|
188
|
-
|
|
189
|
-
- **Two-tier SWR cache** — users never wait on GitHub's API.
|
|
190
|
-
- **Request coalescing** — concurrent misses share a single upstream fetch.
|
|
191
|
-
- **Defensive upstream** — timeouts, size caps, and typed errors (`401/404/429/502`).
|
|
248
|
+
**[MIT](LICENSE) © [saku shiina](https://www.shiina.xyz)** — built with Bun, Elysia, and system fonts.
|
|
192
249
|
|
|
193
|
-
|
|
250
|
+
<sub>Stars default to <code>owner</code> only in 4.2 — add <code>?affiliations=affiliated</code> to include orgs.</sub>
|
|
194
251
|
|
|
195
|
-
|
|
252
|
+
</div>
|
package/dist/lib.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export { renderCard, type CardOpts } from "./card";
|
|
8
8
|
export type { UserProfile, UserStats, LanguageStat, ProfileData, CardOptions } from "./types";
|
|
9
9
|
export { themes, resolveColors, type Theme } from "./utils/themes";
|
|
10
|
-
export { kFormat, escapeXml, wrapText } from "./utils/format";
|
|
10
|
+
export { kFormat, escapeXml, wrapText, measureText } from "./utils/format";
|
|
11
11
|
export { icons, icon } from "./utils/icons";
|
|
12
12
|
export { getLangColor } from "./utils/languages";
|
|
13
13
|
export { FONT_FACE, FONT_FAMILY } from "./utils/font";
|