Skip to content

Commit 230fbf7

Browse files
Senavictorsclaude
andcommitted
feat: initial monorepo — Stats widget, Worker API, CI pipeline
Bootstraps the full GitWidgets monorepo: - packages/core: Stats domain, GraphQL fetcher with ETag/D1 cache, SVG renderer, dark theme, rank algorithm (38 tests passing) - apps/api: Cloudflare Worker serving /api/stats.svg with 3-layer cache (HTTP headers → KV → D1); error SVG fallback - Shared tsconfig presets, Biome config, Turborepo pipeline - CI: lint → typecheck → test → build - README, ADR-0001, issue templates, PR template Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0 parents  commit 230fbf7

68 files changed

Lines changed: 9292 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Bug report
2+
description: Something is broken
3+
labels: [bug]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Thanks for taking the time to report a bug. Fill in as much as you can.
9+
10+
- type: input
11+
id: widget-url
12+
attributes:
13+
label: Widget URL
14+
description: The full URL that is producing the wrong output
15+
placeholder: "https://gitwidgets.dev/api/stats.svg?username=..."
16+
validations:
17+
required: false
18+
19+
- type: textarea
20+
id: description
21+
attributes:
22+
label: What happened?
23+
description: Describe the bug. Include the SVG output or a screenshot if possible.
24+
validations:
25+
required: true
26+
27+
- type: textarea
28+
id: expected
29+
attributes:
30+
label: What did you expect?
31+
validations:
32+
required: true
33+
34+
- type: textarea
35+
id: context
36+
attributes:
37+
label: Additional context
38+
description: Browser, OS, README link, error logs from wrangler dev, etc.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Discussions
4+
url: https://github.com/gitwidgets-org/gitwidgets/discussions
5+
about: Questions, ideas, and show-and-tell go here.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Feature request
2+
description: Propose a new widget, theme, or parameter
3+
labels: [enhancement]
4+
body:
5+
- type: textarea
6+
id: problem
7+
attributes:
8+
label: What problem does this solve?
9+
description: Describe the use case. What can't you do today?
10+
validations:
11+
required: true
12+
13+
- type: textarea
14+
id: proposal
15+
attributes:
16+
label: Proposed solution
17+
description: How would you like it to work? Include example URLs or sketches if helpful.
18+
validations:
19+
required: true
20+
21+
- type: textarea
22+
id: alternatives
23+
attributes:
24+
label: Alternatives considered
25+
description: Any workarounds you've tried or other tools that do this.
26+
27+
- type: checkboxes
28+
id: scope
29+
attributes:
30+
label: Scope
31+
options:
32+
- label: New widget
33+
- label: New theme
34+
- label: New query parameter for an existing widget
35+
- label: API / Action / SDK behaviour
36+
- label: Dashboard / docs

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Summary
2+
3+
<!-- 1-3 bullet points describing what changed and why -->
4+
5+
## Type of change
6+
7+
- [ ] Bug fix
8+
- [ ] New widget / theme
9+
- [ ] New query parameter
10+
- [ ] Refactor (no behaviour change)
11+
- [ ] Docs / tests only
12+
13+
## Test plan
14+
15+
<!-- How did you verify this works? -->
16+
17+
- [ ] `pnpm lint && pnpm typecheck && pnpm test` passes
18+
- [ ] Snapshot updated (if renderer changed): `pnpm test -u`
19+
- [ ] Tested locally with `wrangler dev --local` (if API changed)
20+
21+
## Screenshots
22+
23+
<!-- Paste the rendered SVG or a browser screenshot if this affects any widget's appearance -->

.github/workflows/ci.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
lint:
9+
name: Lint
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: pnpm/action-setup@v4
14+
with:
15+
version: 9
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 20
19+
cache: pnpm
20+
- run: pnpm install --frozen-lockfile
21+
- run: pnpm lint
22+
23+
typecheck:
24+
name: Typecheck
25+
runs-on: ubuntu-latest
26+
needs: lint
27+
steps:
28+
- uses: actions/checkout@v4
29+
- uses: pnpm/action-setup@v4
30+
with:
31+
version: 9
32+
- uses: actions/setup-node@v4
33+
with:
34+
node-version: 20
35+
cache: pnpm
36+
- run: pnpm install --frozen-lockfile
37+
- run: pnpm typecheck
38+
39+
test:
40+
name: Test
41+
runs-on: ubuntu-latest
42+
needs: typecheck
43+
steps:
44+
- uses: actions/checkout@v4
45+
- uses: pnpm/action-setup@v4
46+
with:
47+
version: 9
48+
- uses: actions/setup-node@v4
49+
with:
50+
node-version: 20
51+
cache: pnpm
52+
- run: pnpm install --frozen-lockfile
53+
- run: pnpm test
54+
55+
build:
56+
name: Build
57+
runs-on: ubuntu-latest
58+
needs: test
59+
steps:
60+
- uses: actions/checkout@v4
61+
- uses: pnpm/action-setup@v4
62+
with:
63+
version: 9
64+
- uses: actions/setup-node@v4
65+
with:
66+
node-version: 20
67+
cache: pnpm
68+
- run: pnpm install --frozen-lockfile
69+
- run: pnpm build

.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Claude Code
2+
CLAUDE.md
3+
plano-gitwidgets.md
4+
5+
# Dependencies
6+
node_modules/
7+
.pnpm-store/
8+
9+
# Build outputs
10+
dist/
11+
.next/
12+
out/
13+
coverage/
14+
*.tsbuildinfo
15+
16+
# Cloudflare / Wrangler
17+
.wrangler/
18+
.dev.vars
19+
.dev.vars.*
20+
21+
# Turbo
22+
.turbo/
23+
24+
# Environment
25+
.env
26+
.env.*
27+
!.env.example
28+
29+
# OS
30+
.DS_Store
31+
Thumbs.db
32+
33+
# Editor
34+
.vscode/settings.json
35+
.idea/
36+
*.swp
37+
*.swo
38+
39+
# Logs
40+
*.log
41+
npm-debug.log*
42+
pnpm-debug.log*

README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# GitWidgets
2+
3+
[![CI](https://github.com/gitwidgets-org/gitwidgets/actions/workflows/ci.yml/badge.svg)](https://github.com/gitwidgets-org/gitwidgets/actions/workflows/ci.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5+
[![pnpm](https://img.shields.io/badge/pnpm-9-orange)](https://pnpm.io)
6+
7+
> Dynamic SVG widgets for GitHub READMEs — stats, streak, top languages, and more.
8+
> One engine. Three delivery channels. Zero lock-in.
9+
10+
---
11+
12+
## Widgets
13+
14+
| Widget | Status | Preview |
15+
|---|---|---|
16+
| **Stats card** | ✅ Live | `GET /api/stats.svg?username=<user>` |
17+
| Streak | 🚧 Coming soon ||
18+
| Top Languages | 🚧 Coming soon ||
19+
| Activity Graph | 🚧 Coming soon ||
20+
21+
### Stats card
22+
23+
```
24+
https://gitwidgets.dev/api/stats.svg?username=senavictors
25+
```
26+
27+
Parameters:
28+
29+
| Param | Default | Description |
30+
|---|---|---|
31+
| `username` | required | GitHub username |
32+
| `theme` | `dark` | `dark` \| `light` \| `glass` \| `minimal` |
33+
| `hide` | `[]` | Comma-separated: `stars,commits,prs,issues,contribs` |
34+
| `show_icons` | `true` | Show stat icons |
35+
| `include_all_commits` | `false` | Count all-time commits (slower) |
36+
37+
---
38+
39+
## Delivery channels
40+
41+
### 1. Public API (zero setup)
42+
43+
Paste a URL in your README `![stats](https://gitwidgets.dev/api/stats.svg?username=yourname)`.
44+
45+
### 2. GitHub Action (self-hosted, no runtime dependency)
46+
47+
```yaml
48+
- uses: gitwidgets-org/gitwidgets@v1
49+
with:
50+
username: ${{ github.repository_owner }}
51+
github_token: ${{ secrets.GITHUB_TOKEN }}
52+
```
53+
54+
### 3. Web Dashboard
55+
56+
Visit [gitwidgets.dev](https://gitwidgets.dev) to build URLs visually and preview your widgets live.
57+
58+
---
59+
60+
## Development
61+
62+
**Requirements:** Node ≥ 20, pnpm ≥ 9
63+
64+
```bash
65+
git clone https://github.com/gitwidgets-org/gitwidgets
66+
cd gitwidgets
67+
pnpm install
68+
69+
# Run the Worker locally
70+
cd apps/api
71+
echo "GITHUB_TOKEN=ghp_..." > .dev.vars
72+
pnpm wrangler dev --local
73+
# → http://localhost:8787/api/stats.svg?username=torvalds
74+
```
75+
76+
### Common commands
77+
78+
```bash
79+
pnpm dev # start all apps in watch mode
80+
pnpm test # vitest across all packages
81+
pnpm typecheck # tsc --noEmit
82+
pnpm lint # biome lint
83+
pnpm build # turbo build (core + worker bundle)
84+
```
85+
86+
### Monorepo layout
87+
88+
```
89+
gitwidgets/
90+
├── apps/
91+
│ ├── api/ # Cloudflare Worker — public SVG API
92+
│ ├── dashboard/ # Next.js — playground and public profiles
93+
│ └── docs/ # Nextra — docs site
94+
└── packages/
95+
├── core/ # Engine — domain, renderers, fetchers, themes
96+
├── action/ # GitHub Action wrapper
97+
├── sdk/ # JS/TS SDK
98+
├── tsconfig/ # Shared TS configs
99+
└── biome-config/ # Shared Biome config
100+
```
101+
102+
All business logic lives in `packages/core`. The apps are thin shells.
103+
104+
---
105+
106+
## Architecture decisions
107+
108+
See [`docs/adr/`](docs/adr/) for the full ADR log.
109+
110+
Key decisions: Cloudflare Workers for edge rendering, Hono for the HTTP layer, SVG template strings (no WASM), `tsup` for path-alias-aware bundling. Details in [ADR-0001](docs/adr/0001-stack-decisions.md).
111+
112+
---
113+
114+
## Contributing
115+
116+
1. Fork → branch → PR against `main`
117+
2. `pnpm lint && pnpm typecheck && pnpm test` must pass
118+
3. One feature per PR; include or update tests
119+
120+
---
121+
122+
## License
123+
124+
`packages/core`, `apps/api`, `apps/docs`, `packages/action`, `packages/sdk`**MIT**
125+
`apps/dashboard`**AGPL-3.0**
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE IF NOT EXISTS github_snapshots (
2+
cache_key TEXT PRIMARY KEY,
3+
etag TEXT,
4+
data TEXT NOT NULL,
5+
fetched_at INTEGER NOT NULL
6+
);

apps/api/package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "@gitwidgets/api",
3+
"version": "0.0.0",
4+
"private": true,
5+
"license": "MIT",
6+
"type": "module",
7+
"scripts": {
8+
"dev": "wrangler dev",
9+
"build": "wrangler deploy --dry-run --outdir dist",
10+
"typecheck": "tsc --noEmit",
11+
"lint": "biome lint ./src",
12+
"format": "biome format ./src --write",
13+
"deploy:preview": "wrangler deploy --env=preview",
14+
"deploy:production": "wrangler deploy --env=production"
15+
},
16+
"dependencies": {
17+
"@gitwidgets/core": "workspace:*",
18+
"hono": "^4.6.0"
19+
},
20+
"devDependencies": {
21+
"@cloudflare/workers-types": "^4.20241218.0",
22+
"@gitwidgets/tsconfig": "workspace:*",
23+
"@gitwidgets/biome-config": "workspace:*",
24+
"typescript": "^5.7.0",
25+
"wrangler": "^3.95.0"
26+
}
27+
}

apps/api/src/env.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type Env = {
2+
RENDER_CACHE: KVNamespace;
3+
GITWIDGETS_DB: D1Database;
4+
GITHUB_TOKEN: string;
5+
};

0 commit comments

Comments
 (0)