@shiinasaku/github-card 2.0.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 +159 -261
- package/dist/card.d.ts +16 -0
- package/dist/lib.d.ts +13 -0
- package/dist/lib.js +1347 -0
- package/dist/types.d.ts +37 -0
- package/dist/utils/colors.d.ts +2 -0
- package/dist/utils/font.d.ts +4 -0
- package/dist/utils/format.d.ts +10 -0
- package/dist/utils/icons.d.ts +11 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/languages.d.ts +2 -0
- package/dist/utils/themes.d.ts +16 -0
- package/package.json +30 -20
- package/src/card.ts +537 -113
- package/src/env.d.ts +4 -0
- package/src/github.ts +406 -480
- package/src/index.ts +148 -134
- package/src/input.css +1 -0
- package/src/lib.ts +1 -1
- package/src/tailwind.css +3837 -0
- package/src/types.ts +1 -0
- package/src/utils/colors.ts +85 -0
- package/src/utils/font.ts +5 -19
- package/src/utils/format.ts +54 -16
- package/src/utils/github-client.ts +198 -0
- package/src/utils/icons.ts +27 -9
- package/src/utils/index.ts +2 -1
- package/src/utils/themes.ts +154 -19
- package/fonts/Roboto-subset.woff2 +0 -0
package/README.md
CHANGED
|
@@ -1,354 +1,252 @@
|
|
|
1
|
-
# GitHub Profile Card
|
|
2
|
-
|
|
3
1
|
<div align="center">
|
|
4
2
|
|
|
5
|
-
<
|
|
3
|
+
<img src="assets/logo.svg" alt="GitHub Card" width="520" />
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://card.shiina.xyz/card/ShiinaSaku?theme=github_dark" />
|
|
9
|
-
<img src="https://card.shiina.xyz/card/ShiinaSaku" alt="GitHub Profile Card" width="500" />
|
|
10
|
-
</picture>
|
|
5
|
+
### Beautiful, blazing-fast GitHub profile cards
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
Live SVG cards for your README — stars, commits, languages, all auto-updating. One line, zero config, edge-cached.
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
<br/>
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
[](https://www.npmjs.com/package/@shiinasaku/github-card)
|
|
12
|
+
[](https://bun.sh)
|
|
13
|
+
[](https://elysiajs.com)
|
|
14
|
+
[](https://www.typescriptlang.org)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
[](#testing)
|
|
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>
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
[All Themes](https://card.shiina.xyz/ShiinaSaku/themes) ·
|
|
25
|
-
[API Docs](https://card.shiina.xyz/openapi) ·
|
|
26
|
-
[npm Package](#programmatic-usage-npm)
|
|
22
|
+
<sub>Live instance · <code>shiinasaku</code> · theme <code>shiina</code> — updates itself as you code</sub>
|
|
27
23
|
|
|
28
24
|
</div>
|
|
29
25
|
|
|
30
26
|
---
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```markdown
|
|
35
|
-

|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Replace `YOUR_USERNAME`. Done.
|
|
39
|
-
|
|
40
|
-
### Dark mode aware
|
|
28
|
+
### ✨ What's new in 4.2
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
<picture>
|
|
44
|
-
<source
|
|
45
|
-
media="(prefers-color-scheme: dark)"
|
|
46
|
-
srcset="https://card.shiina.xyz/card/YOUR_USERNAME?theme=github_dark"
|
|
47
|
-
/>
|
|
48
|
-
<img src="https://card.shiina.xyz/card/YOUR_USERNAME" alt="GitHub Stats" />
|
|
49
|
-
</picture>
|
|
50
|
-
```
|
|
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.
|
|
51
31
|
|
|
52
32
|
---
|
|
53
33
|
|
|
54
|
-
##
|
|
55
|
-
|
|
56
|
-
20 built-in themes. Pass `?theme=name` to use one.
|
|
34
|
+
## Quickstart
|
|
57
35
|
|
|
58
|
-
|
|
59
|
-
<tr>
|
|
60
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=default" width="400" alt="default" /><br/><code>default</code></td>
|
|
61
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=github_dark" width="400" alt="github_dark" /><br/><code>github_dark</code></td>
|
|
62
|
-
</tr>
|
|
63
|
-
<tr>
|
|
64
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=tokyonight" width="400" alt="tokyonight" /><br/><code>tokyonight</code></td>
|
|
65
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=dracula" width="400" alt="dracula" /><br/><code>dracula</code></td>
|
|
66
|
-
</tr>
|
|
67
|
-
<tr>
|
|
68
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=nord" width="400" alt="nord" /><br/><code>nord</code></td>
|
|
69
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=radical" width="400" alt="radical" /><br/><code>radical</code></td>
|
|
70
|
-
</tr>
|
|
71
|
-
<tr>
|
|
72
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=synthwave" width="400" alt="synthwave" /><br/><code>synthwave</code></td>
|
|
73
|
-
<td align="center"><img src="https://card.shiina.xyz/card/ShiinaSaku?theme=rose" width="400" alt="rose" /><br/><code>rose</code></td>
|
|
74
|
-
</tr>
|
|
75
|
-
</table>
|
|
36
|
+
Paste into your profile README — replace `shiinasaku` with your username:
|
|
76
37
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
38
|
+
```md
|
|
39
|
+
[](https://github.com/shiinasaku)
|
|
40
|
+
```
|
|
80
41
|
|
|
81
|
-
|
|
42
|
+
That's it. No sign-up, no build — the card refreshes on every push.
|
|
82
43
|
|
|
83
|
-
|
|
44
|
+
<details>
|
|
45
|
+
<summary><b>Self-host / local dev</b></summary>
|
|
84
46
|
|
|
85
|
-
```
|
|
86
|
-
|
|
47
|
+
```bash
|
|
48
|
+
bun install
|
|
49
|
+
cp .env.example .env # add GITHUB_TOKEN
|
|
50
|
+
bun dev # http://localhost:3000
|
|
87
51
|
```
|
|
88
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
|
+
|
|
89
60
|
</details>
|
|
90
61
|
|
|
91
62
|
---
|
|
92
63
|
|
|
93
|
-
##
|
|
94
|
-
|
|
95
|
-
All parameters are optional query strings on `/card/:username`.
|
|
96
|
-
|
|
97
|
-
### Appearance
|
|
64
|
+
## Why GitHub Card?
|
|
98
65
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| `compact` | `false` | Hides bio, pronouns, language labels |
|
|
103
|
-
| `hide_border` | `false` | Removes the card border |
|
|
104
|
-
|
|
105
|
-
### Custom Colors
|
|
66
|
+
<table>
|
|
67
|
+
<tr>
|
|
68
|
+
<td width="50%">
|
|
106
69
|
|
|
107
|
-
|
|
70
|
+
**One line, zero config**<br/>
|
|
71
|
+
An `<img>` tag is the entire integration. No OAuth, no action.
|
|
108
72
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
| `bg_color` | Background |
|
|
112
|
-
| `title_color` | Name text |
|
|
113
|
-
| `text_color` | Body text & labels |
|
|
114
|
-
| `icon_color` | Stat icons |
|
|
115
|
-
| `border_color` | Card border |
|
|
73
|
+
**Edge-fast**<br/>
|
|
74
|
+
L1 memory + L2 Redis SWR, `s-maxage=1800`, `stale-while-revalidate`, `ETag`/`304`. Warm hits render in microseconds.
|
|
116
75
|
|
|
117
|
-
|
|
76
|
+
**Retina avatars**<br/>
|
|
77
|
+
Profile images inlined as Base64 at 2×, clipped + ringed in pure SVG.
|
|
118
78
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
| `lang_count` | `5` | Top languages shown (1--10) |
|
|
122
|
-
| `hide` | -- | Comma-separated: `stars,commits,issues,repos,prs` |
|
|
123
|
-
| `scope` | `personal` | `personal` / `org` / `all` -- see [scope details](#what-the-card-shows) |
|
|
124
|
-
| `orgs` | -- | Comma-separated org logins to include (filters contributed-to repos) |
|
|
79
|
+
</td>
|
|
80
|
+
<td width="50%">
|
|
125
81
|
|
|
126
|
-
|
|
82
|
+
**Adaptive layout**<br/>
|
|
83
|
+
Width, wrapping, and legends measured with per-glyph metrics — nothing ever overlaps or clips.
|
|
127
84
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
https://card.shiina.xyz/card/ShiinaSaku?compact=true&lang_count=3
|
|
85
|
+
**Users _and_ orgs**<br/>
|
|
86
|
+
`GET /card/:login` works for users and organizations.
|
|
131
87
|
|
|
132
|
-
|
|
133
|
-
|
|
88
|
+
**Glassmorphic depth**<br/>
|
|
89
|
+
Radial + linear ambient gradients track your accent for volumetric light at zero runtime cost.
|
|
134
90
|
|
|
135
|
-
|
|
136
|
-
|
|
91
|
+
</td>
|
|
92
|
+
</tr>
|
|
93
|
+
</table>
|
|
137
94
|
|
|
138
|
-
|
|
139
|
-
https://card.shiina.xyz/card/ShiinaSaku?hide=issues,prs,stars
|
|
140
|
-
```
|
|
95
|
+
OpenAPI docs live at [`/openapi`](https://card.shiina.xyz/openapi). Pure ESM lib, zero server dep for `renderCard`.
|
|
141
96
|
|
|
142
97
|
---
|
|
143
98
|
|
|
144
|
-
##
|
|
99
|
+
## Themes — 21 hand-tuned
|
|
145
100
|
|
|
146
|
-
|
|
101
|
+
Preview **every** theme with your own data:
|
|
147
102
|
|
|
148
|
-
```
|
|
149
|
-
|
|
103
|
+
```md
|
|
104
|
+

|
|
150
105
|
```
|
|
151
106
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const svg = renderCard(
|
|
158
|
-
{
|
|
159
|
-
login: "octocat",
|
|
160
|
-
name: "The Octocat",
|
|
161
|
-
avatarUrl: "https://github.com/octocat.png",
|
|
162
|
-
bio: "Open source enthusiast",
|
|
163
|
-
pronouns: "they/them",
|
|
164
|
-
twitter: "github",
|
|
165
|
-
},
|
|
166
|
-
{ stars: 3200, commits: 1450, issues: 89, repos: 42, prs: 210 },
|
|
167
|
-
[
|
|
168
|
-
{ name: "TypeScript", size: 120000, color: "#3178c6" },
|
|
169
|
-
{ name: "Go", size: 80000, color: "#00ADD8" },
|
|
170
|
-
{ name: "Rust", size: 40000, color: "#dea584" },
|
|
171
|
-
],
|
|
172
|
-
{ theme: "tokyonight", compact: false },
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
// svg is a self-contained SVG string with embedded font
|
|
176
|
-
```
|
|
107
|
+
| Dark favorites | Light & accent |
|
|
108
|
+
| -------------------------------------------------- | ------------------------------------------------ |
|
|
109
|
+
| `shiina` · `aurora` · `oled` · `slate` | `default` · `pearl` · `sand` |
|
|
110
|
+
| `github_dark` · `dark` · `nord` · `dracula` | `forest` · `rose` · `cobalt` |
|
|
111
|
+
| `tokyonight` · `synthwave` · `radical` · `monokai` | `gruvbox` · `merko` · `onedark` · `highcontrast` |
|
|
177
112
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import {
|
|
182
|
-
// Core renderer
|
|
183
|
-
renderCard,
|
|
184
|
-
type CardOpts,
|
|
185
|
-
|
|
186
|
-
// Types
|
|
187
|
-
type UserProfile,
|
|
188
|
-
type UserStats,
|
|
189
|
-
type LanguageStat,
|
|
190
|
-
type ProfileData,
|
|
191
|
-
type CardOptions,
|
|
192
|
-
|
|
193
|
-
// Theming
|
|
194
|
-
themes,
|
|
195
|
-
resolveColors,
|
|
196
|
-
type Theme,
|
|
197
|
-
|
|
198
|
-
// Utilities
|
|
199
|
-
kFormat, // 1500 -> "1.5k"
|
|
200
|
-
escapeXml, // "<>" -> "<>"
|
|
201
|
-
wrapText, // text wrapping with ellipsis
|
|
202
|
-
icon, // SVG stat icons (star, commit, pr, issue, repo, x)
|
|
203
|
-
icons, // raw SVG path data
|
|
204
|
-
getLangColor, // language -> hex color (650+ languages)
|
|
205
|
-
FONT_FACE, // base64 @font-face CSS rule
|
|
206
|
-
FONT_FAMILY, // font-family declaration
|
|
207
|
-
} from "github-card";
|
|
208
|
-
```
|
|
113
|
+
Add `?theme=tokyonight` or override any slot with hex or Tailwind tokens: `pink-400`, `#ff79c6`, `ff79c6`.
|
|
209
114
|
|
|
210
|
-
|
|
115
|
+
---
|
|
211
116
|
|
|
212
|
-
|
|
117
|
+
## Customization
|
|
213
118
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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 |
|
|
217
138
|
|
|
218
|
-
|
|
219
|
-
.use(githubCard) // adds /card/:username, /:username/themes, etc.
|
|
220
|
-
.get("/my-route", () => "hello")
|
|
221
|
-
.listen(3000);
|
|
222
|
-
```
|
|
139
|
+
#### Examples
|
|
223
140
|
|
|
224
|
-
|
|
141
|
+
```md
|
|
142
|
+
<!-- Dracula, no border, animated -->
|
|
225
143
|
|
|
226
|
-
|
|
144
|
+

|
|
227
145
|
|
|
228
|
-
|
|
146
|
+
<!-- Fully custom colors -->
|
|
229
147
|
|
|
230
|
-
|
|
231
|
-
git clone https://github.com/ShiinaSaku/Github-Card.git
|
|
232
|
-
cd Github-Card
|
|
233
|
-
vercel deploy
|
|
234
|
-
```
|
|
148
|
+

|
|
235
149
|
|
|
236
|
-
|
|
150
|
+
<!-- Compact, no issues/prs -->
|
|
237
151
|
|
|
238
|
-
|
|
239
|
-
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx # required
|
|
240
|
-
UPSTASH_REDIS_REST_URL=https://... # optional, L2 cache
|
|
241
|
-
UPSTASH_REDIS_REST_TOKEN=... # optional
|
|
242
|
-
```
|
|
152
|
+

|
|
243
153
|
|
|
244
|
-
|
|
154
|
+
<!-- Include org stars explicitly -->
|
|
245
155
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
156
|
+

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

|
|
251
161
|
```
|
|
252
162
|
|
|
253
163
|
---
|
|
254
164
|
|
|
255
|
-
##
|
|
165
|
+
## Deploy your own
|
|
256
166
|
|
|
257
|
-
|
|
258
|
-
| :---------------------- | :------------------------------------------ |
|
|
259
|
-
| `GET /card/:username` | SVG stats card |
|
|
260
|
-
| `GET /:username/themes` | SVG grid of all themes |
|
|
261
|
-
| `GET /health` | JSON -- cache metrics, Redis status, uptime |
|
|
262
|
-
| `GET /openapi` | Interactive API documentation |
|
|
167
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
263
168
|
|
|
264
|
-
|
|
169
|
+
1. Click the button (or fork + import).
|
|
170
|
+
2. Add env vars:
|
|
265
171
|
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
| `
|
|
269
|
-
|
|
|
270
|
-
| `Server-Timing` | Per-request timing telemetry |
|
|
271
|
-
| `Access-Control-Allow-Origin` | `*` |
|
|
172
|
+
| Variable | Required | Purpose |
|
|
173
|
+
| :------------: | :------: | ----------------------------------- |
|
|
174
|
+
| `GITHUB_TOKEN` | ✅ | GitHub PAT — read-only is enough |
|
|
175
|
+
| `REDIS_URL` | ➖ | Redis / Upstash for shared L2 cache |
|
|
272
176
|
|
|
273
|
-
|
|
177
|
+
3. Done — serves `/card/:username` on Vercel CDN `s-maxage=1800, stale-while-revalidate=1800`.
|
|
274
178
|
|
|
275
|
-
|
|
276
|
-
| :--- | :------------------ |
|
|
277
|
-
| 200 | SVG card |
|
|
278
|
-
| 304 | Cached (ETag match) |
|
|
279
|
-
| 401 | Bad GitHub token |
|
|
280
|
-
| 404 | User not found |
|
|
281
|
-
| 422 | Invalid parameters |
|
|
282
|
-
| 429 | GitHub rate limited |
|
|
283
|
-
| 502 | GitHub API down |
|
|
179
|
+
> Without Redis, in-memory LRU (1000 entries, SWR 30 min) still keeps warm instances fast.
|
|
284
180
|
|
|
285
181
|
---
|
|
286
182
|
|
|
287
|
-
##
|
|
183
|
+
## API
|
|
288
184
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
```
|
|
185
|
+
| Endpoint | Description |
|
|
186
|
+
| ----------------------- | ------------------------------------------- |
|
|
187
|
+
| `GET /card/:username` | SVG card — all params above |
|
|
188
|
+
| `GET /:username/themes` | One SVG with **all themes** for a user |
|
|
189
|
+
| `GET /meta` | Service metadata + theme list |
|
|
190
|
+
| `GET /health` | Uptime, cache telemetry, Redis reachability |
|
|
191
|
+
| `GET /openapi` | Interactive OpenAPI docs |
|
|
297
192
|
|
|
298
|
-
|
|
299
|
-
| :-------- | :---------------------------------------- |
|
|
300
|
-
| Runtime | Bun |
|
|
301
|
-
| Framework | Elysia |
|
|
302
|
-
| Data | GitHub GraphQL API |
|
|
303
|
-
| Cache L1 | In-memory Map with SWR |
|
|
304
|
-
| Cache L2 | Upstash Redis (serverless) |
|
|
305
|
-
| Font | Roboto (subsetted WOFF2, base64 embedded) |
|
|
306
|
-
| Deploy | Vercel Functions |
|
|
307
|
-
| Tests | bun:test -- 21 tests |
|
|
308
|
-
| Lint | oxlint + oxfmt |
|
|
193
|
+
Responses: `image/svg+xml`, `ETag` + `CDN-Cache-Control` + CORS `*`. Conditional `If-None-Match` → `304`.
|
|
309
194
|
|
|
310
195
|
---
|
|
311
196
|
|
|
312
|
-
##
|
|
197
|
+
## Use as a library
|
|
313
198
|
|
|
314
199
|
```bash
|
|
315
|
-
bun
|
|
316
|
-
|
|
317
|
-
bun run typecheck # tsc
|
|
318
|
-
bun run lint # oxlint
|
|
200
|
+
bun add @shiinasaku/github-card # Bun
|
|
201
|
+
npm install @shiinasaku/github-card # Node / Next / Vite
|
|
319
202
|
```
|
|
320
203
|
|
|
321
|
-
|
|
204
|
+
```ts
|
|
205
|
+
import { renderCard, themes } from "@shiinasaku/github-card";
|
|
322
206
|
|
|
323
|
-
|
|
207
|
+
const svg = renderCard(user, stats, languages, { theme: "tokyonight" });
|
|
208
|
+
// → string of SVG, zero deps, any runtime
|
|
209
|
+
```
|
|
324
210
|
|
|
325
|
-
|
|
326
|
-
| :-------- | :------------------------------------- |
|
|
327
|
-
| Stars | Total across owned repos (excl. forks) |
|
|
328
|
-
| Commits | Current calendar year |
|
|
329
|
-
| Issues | Open + closed |
|
|
330
|
-
| Repos | Owned, non-fork |
|
|
331
|
-
| PRs | Open + closed + merged |
|
|
332
|
-
| Languages | Top N by code size |
|
|
211
|
+
Prebuilt `dist/lib.js` + `.d.ts`; Bun resolves raw TS via `bun` export condition. Pure renderer — no network, no server.
|
|
333
212
|
|
|
334
|
-
|
|
213
|
+
---
|
|
335
214
|
|
|
336
|
-
|
|
337
|
-
| :--------- | :--------------------------------------------------- | :--------------------------------- |
|
|
338
|
-
| `personal` | Your own repos only | Single query |
|
|
339
|
-
| `org` | Org repos you actually contributed to (commits, PRs) | Parallel: metadata + contributions |
|
|
340
|
-
| `all` | Your repos + org repos you contributed to | Parallel: personal + contributions |
|
|
215
|
+
## Architecture
|
|
341
216
|
|
|
342
|
-
|
|
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
|
+
```
|
|
229
|
+
|
|
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.
|
|
343
233
|
|
|
344
234
|
---
|
|
345
235
|
|
|
346
|
-
##
|
|
236
|
+
## Releasing
|
|
237
|
+
|
|
238
|
+
Fully automated:
|
|
347
239
|
|
|
348
|
-
|
|
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.
|
|
349
243
|
|
|
350
244
|
---
|
|
351
245
|
|
|
352
246
|
<div align="center">
|
|
353
|
-
|
|
247
|
+
|
|
248
|
+
**[MIT](LICENSE) © [saku shiina](https://www.shiina.xyz)** — built with Bun, Elysia, and system fonts.
|
|
249
|
+
|
|
250
|
+
<sub>Stars default to <code>owner</code> only in 4.2 — add <code>?affiliations=affiliated</code> to include orgs.</sub>
|
|
251
|
+
|
|
354
252
|
</div>
|
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UserProfile, UserStats, LanguageStat } from "./types";
|
|
2
|
+
export type CardOpts = {
|
|
3
|
+
theme?: string;
|
|
4
|
+
title_color?: string;
|
|
5
|
+
text_color?: string;
|
|
6
|
+
icon_color?: string;
|
|
7
|
+
bg_color?: string;
|
|
8
|
+
border_color?: string;
|
|
9
|
+
hide_border?: boolean;
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
hide?: string[];
|
|
12
|
+
hide_langs?: string[];
|
|
13
|
+
show_langs?: string[];
|
|
14
|
+
animate?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare function renderCard(user: UserProfile, stats: UserStats, langs: LanguageStat[], opts?: CardOpts): string;
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* github-card — npm entry point
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the pure SVG renderer, all themes, types, and utility functions.
|
|
5
|
+
* No server dependency — works in any JS/TS runtime.
|
|
6
|
+
*/
|
|
7
|
+
export { renderCard, type CardOpts } from "./card";
|
|
8
|
+
export type { UserProfile, UserStats, LanguageStat, ProfileData, CardOptions } from "./types";
|
|
9
|
+
export { themes, resolveColors, type Theme } from "./utils/themes";
|
|
10
|
+
export { kFormat, escapeXml, wrapText, measureText } from "./utils/format";
|
|
11
|
+
export { icons, icon } from "./utils/icons";
|
|
12
|
+
export { getLangColor } from "./utils/languages";
|
|
13
|
+
export { FONT_FACE, FONT_FAMILY } from "./utils/font";
|