Adds `disable_animations` to the gist card so it matches the stats,
top-languages, repo and wakatime cards.
## Changes
- `packages/core/src/cards/gist.ts`: new `disable_animations` option
(default `false`). When it is `true`, `card.disableAnimations()` is
called. The default output stays the same, with the title fade-in still
animated.
- `packages/core/src/api/gist.ts`: reads the query param and passes it
through `parseBoolean`.
- Wizard (`buildCardUrl.ts`): appends `disable_animations=true` for the
gist card when "Enable Animations?" is unchecked. `Customize.tsx` now
shows that checkbox for the gist card. All five card types now support
it, so I removed the card-type condition around the checkbox. Keeping it
would have tripped `@typescript-eslint/no-unnecessary-condition`.
- Docs: added `disable_animations` to the options table in
`gist-pin.md`.
## Tests
- `renderGistCard.test.ts`: by default the blanket `animation-duration:
0s` rule is absent, and `disable_animations: true` adds it.
- `buildCardUrl.test.ts`: the gist URL gets `disable_animations=true`
when animations are turned off.
- `gist.test.js` (backend contract): added `disable_animations: "true"`
to the many-params snapshot request. The only snapshot change is the
added rule.
- `xss.test.js`: added `disable_animations` to the gist API param list.
## Verified locally (Node 24)
- New tests before the fix: 2 failing (render + wizard URL). After the
fix, all pass.
- `pnpm run test`: 40 files, 766 tests passed
- `pnpm run lint`: ok
- `pnpm run typecheck`: ok
- `prettier --check` on the changed files: ok
Closes#614
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Adds `disable_animations` to the repo (pin) card, so it behaves like the
stats, top-languages and wakatime cards.
## One thing worth a maintainer's eye
The issue says the title animation is on today and that
`disable_animations=false` should preserve current behaviour. Those two
can't both hold: `renderRepoCard` calls `card.disableAnimations()`
unconditionally (inherited from upstream), which emits `* {
animation-duration: 0s !important; animation-delay: 0s !important; }`,
so the `.header` fade-in has never actually run. You can see the rule in
the committed `pin.test.js.snap` on master.
I went with consistency: the call is now conditional, so the default
(`false`) animates the title like the other cards, and `true` keeps the
card static. That flips two existing pin snapshots, which is the visible
part of this diff. If you'd rather keep the card static by default, it's
a one-line change to `disable_animations = true` — say the word.
## Changes
- `packages/core/src/cards/repo.ts` — new `disable_animations` option,
`card.disableAnimations()` is now conditional.
- `packages/core/src/api/pin.js` — reads the query param and passes it
through `parseBoolean`.
- `apps/frontend/src/wizard/Home/buildCardUrl.ts` +
`stages/Customize.tsx` — the existing "Enable Animations?" checkbox is
now shown for the pin card and appends the param.
- `apps/frontend/src/content/docs/docs/cards/repo-pin.md` — documented.
## Tests
- `renderRepoCard.test.ts`: two cases, default renders without the
blanket rule, `disable_animations: true` renders with it.
- `buildCardUrl.test.ts`: pin URL gets `disable_animations=true` when
animations are turned off in the wizard.
- `pin.test.js`: `disable_animations=true` added to the many-params
snapshot request, same as the stats/top-langs/wakatime contract tests
do.
## Verified
`pnpm run typecheck`, `pnpm run lint` and the full `vitest run` suite
pass locally (755 passed, 6 skipped). I had to run vitest with
`--pool=threads`; the default forks pool times out spawning workers on
my Windows box, unrelated to this change.
Closes#612
---------
Co-authored-by: qwist1233-cpu <qwist1233@users.noreply.github.com>
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
This allows for better matching misspelled language names (such as
Typescript vs TypeScript).
I also lower-cased all colours, not just some.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- use 4 parallel workers instead of 3
More PATs were added to the server recently, so no single PAT should
make too many requests to GitHub.
- Allow /api/repeat-recent to take up to 10 min.
The Vercel timeout was increased to 600 s via
https://vercel.com/docs/functions/configuring-functions/duration#dashboard.
This is a rewrite of #510 on top of the commits by luojiyin1987 so that
they are still credited as contribution.
---------
Co-authored-by: luojiyin <luojiyin@hotmail.com>
Fixes#509
## What
The five API handlers (`index`, `gist`, `pin`, `top-langs`, `wakatime`)
attach structured error details to their results while keeping the
`status` value stable:
```js
return {
status: "error - temporary",
error: describeError(err),
content: renderError({ ... }),
};
```
`describeError()` in `common/error.ts` returns `{ type?, message }`, for
example:
- `{ type: "MAX_RETRY", message: "Downtime due to GitHub API rate
limiting ..." }`
- `{ type: undefined, message: 'Missing params "username" ...' }`
## Why this shape
- `status` keeps its exact value, so the `=== "error - temporary"`
comparisons in `apps/backend/router.js` keep working. Error cache
headers (10 minutes) are unaffected.
- The npm package contract only gains an optional field, so external
callers see a backward-compatible extension.
- Unattended jobs can log `result.error.type` / `result.error.message`
to tell rate limits, token problems, network failures, and validation
errors apart.
## Tests
Full suite passes (724 tests). No snapshot changes: cache headers and
status values are identical to `master`.
Thanks to the review feedback on the first version of this PR, which
appended details to the status string and broke exact comparisons.
Dropped the unmaintained (from June 2020) and untyped `save-svg-as-png`
for `wizard/components/Card/downloadSvgAsPng.ts`:
`XMLSerializer` ➡️ data URL ➡️ `<img>` ➡️ `<canvas>` ➡️ `toBlob`.
The card SVGs are self-contained, so the library's style-inlining bought
nothing.
`Display.tsx` now reaches the card through a ref forwarded via
`CardImage` to `SvgInline`, rather than `getElementById("svg-wrapper")`.
Verified against the old library before removing it: both paths
converted the stats and repo cards at `scale: 2`, and the PNGs were
diffed pixel by pixel in Chromium (via LLM).
Dimensions match exactly; the few differing pixels are the library's,
which [copies rules matching nothing in the
SVG](https://github.com/exupero/saveSvgAsPng/blob/96484668c131d8a4babd82faa8a9d5bfdcaed64a/src/saveSvgAsPng.js#L212-L214)
out of the host page's stylesheets, and the injected font declaration
shifts the glyphs.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- Text and number fields now use daisyUI's `.input` instead of
hand-rolled Tailwind,
and `NumericSection` adds `validator` so its existing `min`/`max` show a
hint.
- Fixed two contrast bugs in `index.css`:
1. an override was suppressing daisyUI's focus ring.
2. disabled text was at 2.5:1 contrast in the light theme (now 5.3:1 /
7.4:1 dark).
- Replaced two hand-rolled pieces with what daisyUI already ships: the
delete-account
modal is a native `<dialog>` plus `.modal`, gaining Esc, focus trap and
focus restore
while dropping
- `useOutsideAlerter` hook
- `createPortal`
- `LoginBox`'s `isOpaque` prop
- The card placeholders use `.skeleton`, removing
`react-loading-skeleton`.
- The sticky card panel on steps 3 and 5 was pinned at a fixed `top-32`,
so the progress bar covered up to 57px of it.
`ProgressBar` now exposes its measured height for the panels to stack
against.
- Section controls had no accessible name:
`Section` takes a `titleId` for its heading and the five sections point
at it with `aria-labelledby`.
## Screenshots
### Card position on step 3
| Before | After |
|
------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------
|
|

|

|
### Disabled field
| Before | After |
|
------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------
|
|

|

|
### Elsewhere
| Dark theme | Delete-account dialog |
|
----------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------
|
|

|

|
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
The wizard ran the whole `apps/backend` router in the browser.
#536 added `node:crypto` to `src/common/database.js`, Vite's browser
stub for a Node builtin throws on the first named-export causing e2e
tests timeouts.
`pg` already needed a `rolldownOptions.external` escape hatch for the
same reason.
- `src/wizard/renderCard.ts` maps a card URL's pathname to the matching
`packages/core` handler and `SvgInline` calls it.
`mock-http.ts` and the the `pg` external are removed alongside backend
dependency.
Resolves the `// will be solved by npm package`
https://github.com/stats-organization/github-stats-extended/blob/2e8537db4eb6ce932b8d072f764960e436f612af/apps/frontend/src/wizard/components/Card/SvgInline.tsx#L76-L78
- ~~`e2e/stubCardApi.ts` fulfils the card endpoints, so the `Display`
stage's fetch of `https://<host>/api…` no longer logs network errors
during e2e.~~ If `process.env.STUB_CARD_API` is set, vite will now serve
a stub card. This avoids network error logs during e2e tests without the
backend server running.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- `setCSS({ light, dark })` now takes `(colors: CardColors) => string`
builders instead of CSS strings.
`Card` holds both palettes, so it calls `dark` only when it has dark
colors.
- Every card drops its `dark: darkColors ? … : null` ternary and its
`lightColors` destructuring,
each builder reads the colors of its own scheme from its parameter.
- `CardColors` moved to `common/color.ts` and is exported from there;
`Card.ts` had a duplicate 5-field copy.
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Another step of #140
- `api/gist.js` ➡️ `api/gist.ts`
- The handler parses (`parseFloat`, `parseBoolean`); the card still
defaults.
Passing `undefined` for an absent param keeps every default in one
place.
- `CommonOptions` ➡️ `CommonCardOptions`, now extending `ColorParams`
since cards spread
their options into `getLightDarkColors`.
- `locale` moved onto the four cards that read it: the gist card has no
translated text.
The gist handler no longer takes or validates it, so
`/api/gist?locale=xx` renders the card instead of "Language not found".
Docs has been updated.
- `border_radius` is now validated at the boundary: `?border_radius=abc`
returns a permanent `Invalid number input for parameter "border_radius"`
instead of a temporary error leaking `Card`'s internal `Invalid border
radius: "NaN"`.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
* Extend scripts/assert-deduped.ts to treat e.g. `2.1.0` and
`2.1.0(axios@1.18.1)` as the same version.
----
* Delayed upgrade to typescript 7, because of peer dependency issues.
* Delayed axios upgrade, because of type incompatibilities with
axios-mock-adapter.
* Upgrade axios-cache-interceptor only a bit, to stay compatible with
the unchanged axios version.
* Upgrade astro, \@astrojs/markdown-satteri and
\@astrojs/markdown-remark only a bit, because their latest versions lead
to two different versions of satteri being installed, which leads to
type conflicts.
* Delayed upgrade to graphql 17, because there we get:
<details>
<summary>error message</summary>
```txt
> @stats-organization/github-readme-stats-core@2.1.5 check-graphql-types
/home/runner/work/github-stats-extended/github-stats-extended/packages/core
> node scripts/generate-graphql-types --check
file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/graphql@17.0.2/node_modules/graphql/type/validate.mjs:36
throw new Error(errors.map((error) => error.message).join('\n\n'));
^
Error: Interface field Node.id is not deprecated, so implementation
field Project.id must not be deprecated.
Interface field Node.id is not deprecated, so implementation field
ProjectCard.id must not be deprecated.
Interface field Node.id is not deprecated, so implementation field
ProjectColumn.id must not be deprecated.
Interface field Reactable.databaseId is not deprecated, so
implementation field PullRequest.databaseId must not be deprecated.
Interface field Reactable.databaseId is not deprecated, so
implementation field PullRequestReview.databaseId must not be
deprecated.
Interface field Reactable.databaseId is not deprecated, so
implementation field PullRequestReviewComment.databaseId must not be
deprecated.
Interface field Comment.authorAssociation is not deprecated, so
implementation field TeamDiscussion.authorAssociation must not be
deprecated.
Interface field UniformResourceLocatable.resourcePath is not deprecated,
so implementation field TeamDiscussion.resourcePath must not be
deprecated.
Interface field UniformResourceLocatable.url is not deprecated, so
implementation field TeamDiscussion.url must not be deprecated.
Interface field Comment.authorAssociation is not deprecated, so
implementation field TeamDiscussionComment.authorAssociation must not be
deprecated.
Interface field UniformResourceLocatable.resourcePath is not deprecated,
so implementation field TeamDiscussionComment.resourcePath must not be
deprecated.
Interface field UniformResourceLocatable.url is not deprecated, so
implementation field TeamDiscussionComment.url must not be deprecated.
at assertValidSchema
(file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/graphql@17.0.2/node_modules/graphql/type/validate.mjs:36:15)
at validateImpl
(file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/graphql@17.0.2/node_modules/graphql/validation/validate.mjs:20:5)
at validate
(file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/graphql@17.0.2/node_modules/graphql/validation/validate.mjs:15:11)
at validateGraphQlDocuments
(file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/@graphql-tools+utils@11.2.2_graphql@17.0.2/node_modules/@graphql-tools/utils/esm/validate-documents.js:19:20)
at
file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/@graphql-codegen+core@6.2.0_graphql@17.0.2/node_modules/@graphql-codegen/core/esm/codegen.js:89:40
at
file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/@graphql-codegen+plugin-helpers@7.2.1_graphql@17.0.2/node_modules/@graphql-codegen/plugin-helpers/esm/profiler.js:5:49
at async codegen
(file:///home/runner/work/github-stats-extended/github-stats-extended/node_modules/.pnpm/@graphql-codegen+core@6.2.0_graphql@17.0.2/node_modules/@graphql-codegen/core/esm/codegen.js:76:24)
at async
file:///home/runner/work/github-stats-extended/github-stats-extended/packages/core/scripts/generate-graphql-types.js:229:21
at async Promise.all (index 0)
at async
file:///home/runner/work/github-stats-extended/github-stats-extended/packages/core/scripts/generate-graphql-types.js:227:19
Node.js v24.20.0
/home/runner/work/github-stats-extended/github-stats-extended/packages/core:
ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL
@stats-organization/github-readme-stats-core@2.1.5 check-graphql-types:
`node scripts/generate-graphql-types --check`
Exit status 1
```
</details>
- frontend: remove line break from page icon
- frontend: add `all_time_contribs` to "all stats" option
- frontend: add mock data for `all_time_contribs`
- Built on top of #531
---
- `starlight-theme.css` shrink-wraps `.card-preview-link` instead of
every `a:has(> img)`,
so links around non-card images (the Vercel deploy button on the Deploy
page) keep their prose layout.
- The walk is now two flat passes: collect every image, then rewrite
each once.
Nothing is spliced mid-iteration, so a copy the plugin adds is never
revisited.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
The Vercel function has a timeout of ca 5 min. By giving curl a bit more
time, the call should be ended by Vercel instead of curl normally. This
will turn the pipeline green.
Handle timeouts, "RESOURCE_LIMITS_EXCEEDED" type responses and empty
responses. For the first two we retry with less data; for the last we
retry 3 times.
- add `all_time_contribs` stat that shows the number of repositories a
user has contributed to across all years — not just the past year like
the default `contribs` stat.
- add parameter `contribs_include_own_repos` to include the user's own
repositories in the `contribs` and `all_time_contribs` stats. By
default, both stats exclude them and only count repositories owned by
other users or organizations.
---------
Co-authored-by: Marco Pasqualetti <24919330+marcalexiei@users.noreply.github.com>
> TL;DR: I have added the translation keys for Traditional Chinese to
ensure that the statistics card does not show error messages due to lack
of translation keys.
Now, when I set the locale to "zh-tw", the thumbnail does not show
anything, but directly tells me that the i18n key for the corresponding
language is missing.
Therefore, I created this pull request to complete the translation key
for Traditional Chinese to ensure that users can see the statistics card
normally.
<img width="591" height="137" alt="image"
src="https://github.com/user-attachments/assets/d2a6e599-2a26-4b3f-b9d9-a79ffbb8e2e0"
/>
At the same time, I also suggest that you consider setting the i18n
Fallback project, so that when the translation key is lacking, the
system will try to display the content in English (or display the
missing translation key, or use any other language).
> [!NOTE]
> Just a POC, marking as draft until #515 and #516 are merged.
- Adds `apps/frontend/src/plugins/rehypeCardImages.ts`:
a `/api` image that names no theme is emitted twice, once per site theme
— `light_github` / `dark_github` or the `*_repocard` pair.
One that names a theme is left untouched.
- Every `/api` image also gets `loading="lazy" decoding="async"`,
so the theme is not using costs no request.
- Drops the inline `<img>`/`<a>` HTML from `docs/index.md` and
`customization/theming.md`;
previews on the other docs pages became theme-aware without being
edited.
Once the other docs PRs are merged I'll rebase and apply the same change
everywhere.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- The generator writes
`apps/frontend/src/content/docs/docs/customization/themes.md`, but the
workflow still described a README.
- Renamed the workflow/job to "Generate Themes Doc" and reworded its
steps.
- PR metadata now reads `docs(frontend): update available themes page`,
branch `update_themes_doc/patch`, with the docs page linked in the body.
- Push filter also watches `scripts/generate-theme-readme.js`.
- Adds one `astro` group in `.github/dependabot.yml`
- `@astrojs/starlight` and its plugins ride along with Astro core bumps,
since a Starlight upgrade usually tracks the Astro version anyway.
Another step of #140
- `cards/wakatime.js` ➡️ `cards/wakatime.ts`
- Test and snapshot renamed to `renderWakatimeCard.test.ts` /
`renderWakatimeCard.test.ts.snap`;
the snapshot are unchanged.
- New `common/languageColors.ts` owns the language-color table:
the gist and wakatime cards repeated `(languageColors as Record<string,
string>)[name] || "#858585"` three times, and top-languages declared a
fourth copy of that hex.
They now share `getLanguageColor()` / `DEFAULT_LANG_COLOR`, and typing
the table at the import removes the cast.
- Closes#461
---
- Turns `apps/frontend` into an [Astro](https://astro.build/) +
[Starlight](https://starlight.astro.build/) site.
Serves the docs at `/frontend/docs` and the card wizard at `/frontend`:
one dev server, one build, one deploy, and no Python in
`vercel-preparation.sh` or in the local setup.
- The wizard becomes a page of that site: a React island on Starlight's
`splash` layout,
so it inherits the header, footer and search.
Its own app bar, theme picker and Redux theme slice go away.
Starlight writes the `data-theme` daisyUI already reads, so one control
themes both halves.
- The `*.md` sources move to `apps/frontend/src/content/docs/docs/` with
a `title` in
frontmatter and Starlight's `:::note` asides, which lets Astro resolve
their links and
images natively (no markdown-conversion code of our own).
`starlight-links-validator` then fails the build on a dead internal
link.
- `packages/core/src/themes/README.md` is generated into the site
instead; README and CONTRIBUTING links follow the move.
- Tailwind now shares a page with Starlight, so `index.css` declares the
cascade-layer order
(its utilities must outrank Starlight's reset) and scopes the app's
element rules under
`.wizard`, leaving the site identical on both halves.
---
To try it out just run
```sh
pnpm --filter ./apps/frontend run dev
```
---
| Wizard | Documentation |
|--------|--------|
| <img width="1710" height="666" alt="Screenshot 2026-08-17 at 00 54 18"
src="https://github.com/user-attachments/assets/c5b29e34-5464-41f3-9d01-08f593c87660"
/> | <img width="1710" height="720" alt="Screenshot 2026-08-17 at 00 54
25"
src="https://github.com/user-attachments/assets/e7e3f414-bf62-441d-9f6e-537a20044b0b"
/> |
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- `packages/core/tsconfig.json` covers `tests` but also set `outDir:
"build"`,
so a simple `tsc` emitted `build/tests`, which turbo then cached and
replayed on every later build.
- `tsconfig.base.json` now sets `noEmit: true`;
`packages/core/tsconfig.build.json` is the only config that opts back
in, and it takes the `outDir`.
- Removed `noEmit` from the typecheck and scripts configs.
- Removed `composite: true` from both apps: nothing references them as
TypeScript projects.
> [!NOTE]
> Local-only issue: CI never runs a standalone `tsc` and starts from a
clean checkout,
> so the polluted `build/` never showed up there.
- Card tests now assert with jest-dom matchers instead of reading nodes
by hand:
`toHaveTextContent`, `toHaveAttribute`, `toHaveStyle`,
`toBeInTheDocument`.
- Fixes assertions in `renderStatsCard.test.ts`:
`queryByTestId` returns `null`, so `toBeDefined()` could never fail.
One of them was checking `rank-percentile-text`, which is a CSS class
and not a test id.
- Index-existence checks became `toHaveLength(n)`;
- The five `toMatchInlineSnapshot` translation checks became explicit
`toHaveTextContent` with the same strings.
- `renderWakatimeCard.test.js` moved to the `screen` API
- `card.test.ts` uses `querySelector` over `getElementsBy*`.
Add a new optional stat for the stats card, "Total Contributions".
* I think this is something many users want. There are many issues where
people wonder why their "contributed to" or their "total commits"
doesn't match their contributions.
* This PR also introduces a way to fetch and sum stats which are only
available for 1 year at a time in the GitHub API. We could reuse this
later for more highly requested all-time stats if necessary.
I will add documentation in a separate PR.
---------
Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
Co-authored-by: Marco Pasqualetti <24919330+marcalexiei@users.noreply.github.com>
The queries moved to `src/graphql/queries/*.graphql` and their types are
generated from
GitHub's schema instead of hand-written.
- `scripts/generate-graphql-types.js` validates each query against
`@octokit/graphql-schema` and writes one file per query plus a shared
`common.ts`,
so a wrong field fails generation and a wrong variable fails `tsc`.
- `pnpm check-graphql-types` runs in CI, so the generated types can't
drift.
- `httpGraphQLRequest` takes a generated document: the four
`*QueryResponse` interfaces are gone and `GRAPHQL_REPOS_FIELD` is a real
fragment.
Untyped `request` stays exported for the backend, with a TODO for
considering its removal.
- Fixed nullability the hand-written types got wrong
- (a gist's `owner` and `files[].name`, `user`, `repositories.nodes`);
- `Lang.color` is nullable again
- `parseOwnerAffiliations` returns the schema's `RepositoryAffiliation`.
- `graphql` stays on 16: `@octokit/graphql-schema` needs `^16`.
> [!WARNING]
> The four `apps/backend` contract snapshots were refreshed:
> the recorded request text changed, the rendered SVGs did not.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Another step of #140.
- `src/cards/top-languages.js` + its test ➡️ `.ts`.
- `fetchers/types.ts`: `Lang.color` made `string | null` to match
GitHub's nullable GraphQL `Language.color`.
The card already falls back to a default and a test pass `color: null`.
- Extracted the copy-pasted "resolve + validate language color" block
into `resolveLangColor`.
- Test uses the `screen` API, caches repeated `queryAll` results in
local variables, and types its language fixtures with `satisfies
TopLangData`.
Another step of #140.
- `src/cards/stats.js` + its test ➡️ `.ts`.
- Moved `createTextNode` out of the stats card into `common/render.js`
(next to the other SVG-node builders).
It was the one card export used by another card (repo).
- `I18n` gained a default type param (usable as a bare type),
and `Card`/`createTextNode` accept the possibly-undefined options cards
forward.
- Card tests now use the `screen` API instead of
`getByTestId(document.body, …)`.
See [recommended query
entrypoint](https://testing-library.com/docs/queries/about/#screen) and
cache repeated queries in local variables.
Also applied on the already-migrated `gist`/`repo` tests.
Upgrading pnpm to version 11 led to errors on Vercel on each request.
https://github.com/stats-organization/github-stats-extended/issues/458
shows an example stack trace. Vercel doesn't support pnpm 11 yet
according to [their docs](https://vercel.com/docs/package-managers). I
have tried understanding and fixing the actual issue, but had to give up
at some point. So for now let's downgrade to pnpm 10, wait for Vercel to
support pnpm 11, then upgrade again.
Additionally, #458 showed that we should direct users to use the
`release` branch when self-hosting. So this PR also updates the docs
accordingly.
> [!NOTE]
When this PR is approved I should create an issue for the pnpm 11
upgrade.
---------
Co-authored-by: Marco Pasqualetti <24919330+marcalexiei@users.noreply.github.com>
- Bumps `packageManager` to `pnpm@11.20.0` and migrates
`onlyBuiltDependencies` to the new `allowBuilds` map.
- Adds
- `savePrefix: ""`
- `strictPeerDependencies`
- `engineStrict`
to `pnpm-workspace.yaml`.
Nothing fails today, so these only guard regressions.
- Regenerates the lockfile and dedupes.
Collapses two duplicates:
- `typescript-eslint` 8.64.0 → 8.65.0,
- `vite>lightningcss` override, guarded by a new `lint:deps` check so
the override can't silently drift.
- **axios stays on 1.18.1.** 1.19 adds a params generic that breaks 5
core tests typecheck
(https://github.com/stats-organization/github-stats-extended/pull/449).
Worth fixing in its own PR then.
Another step of #140
- `src/cards/repo.js` + its test ➡️ `.ts`
- Colocated each card's options type into its own file;
`types.ts` keeps only the shared `CommonOptions` and the options of the
js cards.
All `*CardOptions` are now `interface CardNameOptions extends
CommonOptions` (were `type` intersections).
- `fetchers/types.ts`: made `RepoInfo.description` and `primaryLanguage`
(and its fields) nullable to match the GraphQL schema.
The card already guards for these and the tests exercise them.
- `common/I18n.ts`: widened the constructor's `locale?: string` to
accept `undefined`, since cards forward possibly-undefined query
options.
Another step of #140, continues #426. Starts `cards/`.
- `src/cards/types.d.ts` ➡️ `types.ts`.
- `gist` card + test ➡️ `.ts`. Typed against `GistData` /
`Partial<GistCardOptions>`;
replaced the `// @ts-ignore` on the language-color lookup with a
`Record` cast.
- `Card.ts`: widened the constructor's `border_radius?: number` to `?:
number | undefined`:
cards forward possibly-undefined query options (same pattern as
`getCardColors`).
Needed by every card.
Follow-up to [the `themes/index.js` ➡️ `index.ts`
migration](https://github.com/stats-organization/github-stats-extended/pull/139),
which left the theme README generation pipeline pointing to files that
no longer exist.
* Renamed the workflow, script, and pnpm command to the consistent
`generate-theme-readme` (previously `generate-theme-doc` /
`theme-readme-gen`) and updated them to use the `.ts` source.
* Reduced workflow permissions from 12 declared scopes to the 2 actually
required:
* `contents: write`
* `pull-requests: write`
* Fixed the generated PR body, which incorrectly referenced language
files.
---
> [!NOTE]
> After this is merged, I'd consider applying the same permission
reduction and workflow rename to `update-langs.yml`.
- Swaps the third-party `fjogeleit/http-request-action` for a plain
`curl` step in `repeat-recent-requests.yml`:
the workflow only needs a POST with a timeout, so the action added no
value.
- The request carries only what the endpoint reads. `repeat-recent`
checks `req.method` and nothing else.
So the action's JSON body and headers were never used.
Each flag has a one-line comment explaining why it's there.
- Failure semantics are preserved: a `>= 400` status or a connection
failure still fails the job, and the response body and status are now
logged even on failure.
Example run:
https://github.com/marcalexiei/github-stats-extended/actions/runs/30751117550/job/91505220151
Related to
https://github.com/stats-organization/github-stats-extended/pull/430
> [(The failing Backend E2E test is expected, because this PR changes
the output of most cards, but in a non-visible
way.)](https://github.com/stats-organization/github-stats-extended/pull/430#issuecomment-5153247227)
- `ci.yml`: comment explaining what the job compares and why it fails.
- `CONTRIBUTING.md`: new "Tests" section, there was no testing
documentation before.
Removed the FAQ, whose three entries were all user questions, and
promoted Feature Request from `h3` to `h2`.
- `advanced_documentation`: kept the two useful FAQ answers, in context:
- language-card troubleshooting links under "Language stats algorithm",
- percent-encoding example (`&hide=jupyter%20notebook`) under "Hide
individual languages".
Demo labels changed from list items to `h4` headings: the images were
never indented into the list, so each label rendered as its own one-item
bullet.
- `deploy.md`: normalized the token-setup lists from `*` with 4 space
indents to `-` with 2 space indents.
Marker and indentation only, nesting preserved.
- `README.md`: the seven section headings were `h1`. With the HTML
`<h1>` in the banner that made eight top-level headings on one page, so
they are now `h2`.
Heading anchors are derived from the text, so the table of contents is
unaffected.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Add support for light mode and dark mode without [brittle,
GitHub-specific
approaches](https://github.com/stats-organization/github-stats-extended/blob/master/docs/advanced_documentation.md#responsive-card-theme).
All endpoints accept new parameters: theme_light, theme_dark,
title_color_light,
title_color_dark, icon_color_light, icon_color_dark, etc.
> Priority (lowest -> highest):
> default theme -> `theme` param -> `theme_light`/`theme_dark` param
> -> general color params -> `*_light`/`*_dark` color params
Additionally, this PR adds the recently introduced `progBarBgColor`
parameter to `CardColors` and handles it together with the other colors
in color.ts, for consistency. And it adds one test for an archived
repository.
This PR is already too big, so I'll add documentation in a later PR, and
maybe also a simple new option for the frontend.
My main question here is: does the API and the intended behaviour make
sense? Bugs can be fixed later, but once the new parameters are
released, ideally we shouldn't change them anymore.
---------
Co-authored-by: Marco Pasqualetti <24919330+marcalexiei@users.noreply.github.com>
Another step of #140, continues #415.
Last fetcher: `fetchers/` is now fully TS.
- `repo` fetcher + test ➡️ `.ts`.
Defines `RepoInfo` and `RepoQueryResponse`, calls
`retryer<RepoQueryResponse>(…)`
- `types.ts`: made `RepositoryData`'s PR/issue count fields optional:
they come from `fetchRepoUserStats`, which only sets them when the
matching `include_*` flag is on.
Another step of #140, continues #410.
- `stats` fetcher + test ➡️ `.ts`, threading typed GraphQL and
REST-search shapes through `retryer<…>`.
- Added a `src/_github-username-regex.d.ts` shim (package ships no
types).
- Fixed a bug caught by the types: statsFetcher expected pat in its
options object,
but the caller passed it as a second argument, so it was ignored.
Private-access users' token is now correctly passed to the main stats
query.
Another step of #140, continues #370.
- `wakatime` fetcher + test ➡️ `.ts`. Typed the props object and the
axios body (`axios.get<{ data: WakaTimeData }>`);
replaced the raw `err.response.status` access with an
`axios.isAxiosError` guard.
- `top-languages` fetcher + test ➡️ `.ts`, calling
`retryer<TopLanguagesQueryResponse>(…)`.
Split the single `let repoNodes` (reused across three shapes) into typed
values and simplified two of the three `reduce` calls (map-builder →
`for…of`, final sort ➡️ `Object.fromEntries`).
The flatten `reduce` is kept as-is — its order feeds the `repoCount`
logic.
- `types.ts`: added `count: number` to `Lang` (the fetcher always
produces it; the card only reads `name`/`color`/`size`).
* In the frontend, "Modify Parameters" step, a few options of several
dropdowns encoded multiple parameters in their value string. That didn't
work anymore since a recent change. This PR fixes the affected dropdown
options.
* Since a recent change, using the "ambient_gradient" theme for WakaTime
card didn't work anymore. This PR fixes that.
Another step of #140, continues #322.
Starts migrating `fetchers/`.
- `retryer` is now generic over the response payload:
`retryer<TData>(…)` returns `AxiosResponse<TData & ResponseErrors>` so
callers get their own `response.data` shape while the retryer still
reads `errors`/`message`.
Defaults to `unknown` so existing callers are unaffected.
- `src/fetchers/types.d.ts` ➡️ `types.ts` (references are extensionless,
so they resolve unchanged).
- `gist` fetcher + test ➡️ `.ts`, using `retryer<GistQueryResponse>(…)`.
> [!WARNING]
> Consider reviewing #375 first, as it resolves the "Resource limits for
this query exceeded" issue.
> This PR will likely conflict with it, so it's better to merge #375
first.
Load on Vercel is higher than expected. It seems the problem is that
Vercel's CDN evicts our responses before they go stale, because there
are relatively few requests per card. So the repeat-recent functionality
currently causes load without achieving much.
This PR increases ISR expiration time to see how this affects load in
practice. Setting this time via env var might be a task for later.
`HomeScreen` held ~16 separate `useState` hooks for card options and
threaded them through 34 props into `CustomizeStage`.
This consolidates them into a single typed `CardOptions` state object
(new `pages/Home/cardOptions.ts`), updated via a keyed setter.
### Changes
- `CustomizeStage` props go from 34 to 5; `buildCardUrl` takes `userId`,
`selectedCard` and `options`.
- Stage descriptions move into `STAGE_LABELS`, replacing a positional
string array in the JSX.
- The three GitHub-URL paste handlers in `CustomizeStage` share one
`pastedPathTail` helper.
- A failed OAuth `authenticate` call left the page stuck on the loading
spinner;
the exchange now runs in `try/catch/finally` and the redirect is parsed
with
`URLSearchParams` instead of substring matching.
- Related to #342
`stats` and `pin` already reject `username`/`repo`/`owner` that don't
match `safePattern` (`/^[-\w/.,]+$/`), but `top-langs`, `wakatime`, and
`gist` didn't.
This applies the same guard:
- `top-langs` + `wakatime`: reject a `username` containing unsafe
characters.
Matters most for `wakatime`, where `username` is interpolated into the
outbound request URL path.
- `gist`: same guard on its `id` param.
All three return the existing `error - permanent` card before any fetch.
## Additional change
Simplified the `layout` / `stats_format` checks in `top-langs`:
dropped the redundant `typeof x !== "string" ||` (a non-string already
fails `.includes(...)`),
keeping the `x !== undefined` guard so the params stay optional.
The advanced documentation file in the docs/ folder incorrectly links to
a nonexistent folder called "backend/" for the calculate rank logic.
This PR fixes the broken link by changing the link to
"packages/core/src/calculateRank.js".
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
* GitHub actually triggers the cron workflow every few hours. Because
they are overloaded I suppose. This PR is an attempt to give the
workflow more chances to be triggered.
* Sometimes we run into secondary rate limiting of the GitHub API when
repeating recent requests. Having less workers should fix this.
The frontend Playwright config only enables the chromium project, so CI
was needlessly downloading Firefox and WebKit.
Scope `playwright install` to `chromium` to speed up the e2e job.
Card URLs were built by hand-concatenating paths and query strings in
several places.
This replaces that with a typed, immutable per-card URL builder
(`cardUrl(cardType)`), so URLs are assembled in one place with proper
encoding.
## Changes
- New `models/CardUrl.ts`: one builder per card type, exposing only the
params that card supports.
`URLSearchParams` handles joining + encoding. Also carries a per-card
`filename()` for downloads.
- `getFullSuffix.ts` ➡️ `buildCardUrl.ts`: returns a builder instead of
a string.
- The builder is passed as a prop through all card components; no
hand-written `?`/`&` concatenation left.
- New `useCardDescriptor` hook resolves per-card display metadata (guest
hint + link) and owns the
Gist URL fetch, replacing the repeated `switch (selectedCard)` blocks in
`Home`.
- Added tests for `CardUrl`.
### Notes
- Params now go through `URLSearchParams`, so commas become `%2C` and
spaces `%20`.
The server decodes these before use, so rendered cards are unchanged.
- Builders are `useMemo`'d in `Home` to keep stable references.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
- Fixes#325
`eslint-plugin-react@7.37.5` doesn't declare support for ESLint 10,
producing an unmet-peer-dependency warning.
## Changes
- Swapped `eslint-plugin-react` ➡️ `@eslint-react/eslint-plugin` and
adopted its `recommended-typescript` config.
This also replaces `eslint-plugin-react-hooks` (the preset ships
equivalent `rules-of-hooks`/`exhaustive-deps`), so both old plugins are
removed.
- Fixed the violations the new preset surfaced:
- IIFEs-in-JSX in `Home.tsx` ➡️ lifted to `const` bindings.
- Ref naming (`*Ref`).
- 4 `set-state-in-effect` cases ➡️ rewritten as render-phase state
adjustment ([React
docs](https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)).
- Extracted the shared debounced-input logic from
`TextSection`/`NumericSection` into a `useDebouncedField` hook.
- Added a standalone Playwright spec (`e2e/app-trends-auth.spec.ts`)
covering the `AppTrends` auth-driven stage transition.
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Second wave of the `packages/core` TypeScript migration (#140),
continuing #292.
Converts the remaining `common/` modules and their tests from JSDoc
`.js` to real `.ts`.
## Changes
- **Modules ➡️ `.ts`**: `common/http`, `common/ops`, `common/render`,
`calculateRank`.
- **Tests ➡️ `.ts`**: `ops`, `flexLayout`, `render`, `calculateRank`.
- **`src/_emoji-name-map.d.ts`**: `declare module` shim.
`emoji-name-map` ships no types
and has no `@types` package (same as the existing
`@uppercod/css-to-object` shim).
- **`common/color.ts`**: widened `getCardColors` optional params to `?:
string | undefined`
so `renderError` can forward possibly-`undefined` colors under
`exactOptionalPropertyTypes`.
Adds light/dark theming to the frontend using the existing DaisyUI +
Tailwind setup.
- Theme picker dropdown in the header; selection is stored in Redux and
persisted to `localStorage`.
The toggle and each option show a sun/moon icon (shared `ThemeIcon`
component) so light/dark are easy to tell apart.
- Migrated hardcoded colors to DaisyUI tokens so the whole UI (and
toasts) follow the theme.
- `Button` now uses `variant` / `size` / `outline` props instead of raw
`btn-*` classes.
- Theme preview cards: (Select Theme grid and the final Display card)
sit on a two-tone backdrop (light or dark), chosen by the card theme so
previews stay consistent regardless of the app theme.
- Smooth theme-switch transitions: surfaces fade gently while
interactive elements stay snappy; respects `prefers-reduced-motion`.
- Added an e2e test for the picker.
<details><summary>Step 1</summary>
<p>
<img width="1710" height="811" alt="Screenshot 2026-06-24 at 06 54 40"
src="https://github.com/user-attachments/assets/38d629b5-eaa3-4fb1-b976-c56e7a840ced"
/>
<img width="1706" height="808" alt="Screenshot 2026-06-24 at 06 54 32"
src="https://github.com/user-attachments/assets/3811a574-016c-4a93-82a9-a340519f5257"
/>
</p>
</details>
<details><summary>Step 4</summary>
<p>
<img width="1709" height="899" alt="Screenshot 2026-06-24 at 06 56 22"
src="https://github.com/user-attachments/assets/4053b938-1faa-427b-b621-e79ce7b2c7b1"
/>
<img width="1705" height="894" alt="Screenshot 2026-06-24 at 06 55 41"
src="https://github.com/user-attachments/assets/8aace78a-f1ca-4d29-b57e-938f7b473e67"
/>
</p>
</details>
---------
Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
Starts migrating `packages/core` to TypeScript (#140).
- Converted the `common/` modules to `.ts`:
- `Card`, `I18n`, `color`, `config`, `constants`, `error`, `fmt`,
`html`, `icons`, `retryer`, `translations`.
- Replaced JSDoc types and `@ts-check`/`@ts-ignore` comments with real
TypeScript types.
- Enabled type-checking on the source and moved `noCheck` into the build
config.
- Converted the tests that target those modules to `.ts`:
- `fmt`, `i18n`, `card`, `color`, `html`, `retryer`.
- Converted `tests/_setup.ts` and moved the jest-dom matcher typing
there: augmenting vitest's `Matchers` interface (per the vitest docs) so
matchers like `toHaveAttribute` are typed on `expect(...)`.
- Added a `tests/css-to-object.d.ts` shim so `@uppercod/css-to-object`
resolves under `nodenext` (it ships types but doesn't expose them via
`exports`).
Bumps the typescript group with 1 update:
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).
Updates `@types/node` from 24.13.1 to 24.13.2
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the react group with 1 update in the / directory:
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react).
Updates `@types/react` from 19.2.16 to 19.2.17
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@@ -21,4 +21,4 @@ If you believe someone is violating the code of conduct, we ask that you report
- Repeated harassment of others. In general, if someone asks you to stop, then stop.
- **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
Based on the [Django Code of Conduct](https://www.djangoproject.com/conduct/).
Based on the [Django Code of Conduct](https://www.djangoproject.com/conduct/).
The easiest way to run and test the project is to deploy it to Vercel as described in the [deployment guide](../docs/deploy.md).
### Backend server
The wizard renders its previews in the browser, but the docs reference cards by
root-relative path (`/api?username=...`), so those images only load with the backend running:
```bash
pnpm run dev:backend # card endpoints on :9000, proxied by the frontend dev server
```
It needs a [Personal Access Token](https://github-stats-extended.vercel.app/frontend/docs/deploy/#first-step-get-your-personal-access-token-pat) in `apps/backend/.env` (the SQL database is optional):
```
PAT_1=your_token_here
```
You can also deploy to Vercel and test there, as described in the [deployment guide](https://github-stats-extended.vercel.app/frontend/docs/deploy/).
## Tests
```bash
pnpm run test# unit tests
pnpm run lint # eslint
pnpm run typecheck # tsc
```
The **Backend E2E test** in CI compares the cards your branch renders against the ones served by the preview deployment, which is still on the last commit merged to master.
So if your PR changes card output at all, that job goes red until the preview catches up.
It's marked `continue-on-error`, so it won't block your PR, but do open it and check the diff is only what you expected.
If the change to card markup was intentional, update the snapshots:
```bash
pnpm --filter ./packages/core/ run test:update:snapshot
pnpm --filter ./apps/backend/ run test:update:snapshot
```
## GraphQL Queries
The GraphQL queries live in `packages/core/src/graphql/queries/*.graphql`,
and their TypeScript types are generated from GitHub's published schema into `packages/core/src/graphql/generated/`.
Those generated files are committed, so if you change a query, regenerate them and include the result in your PR:
```bash
pnpm --filter ./packages/core/ run generate-graphql-types
```
CI runs `pnpm --filter ./packages/core/ run check-graphql-types`, which fails if the committed types no longer match the queries.
Never edit the generated files by hand — change the `.graphql` file and regenerate.
## Themes Contribution
We have stopped the addition of new themes to decrease maintenance efforts. If you are considering contributing your theme just because you are using it personally, then instead of adding it to our theme collection, you can use card [customization options](../docs/advanced_documentation.md#customization).
We have stopped the addition of new themes to decrease maintenance efforts. If you are considering contributing your theme just because you are using it personally, then instead of adding it to our theme collection, you can use card [customization options](https://github-stats-extended.vercel.app/frontend/docs/customization/common-options/).
## Translations Contribution
GitHub-Stats-Extended supports multiple languages. If we are missing your language, you can contribute it! You can check the currently supported languages [here](../docs/advanced_documentation.md#available-locales).
GitHub-Stats-Extended supports multiple languages. If we are missing your language, you can contribute it! You can check the currently supported languages [here](https://github-stats-extended.vercel.app/frontend/docs/customization/locales/).
To contribute your language you need to edit the [backend/src/translations.js](../backend/src/translations.js) file and add a new property to each object where the key is the language code in [ISO 639-1 standard](https://www.andiamo.co.uk/resources/iso-language-codes/) and the value is the translated string.
To contribute your language you need to edit the [packages/core/src/translations.ts](../packages/core/src/translations.ts) file and add a new property to each object where the key is the language code in [ISO 639-1 standard](https://www.andiamo.co.uk/resources/iso-language-codes/) and the value is the translated string.
## Any contributions you make will be under the MIT Software License
@@ -30,25 +77,7 @@ In short, when you submit changes, your submissions are understood to be under t
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/stats-organization/github-stats-extended/issues/new/choose). If there is already an open issue for your bug in the upstream repo [github-readme-stats](https://github.com/anuraghazra/github-readme-stats/issues) you don't need to report it here.
## Frequently Asked Questions (FAQs)
**Q:** How to hide Jupyter Notebook?
> **Ans:** &hide=jupyter%20notebook
**Q:** Language Card is incorrect
> **Ans:** Please read all the related issues/comments before opening any issues regarding language card stats:
Please report any security vulnerabilities to github.stats.extended@gmail.com. I will try to respond as quickly as possible, but since I am maintaining this project in my free time, please allow some time for a response.
Please report any security vulnerabilities to github.stats.extended@gmail.com. I will try to respond as quickly as possible, but since I am maintaining this project in my free time, please allow some time for a response.
This project is an [extended version](docs/fork.md) of [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). It generates [various stats cards](#card-types), e.g. about your GitHub contributions, your top languages, etc. You can [customize](#advanced-customization) the cards via multiple parameters.
GitHub-Stats-Extended is the [extended, actively maintained successor](https://github-stats-extended.vercel.app/frontend/docs/fork/) of [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). It generates [various stats cards](#card-types) about your GitHub contributions, your top languages and more. You can [customize](#documentation) the cards via multiple parameters.
## Table of Contents
# Table of Contents
- [Quick Start](#quick-start)
- [Migration from github-readme-stats](#migration-from-github-readme-stats)
- Change the `?username=` value to your GitHub username.
- Done!
## Quick Start
-----------------------
Copy and paste this into your markdown, then change the `?username=` value to your GitHub username:
As more comfortable alternative, use the [GitHub-Stats-Extended Wizard](https://github-stats-extended.vercel.app/frontend) to create your custom stats card. Copy the generated markdown code and paste it into your [GitHub profile README](https://docs.github.com/en/account-and-profile/how-tos/profile-customization/managing-your-profile-readme#adding-a-profile-readme). Done!
As a more comfortable alternative, use the [card wizard](https://github-stats-extended.vercel.app/frontend) to configure your card visually. Then copy the generated markdown into your [GitHub profile README](https://docs.github.com/en/account-and-profile/how-tos/profile-customization/managing-your-profile-readme#adding-a-profile-readme).
## Migration from github-readme-stats
To migrate from [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) you only need to change the domain from `github-readme-stats.vercel.app` to `github-stats-extended.vercel.app`:
GitHub-Stats-Extended aims to be fully compatible with github-readme-stats. For details see [Compatibility Notes](https://github-stats-extended.vercel.app/frontend/docs/fork/#compatibility-notes).
The [GitHub-Stats-Extended Wizard](https://github-stats-extended.vercel.app/frontend) offers some essential customization options. For more advanced customization check out the [advanced documentation](docs/advanced_documentation.md).
## Documentation
# Acknowledgements
This project is based on [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). On top of their functionality I added several new features and improvements. See [Fork Information](docs/fork.md) for a list of changes. The frontend I added to the project is based on [GitHub Trends](https://github.com/avgupta456/github-trends). Big thanks to [@anuraghazra](https://github.com/anuraghazra), [@avgupta456](https://github.com/avgupta456), [@rickstaa](https://github.com/rickstaa), [@qwerty541](https://github.com/qwerty541) and everyone else who worked on these projects! ❤️
The [card wizard](https://github-stats-extended.vercel.app/frontend) offers some essential customization options. For more advanced customization and other project info check out the [documentation](https://github-stats-extended.vercel.app/frontend/docs/cards/stats/).
# Self-Hosting
Since the GitHub API only allows a limited number of requests per hour, the public instance of GitHub-Stats-Extended at https://github-stats-extended.vercel.app/api could possibly hit the rate limiter. If you host your own instance you do not have to worry about anything. Also, if you don't want to give my GitHub-Stats-Extended instance access to your private contributions but still want to include these contributions in your stats, you can simply host your own instance.
## Acknowledgements
See [Deploy on your own](docs/deploy.md) for various deployment options.
This project is based on [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). The card wizard is based on [GitHub Trends](https://github.com/avgupta456/github-trends). Big thanks to [@anuraghazra](https://github.com/anuraghazra), [@avgupta456](https://github.com/avgupta456), [@rickstaa](https://github.com/rickstaa), [@qwerty541](https://github.com/qwerty541) and everyone else who worked on these projects! ❤️
<tspan dy="1.2em" x="25">Help us take over the world with a deeply customizable</tspan><tspan dy="1.2em" x="25">React, TypeScript and GraphQL chat app that has enough</tspan><tspan dy="1.2em" x="25">text to wrap across multiple lines in the repository card.</tspan>
"Help us take over the world with a deeply customizable React, TypeScript and GraphQL chat app that has enough text to wrap across multiple lines in the repository card.",
Starlight fixes its content collection at `src/content/docs/`, and maps that folder to the **site root** (`/frontend`), which the card wizard occupies (`src/pages/index.astro`).
The pages therefore sit one level down, in `docs/`, so they publish at `/frontend/docs/`.
Nothing else can be renamed: the outer name is Starlight's, the inner one is the URL segment.
Flattening this needs a custom `generateId` on the loader, which is the one thing `starlight-links-validator` cannot follow.
It derives valid routes from file paths, so every internal link would be reported broken.
The nesting buys build-time dead-link checking.
Starlight ignores files starting with `_`, which is why this note isn't published.
See <https://starlight.astro.build/guides/pages/#pages-from-markdown>.
You can customize the appearance and behavior of the gist card using the [common options](/frontend/docs/customization/common-options/) and exclusive options listed in the table below.
You can customize the appearance and behavior of the pinned repository card using the [common options](/frontend/docs/customization/common-options/) and exclusive options listed in the table below.
| `browser_rendering` | Compute text wrapping of repository description natively in the browser, instead of computing it server-side. | boolean | `false` |
| `description_lines_count` | Manually set the number of lines for the description. Specified value will be clamped between 1 and 3. If this parameter is not specified, the number of lines will be automatically adjusted according to the actual length of the description. | number | `null` |
| `card_width` | Sets the card's width manually. | number | `400px (approx.)` |
| `show_icons` | Shows icons near all stats enabled via `show`. | boolean | `true` |
| `line_height` | Sets the line height between stats enabled via `show`. | integer | `22` |
| `text_bold` | Uses bold text for all stats enabled via `show`. | boolean | `false` |
| `disable_animations` | Disables all animations in the card. | boolean | `true` |
| `number_format` | Switches between two available formats for displaying the numbers for all stats enabled via `show`: `short` (i.e. `6.6k`) and `long` (i.e. `6626`). | enum | `short` |
You can also specify the `repo` parameter in the form `<user_or_organization>/<repository>` to pin a repository from any user or organization, not just your own. This allows you to showcase repositories you contributed to, regardless of ownership.
The stats card shows a summary of your GitHub activity: stars earned, commits, pull requests, issues, contributions and an overall rank.
:::caution[Warning]
By default, the stats card only shows statistics like stars, commits, and pull requests from public repositories. To show private statistics on the stats card, [allow GitHub-Stats-Extended to access your private contributions](/frontend/docs/fork/#private-contributions-support) or [deploy your own instance](/frontend/docs/deploy/).
:::
:::note
Available ranks are S (top 1%), A+ (12.5%), A (25%), A- (37.5%), B+ (50%), B (62.5%), B- (75%), C+ (87.5%) and C (everyone). This ranking scheme is based on the [Japanese academic grading](https://wikipedia.org/wiki/Academic_grading_in_Japan) system. The global percentile is calculated as a weighted sum of percentiles for each statistic (number of commits, pull requests, reviews, issues, stars, and followers), based on the cumulative distribution function of the [exponential](https://wikipedia.org/wiki/exponential_distribution) and the [log-normal](https://wikipedia.org/wiki/Log-normal_distribution) distributions. The implementation can be investigated at [calculateRank.ts](https://github.com/stats-organization/github-stats-extended/blob/master/packages/core/src/calculateRank.ts). The circle around the rank shows 100 minus the global percentile.
:::
## Hiding individual stats
You can pass a query parameter `&hide=` to hide any specific stats with comma-separated values.
To compute your stats for only a specific repository, you can pass a query parameter `&repo=<user_or_organization>/<repository>`. You can also specify a comma-separated list of multiple repositories, e.g. `&repo=userA/repositoryA,organizationB/repositoryB`. And you can select all repositories owned by specific organizations or users by providing a comma-separated list of owners via the `owner` query parameter, e.g. `&owner=userA,organizationB,organizationC`. The `repo` and `owner` filters are supported by the following items: `commits` (when used with `&include_all_commits=true`), `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` and `issues_commented`. Note that most of these items are not displayed by default, but [you can enable them individually](#showing-additional-individual-stats).
(Some of these mentioned items are similar to other items which are included by default, e.g. `issues_authored` is similar to `issues`. The difference is how these values are fetched - [via GraphQL or via REST API](https://github.com/anuraghazra/github-readme-stats/discussions/1770#number-of-commits-is-incorrect). The default items use GraphQL, but filtering by repository works better via REST API.)
Alternatively, you can use the `role` parameter to specify a comma-separated list of [roles](https://docs.github.com/en/graphql/reference/repos#enum-repositoryaffiliation). The stats will include all repositories in which the user has the specified role. By default, only repositories where the user is OWNER will be included, but you could e.g. set `&role=OWNER,ORGANIZATION_MEMBER,COLLABORATOR`. The `role` parameter is supported by all items except the following: `commits` (when used with `&include_all_commits=true`), `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` and `issues_commented`.
## Showing commits count for specified year
You can specify a year and fetch only the commits that were made in that year by passing `&commits_year=YYYY` to the parameter.
You can customize the appearance and behavior of the stats card using the [common options](/frontend/docs/customization/common-options/) and the exclusive options listed in the table below.
| `hide` | Hides the [specified items](#hiding-individual-stats) from stats. | string (comma-separated values) | `null` |
| `hide_title` | Hides the title of your stats card. | boolean | `false` |
| `card_width` | Sets the card's width manually. | number | `500px (approx.)` |
| `hide_rank` | Hides the rank and automatically resizes the card width. | boolean | `false` |
| `rank_icon` | Shows alternative rank icon (i.e. `github`, `percentile` or `default`). | enum | `default` |
| `show_icons` | Shows icons near all stats. | boolean | `false` |
| `include_all_commits` | Count total commits instead of just the current year commits. | boolean | `false` |
| `line_height` | Sets the line height between text. | integer | `25` |
| `exclude_repo` | Excludes specified repositories. Affects only the count for "Total Stars Earned". | string (comma-separated values) | `null` |
| `repo` | Count only stats from the specified repositories. Affects only [certain items](#filtering-by-repository-and-owner). | string (comma-separated values) | `null` |
| `owner` | Count only stats from the specified organizations or users. Affects only [certain items](#filtering-by-repository-and-owner). | string (comma-separated values) | `null` |
| `role` | Include repositories where the user has one of the specified [roles](https://docs.github.com/en/graphql/reference/repos#enum-repositoryaffiliation) (OWNER, ORGANIZATION_MEMBER, COLLABORATOR). | string (comma-separated values) | `OWNER` |
| `custom_title` | Sets a custom title for the card. | string | `<username> GitHub Stats` |
| `disable_animations` | Disables all animations in the card. | boolean | `false` |
| `ring_color`<sup>1</sup> | Color of the rank circle. | string (hex color) | `2f80ed` |
| `number_format` | Switches between two available formats for displaying the card values: `short` (i.e. `6.6k`) and `long` (i.e. `6626`). | enum | `short` |
| `number_precision` | Enforce the number of digits after the decimal point for `short` number format. Must be an integer between 0 and 2. Will be ignored for `long` number format. | integer (0, 1 or 2) | `null` |
| `show` | Shows [additional items](#showing-additional-individual-stats) on stats card (i.e. `all_time_contribs`, `contributions`, `reviews`, `discussions_started`, `discussions_answered`, `prs_merged` or `prs_merged_percentage`. And the following, which support the `repo` and `owner` filters: `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` or `issues_commented`). | string (comma-separated values) | `null` |
| `contribs_include_own_repos` | Includes the user's own repositories when calculating the `contribs` and `all_time_contribs` stats. By default, only repositories owned by other users or organizations are counted. | boolean | `false` |
| `commits_year` | Filters and counts only commits made in the specified year. | integer _(YYYY)_ | `<current year> (one year to date)` |
<sup>1</sup>: Supports light and dark mode via `ring_color_light` and `ring_color_dark`.
:::caution[Warning]
Custom title should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) (i.e: `Anurag's GitHub Stats` should become `Anurag%27s%20GitHub%20Stats`). You can use [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically.
:::
:::note
When hide\_rank=`true`, the minimum card width is 270 px + the title length and padding.
The top languages card shows your most frequently used languages.
:::caution[Warning]
By default, the language card shows language results only from public repositories. To include languages used in private repositories, [allow GitHub-Stats-Extended to access your private contributions](/frontend/docs/fork/#private-contributions-support) or [deploy your own instance](/frontend/docs/deploy/).
:::
:::caution[Warning]
This card shows language usage only inside your own non-forked repositories, not depending on who the author of the commits is. It does not include your contributions into another users/organizations repositories. Currently there are no way to get this data from GitHub API. If you want this behavior to be improved you can support [this feature request](https://github.com/orgs/community/discussions/18230) created by [@rickstaa](https://github.com/rickstaa) inside GitHub Community.
:::
:::caution[Warning]
Currently this card shows data only about first 1000 repositories. This is because GitHub API limitations which cause downtimes of public instances (see [#1471](https://github.com/anuraghazra/github-readme-stats/issues/1471)). In future this behavior will be improved by releasing GitHub action or providing environment variables for user's own instances.
:::
## Usage
Copy-paste this code into your readme and change the links.
You can customize the appearance and behavior of the top languages card using the [common options](/frontend/docs/customization/common-options/) and exclusive options listed in the table below.
| `role` | Include repositories where the user has one of the specified [roles](https://docs.github.com/en/graphql/reference/repos#enum-repositoryaffiliation) (OWNER, ORGANIZATION_MEMBER, COLLABORATOR). | string (comma-separated values) | `OWNER` |
| `custom_title` | Sets a custom title for the card. | string | `Most Used Languages` |
| `disable_animations` | Disables all animations in the card. | boolean | `false` |
| `prog_bar_bg_color`<sup>1</sup> | Background color of the bars. (Applies only to `normal` layout.) | string (hex color) | `#ddd` |
| `hide_progress` | Uses the compact layout option, hides percentages, and removes the bars. | boolean | `false` |
| `hide_values` | Hides language percentages or bytes while keeping the progress bars or chart. | boolean | `false` |
| `size_weight` | Configures language stats algorithm (see [Language stats algorithm](#language-stats-algorithm)). | number | `1` |
| `count_weight` | Configures language stats algorithm (see [Language stats algorithm](#language-stats-algorithm)). | number | `0` |
| `stats_format` | Switches between two available formats for language's stats `percentages` and `bytes`. | enum | `percentages` |
<sup>1</sup>: Supports light and dark mode via `prog_bar_bg_color_light` and `prog_bar_bg_color_dark`.
:::caution[Warning]
Language names and custom title should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, `Most Used Languages` should become `Most%20Used%20Languages`, etc.) You can use [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically.
:::
## Language stats algorithm
We use the following algorithm to calculate the languages percentages on the language card:
By default, only the byte count is used for determining the languages percentages shown on the language card (i.e. `size_weight=1` and `count_weight=0`). You can, however, use the `&size_weight=` and `&count_weight=` options to weight the language usage calculation. The values must be positive real numbers. [More details about the algorithm can be found here](https://github.com/anuraghazra/github-readme-stats/issues/1600#issuecomment-1046056305).
-`&size_weight=1&count_weight=0` - _(default)_ Orders by byte count.
-`&size_weight=0.5&count_weight=0.5` - _(recommended)_ Uses both byte and repo count for ranking
-`&size_weight=0&count_weight=1` - Orders by repo count
Language names with spaces or symbols need to be [percent-encoded](#options), so Jupyter Notebook becomes `&hide=jupyter%20notebook` and C++ becomes `&hide=c%2B%2B`.
## Show more languages
You can use the `&langs_count=` option to increase or decrease the number of languages shown on the card. Valid values are integers between 1 and 20 (inclusive). By default it was set to `5` for `normal` & `donut` and `6` for other layouts.
The WakaTime card shows how much time you have spent coding in each language, taken from your [WakaTime](https://wakatime.com) profile.
:::caution[Warning]
Please be aware that we currently only show data from WakaTime profiles that are public. You therefore have to make sure that **BOTH**`Display code time publicly` and `Display languages, editors, os, categories publicly` are enabled.
:::
:::caution[Warning]
In case you just created a new WakaTime account, then it might take up to 24 hours until your stats will become visible on the WakaTime card.
:::
Change the `?username=` value to your WakaTime username.
You can customize the appearance and behavior of the WakaTime card using the [common options](/frontend/docs/customization/common-options/) and exclusive options listed in the table below.
| `hide` | Hides the languages specified from the card. | string (comma-separated values) | `null` |
| `hide_title` | Hides the title of your card. | boolean | `false` |
| `card_width` | Sets the card's width manually. | number | `495` |
| `line_height` | Sets the line height between text. | integer | `25` |
| `hide_progress` | Hides the progress bar and percentage. | boolean | `false` |
| `custom_title` | Sets a custom title for the card. | string | `WakaTime Stats` |
| `layout` | Switches between two available layouts `default` & `compact`. | enum | `default` |
| `langs_count` | Limits the number of languages on the card, defaults to all reported languages. | integer | `null` |
| `api_domain` | Sets a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi) | string | `wakatime.com` |
| `display_format` | Sets the WakaTime stats display format. Choose `time` to display time-based stats or `percent` to show percentages. | enum | `time` |
| `disable_animations` | Disables all animations in the card. | boolean | `false` |
:::caution[Warning]
Custom title should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) (i.e: `WakaTime Stats` should become `WakaTime%20Stats`). You can use [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically.
| `theme`<sup>1</sup> | Name of the theme, choose from [all available themes](/frontend/docs/customization/themes/). | enum | `default` |
| `cache_seconds` | Sets the cache header manually (min: 21600, max: 86400). This setting is only respected on self-hosted instances! | integer | `21600` |
| `locale` | Sets the language in the card, you can check full list of available locales [here](/frontend/docs/customization/locales/). | enum | `en` |
| `border_radius` | Corner rounding on the card. | number | `4.5` |
<sup>1</sup>: Supports light and dark mode via `*_light` / `*_dark` variants (e.g. `title_color_light`). See [Light & Dark Mode Parameters](/frontend/docs/customization/theming/#light--dark-mode-parameters) for details.
:::caution[Warning]
We use caching to decrease the load on our servers (see [this discussion](https://github.com/anuraghazra/github-readme-stats/issues/1471#issuecomment-1271551425)). Cards generated by [https://github-stats-extended.vercel.app/](https://github-stats-extended.vercel.app/frontend) are usually cached for a few days. If you need your card data to update more frequently, you can [deploy your own instance](/frontend/docs/deploy/) and set the [`CACHE_SECONDS`](/frontend/docs/deploy/#available-environment-variables) environment variable to your preferred value. Alternatively, you can use the [GitHub Actions workflow](/frontend/docs/deploy/#github-action) to update your cards on a schedule.
:::
## Gradient in bg\_color
You can provide multiple comma-separated values in the bg\_color option to render a gradient with the following format:
If we don't support your language, please consider contributing! You can find more information about how to do it in our [contributing guidelines](https://github.com/stats-organization/github-stats-extended/blob/master/.github/CONTRIBUTING.md#translations-contribution).
Use `light_github` and `dark_github` to match GitHub's own light and dark themes. For repository and gist cards use `light_github_repocard` and `dark_github_repocard`, which differ only in icon color.
:::
Preview [all available themes](/frontend/docs/customization/themes/) or read the [theme config file](https://github.com/stats-organization/github-stats-extended/blob/master/packages/core/src/themes/index.ts). We have paused the addition of new themes to reduce maintenance effort; pull requests adding one will be closed.
There are several ways to switch a card between modes on the client side.
### Use GitHub's media feature (recommended)
[GitHub's media feature](https://github.blog/changelog/2022-05-19-specify-theme-context-for-images-in-markdown-beta/) picks the image from a `<picture>` element using the `prefers-color-scheme` media query.
`theme_light` / `theme_dark` and the `*_light` / `*_dark` color parameters put both modes in a single card URL, which then follows the viewer's browser or OS setting. See [Light & Dark Mode Parameters](#light--dark-mode-parameters) for the details.
This approach is not GitHub-specific, so it also works outside GitHub — including GitHub sponsorship pages, where the other approaches don't work.
:::note
GitHub serves the card from its [CDN](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls), so a GitHub theme that differs from the browser/OS setting cannot be detected by this approach.
Appending [`#gh-dark-mode-only` or `#gh-light-mode-only`](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) to an image URL shows it only to viewers on that GitHub mode:
### Add transparent alpha channel to a themes bg\_color
Any of [the available themes](/frontend/docs/customization/themes/) turns transparent when `bg_color` carries an alpha channel (i.e. `bg_color=00000000`):

## Showing stats for a specific organization

Since the GitHub API only allows a limited number of requests per hour, my `https://github-stats-extended.vercel.app/api` could possibly hit the rate limiter. If you deploy it yourself via GitHub Actions or your own hosted instance, then you do not have to worry about anything. Also, if you don't want to give my GitHub-Stats-Extended instance access to your private contributions but still want to include these contributions in your stats, you can simply host your own instance.
We cache generated cards for a few hours or days to avoid potential rate-limiting in the GitHub API or on Vercel. If you want to set your own cache duration or you want to include private contributions in your stats without granting our hosted version of GitHub-Stats-Extended access to your private contributions, you can run GitHub-Stats-Extended on your own.
GitHub Actions is the simplest setup with static SVGs stored in your repo but less frequent updates, while self-hosting takes more work and can serve fresher stats (with caching).
GitHub Actions is the simplest setup with static SVGs stored in your repo but less frequent updates, while self-hosting GitHub-Stats-Extended on Vercel takes more work and can serve fresher stats (with caching).
## GitHub Actions
## GitHub Action
GitHub Actions generates static SVGs and avoids per-request API calls. By default it uses `GITHUB_TOKEN` (public stats only), for private stats, set a [PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) as a secret and pass it to the action instead.
With [github-readme-stats-action](https://github.com/stats-organization/github-readme-stats-action) you can generate static cards in your GitHub Actions workflow, commit them to your profile repository, and embed them directly from there. This avoids any per-request API calls.
Create `/.github/workflows/grs.yml` in your profile repo (`USERNAME/USERNAME`):
Then embed from your [profile README](https://docs.github.com/en/account-and-profile/how-tos/profile-customization/managing-your-profile-readme#adding-a-profile-readme):
```md

@@ -49,7 +55,7 @@ Then embed from your profile README:
See more options and examples in the [GitHub Readme Stats Action README](https://github.com/stats-organization/github-readme-stats-action#readme).
## Self-hosted (Vercel/Other)
## Self-hosted on Vercel
Running your own instance avoids public rate limits and gives you full control over caching, tokens, and private stats.
@@ -61,52 +67,50 @@ Selecting the right scopes for your token is important in case you want to displ
#### Classic token
* Go to [Account -> Settings -> Developer Settings -> Personal access tokens -> Tokens (classic)](https://github.com/settings/tokens).
* Click on `Generate new token -> Generate new token (classic)`.
* Scopes to select:
* repo
* read:user
* Click on `Generate token` and copy it.
- Go to [Account → Settings → Developer Settings → Personal access tokens → Tokens (classic)](https://github.com/settings/tokens).
- Click on `Generate new token → Generate new token (classic)`.
- Scopes to select:
- repo
- read:user
- Click on `Generate token` and copy it.
#### Fine-grained token
> [!WARNING]\
> This limits the scope of commits to public repositories only.
:::caution[Warning]
This limits the scope of commits to public repositories only.
:::
* Go to [Account -> Settings -> Developer Settings -> Personal access tokens -> Fine-grained tokens](https://github.com/settings/personal-access-tokens).
* Click on `Generate new token -> Generate new token`.
* Enter a token name
* Select an expiration date
* Select `All repositories`
* Scopes to select under `Permissions`:
* Commit statuses: read-only
* Contents: read-only
* Issues: read-only
* Metadata: read-only (added automatically when selecting above scopes)
* Pull requests: read-only
* Click on `Generate token` and copy it.
- Go to [Account → Settings → Developer Settings → Personal access tokens → Fine-grained tokens](https://github.com/settings/personal-access-tokens).
- Click on `Generate new token → Generate new token`.
- Enter a token name
- Select an expiration date
- Select `All repositories`
- Scopes to select under `Permissions`:
- Commit statuses: read-only
- Contents: read-only
- Issues: read-only
- Metadata: read-only (added automatically when selecting above scopes)
- Pull requests: read-only
- Click on `Generate token` and copy it.
### On Vercel
<b>:film\_projector: [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107)</b>
Click on the deploy button to get started!
[](https://vercel.com/import/project?template=https://github.com/stats-organization/github-stats-extended)
[](https://vercel.com/new/clone?repository-url=https://github.com/stats-organization/github-stats-extended&root-directory=apps/backend)
<details>
<summary><b>:hammer_and_wrench: Recommended: Step-by-step guide on setting up your own Vercel instance</b></summary>
<b>Recommended: Step-by-step guide on setting up your own Vercel instance</b>
1. Go to [vercel.com](https://vercel.com/).
2. Click on `Log in`.


3. Sign in with GitHub by pressing `Continue with GitHub`.


4. Sign in to GitHub and allow access to all repositories if prompted.
5. Fork this repo.
5. Fork this repo. Disable "Copy the `master` branch only".
6. Go back to your [Vercel dashboard](https://vercel.com/dashboard).
7. To import a project, click the `Add New...` button and select the `Project` option.


8. Search for the forked Git Repository and import it by clicking the `Import` button.
9. Create a Personal Access Token (PAT) as described in the [previous section](#first-step-get-your-personal-access-token-pat).
10. Add the PAT as an environment variable named `PAT_1` (as shown).
@@ -119,30 +123,30 @@ Click on the deploy button to get started!
3. Now you can make the variable `Sensitive` by checking the checkbox.

11. As `Root directory` select the `apps/backend` folder.
12. Click deploy, and you're good to go. See your domains to use the API!
13. optional: add an SQL database; by using e.g. the ["Nile" integration](https://vercel.com/marketplace/nile) or by manually setting the environment variable `POSTGRES_URL`
14. optional: [create your own OAuth App](https://github.com/settings/developers) and set environment variables `OAUTH_REDIRECT_URI`, `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` on Vercel accordingly
15. optional: in addition to the Vercel project based on the `apps/backend` folder, create a second project based on the `apps/frontend` folder. No environment variables needed.
16. optional: set the environment variable `TURBO_PLATFORM_ENV_DISABLED` to `true` to disable the build-time warning from [turbo](https://turborepo.dev/) about environment variables missing from "turbo.json" - This warning is not relevant in our project.
12. Click deploy.
13. Point your Vercel project at the `release` branch instead of `master`.
`master` contains unreleased, potentially unstable code, while `release` contains the latest stable release.
1. In your Vercel project settings, go to `Environments → Production` and change the tracked branch from `master` to `release`.
2. Go to `Deployments → ... → Create Deployment`, select `release` and click `Deploy to production`.
14. See your domains to use the API!
</details>
### Optional steps
### On other platforms
#### Add an SQL database
> [!WARNING]
> This way of using GitHub-Stats-Extended is not officially supported and was added to cater to some particular use cases where Vercel could not be used (e.g. [#2341](https://github.com/anuraghazra/github-readme-stats/discussions/2341)). The support for this method, therefore, is limited.
Add an SQL database, either through an integration such as ["Nile"](https://vercel.com/marketplace/nile), or by manually setting the environment variable `POSTGRES_URL`.
<details>
<summary><b>:hammer_and_wrench: Step-by-step guide for deploying on other platforms</b></summary>
#### Increase Vercel's function timeout
1. Fork or clone this repo as per your needs
2. Move `express` from the devDependencies to the dependencies section of `package.json`
If you handle a large number of requests, the `/api/repeat-recent` endpoint may time out. By default, Vercel limits serverless functions to 5 minutes. You can [increase this limit](https://vercel.com/docs/functions/configuring-functions/duration#dashboard) in Vercel's dashboard. Note that this [requires](https://vercel.com/docs/functions/limitations#max-duration) a "Pro" or "Enterprise" plan.
#### Use your own OAuth App
[Create your own OAuth App](https://github.com/settings/developers) and set the environment variables `OAUTH_REDIRECT_URI`, `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` on Vercel accordingly.
#### Silence the turbo build warning
Set the environment variable `TURBO_PLATFORM_ENV_DISABLED` to `true` to disable the build-time warning from [turbo](https://turborepo.dev/) about environment variables missing from `turbo.json`. This warning is not relevant in our project.
### Available environment variables
@@ -164,12 +168,12 @@ GitHub Stats Extended provides several environment variables that can be used to
</tr>
<tr>
<td><code>UPDATE_AFTER_HOURS</code></td>
<td>Sets the duration in hours after which the server <a href="fork.md#improved-performance-and-latency">proactively regenerates</a> a previously requested card. Defaults to 11 hours.</td>
<td>Sets the duration in hours after which the server <a href="/frontend/docs/fork/#improved-performance-and-latency">proactively regenerates</a> a previously requested card. Defaults to 11 hours.</td>
<td>Any int or float</td>
</tr>
<tr>
<td><code>DELETE_AFTER_HOURS</code></td>
<td>Sets the duration in hours after which the server stops <a href="fork.md#improved-performance-and-latency">proactively regenerating</a> a previously requested card if it hasn't been requested again in the meantime. Defaults to 8 days, i.e. 192 hours.</td>
<td>Sets the duration in hours after which the server stops <a href="/frontend/docs/fork/#improved-performance-and-latency">proactively regenerating</a> a previously requested card if it hasn't been requested again in the meantime. Defaults to 8 days, i.e. 192 hours.</td>
<td>Any int or float</td>
</tr>
<tr>
@@ -197,11 +201,12 @@ GitHub Stats Extended provides several environment variables that can be used to
See [the Vercel documentation](https://vercel.com/docs/concepts/projects/environment-variables) on adding these environment variables to your Vercel instance.
> [!WARNING]
> Please remember to redeploy your instance after making any changes to the environment variables so that the updates take effect. The changes will not be applied to the previous deployments.
:::caution[Warning]
Please remember to redeploy your instance after making any changes to the environment variables so that the updates take effect. The changes will not be applied to the previous deployments.
:::
### Keep your fork up to date
You can keep your fork, and thus your private Vercel instance up to date with the upstream using GitHub's [Sync Fork button](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork). You can also use the [pull](https://github.com/wei/pull) package created by [@wei](https://github.com/wei) to automate this process.
As a prerequisite, GitHub has to know that your personal GitHub-Stats-Extended repo is a fork of https://github.com/stats-organization/github-stats-extended. This only works if you follow the "Step-by-step guide on setting up your own Vercel instance" above, instead of clicking the Vercel "Deploy" button above.
As a prerequisite, GitHub has to know that your personal GitHub-Stats-Extended repo is a fork of https://github.com/stats-organization/github-stats-extended. This only works if you follow the "Step-by-step guide on setting up your own Vercel instance" above, instead of clicking the Vercel "Deploy" button above.
This project is an actively maintained fork and extension of [github-readme-stats](https://github.com/anuraghazra/github-readme-stats).
## Key Differences
Compared to [github-readme-stats](https://github.com/anuraghazra/github-readme-stats), this project adds the following changes:
### Frontend for easy, visual configuration of cards
GitHub-Stats-Extended adds a frontend which allows users to visually configure stats cards. It is hosted at https://github-stats-extended.vercel.app/frontend.

The frontend is based on [GitHub Trends](https://github.com/avgupta456/github-trends) by [@avgupta456](https://github.com/avgupta456).
### Aggregate stats across organizations
To include stars from repos which are not owned by you, but where you are a collaborator or organization member, add `&role=OWNER,ORGANIZATION_MEMBER,COLLABORATOR` to your stats card url. To include such repos in your language stats, you can also add the same parameter to your top languages card url.
See [here](/frontend/docs/cards/stats/#filtering-by-repository-and-owner) for full feature documentation.
The resolution of this most requested feature in github-readme-stats was [originally implemented](https://github.com/anuraghazra/github-readme-stats/issues/1#issuecomment-855681098) by [@developStorm](https://github.com/developStorm).
### Improved performance and latency
GitHub-Stats-Extended proactively precomputes and caches cards. This solves the problem where [cards wouldn't load on the first try](https://github.com/anuraghazra/github-readme-stats/issues/2603). It also gives GitHub-Stats-Extended more time while generating cards in the background, which allows it to fetch more repo data:
### Multi-page fetching for accurate star counts
GitHub-Stats-Extended fetches up to 1000 of your starred repositories to accurately compute your stars count. In github-readme-stats, this is limited to 100 repos because github-readme-stats doesn't have the above-mentioned performance improvements.
### Light and dark mode in a single card URL
GitHub-Stats-Extended adds parameters `theme_light`, `theme_dark` and the `*_light` / `*_dark` color variants (e.g. `title_color_light`), to specify both modes in one card URL. The card then follows the viewer's browser or OS setting.
It works everywhere, including GitHub sponsorship pages, where the other light/dark approaches do not. See [Set light and dark mode in one card](/frontend/docs/customization/theming/#set-light-and-dark-mode-in-one-card) for the details.
### GitHub-themed light and dark themes
GitHub-Stats-Extended adds `light_github` and `dark_github` [themes](/frontend/docs/customization/themes/) that exactly match GitHub's own UI colors. For repo and gist cards use `light_github_repocard` and `dark_github_repocard`, which differ only in icon color.
### New contributions stat
GitHub-Stats-Extended adds an optional stat showing the number of [contributions](https://docs.github.com/en/account-and-profile/reference/profile-contributions-reference#what-counts-as-a-contribution) (commits, pull requests, issues, etc.) across all years of a user's history. Enable it with `&show=contributions`. Whether private contributions are counted depends on [your profile visibility settings](https://docs.github.com/en/account-and-profile/how-tos/contribution-settings/manage-visibility-settings-for-private-contributions-and-achievements#changing-the-visibility-of-your-private-contributions).
:::note
The pre-existing "Contributed to" stat counts repositories a user has contributed to, not contributions.
:::
### New options for "contributed-to" stats
GitHub-Stats-Extended adds an `all_time_contribs` stat that shows the number of repositories a user has contributed to across all years — not just the past year like the default `contribs` stat.
Enable it with [`&show=all_time_contribs`](/frontend/docs/cards/stats/#showing-additional-individual-stats).
GitHub-Stats-Extended also adds a parameter [`contribs_include_own_repos`](/frontend/docs/cards/stats/#options) to include the user's own repositories in the `contribs` and `all_time_contribs` stats.
By default, both stats exclude them and only count repositories owned by other users or organizations.
### Customization of top languages card
GitHub-Stats-Extended can show your top languages without any numbers via the `hide_values` parameter. And the new `prog_bar_bg_color` parameter sets the background color of progress bars, e.g. to transparent:

### Private contributions support
GitHub-Stats-Extended can include private contributions in your stats cards. You no longer have to deploy your own instance for that. Just log into the [GitHub-Stats-Extended Wizard](/frontend) via the "GitHub Private Access" button (or click "Upgrade to Private Access" if already logged in). This will allow GitHub-Stats-Extended to see your private contributions.
### Display contributions to specific repositories or organizations
GitHub-Stats-Extended adds the ability to show contribution stats for specific repositories and organizations.
Especially for regular contributors in open source projects it might make sense to display an overview of their own contributions to these projects on their GitHub profile.
See [here](/frontend/docs/cards/stats/#filtering-by-repository-and-owner) for full feature documentation.
---
Anuraghazra's contributions to github-readme-stats:

Add `&show=prs_authored,prs_commented,prs_reviewed,issues_authored,issues_commented` to your repo card url to display your contributions to the pinned repository.
---
Anuraghazra's contributions to razorpay:

Add `&repo=userA/repoA,orgB/repoB` or `&owner=userC,orgD` to your profile stats url to filter your contributions by repo or organization. (The screenshot above uses further customization options.)
### Other
GitHub-Stats-Extended adds various other, minor improvements. For example, the repo card now supports the `card_width` parameter.
## Why This Fork Exists
[github-readme-stats](https://github.com/anuraghazra/github-readme-stats) is a great project, which unfortunately saw its development slow down in the past years, with [highly requested features](https://github.com/anuraghazra/github-readme-stats/issues/1935) getting delayed for a long time.
One of the valued maintainers [wrote](https://github.com/anuraghazra/github-readme-stats/pull/3911#issuecomment-3377726545):
> I joined the project as collaborator in the middle of 2023 and there was just a few guys in the team while hundreds of PRs, issues and discussions pending to be reviewed.
>
> The volume is overwhelming for the small team, especially taking into account that right now I'm alone online and working only sometimes when I have a free hours, so it took some time to get to your PR.
So [@martin-mfg](https://github.com/martin-mfg) decided to fork the project, implement some of the highly requested features and make the enhanced project available to everyone. Since the initial release of this fork @martin-mfg joined forces with the maintainers of [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) and GitHub-Stats-Extended is now becoming the successor of github-readme-stats.
## Compatibility Notes
GitHub-Stats-Extended aims to be fully compatible with [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). Additional functionality introduced in this fork has to be explicitly enabled via some parameter.
So you can change an existing stats card url from [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) to GitHub-Stats-Extended simply by changing the domain from `github-readme-stats.vercel.app` to `github-stats-extended.vercel.app`. The card will look the same.
There is only one exception to this: GitHub-Stats-Extended improves line wrapping for multi-line gist and repository descriptions.
This should be an improvement for existing cards, but it still changes their appearance a bit.
Previously, line wrapping happened simply after 59 characters, with special handling for Chinese characters:
GitHub-Stats-Extended is the [extended, actively maintained successor](/frontend/docs/fork/) of [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). It generates [various stats cards](#card-types) about your GitHub contributions, your top languages and more. You can [customize](/frontend/docs/customization/common-options/) the cards via multiple parameters.
## Quick Start
Copy and paste this into your markdown, then change the `?username=` value to your GitHub username:
As a more comfortable alternative, use the [card wizard](/frontend) to configure your card visually. Then copy the generated markdown into your [GitHub profile README](https://docs.github.com/en/account-and-profile/how-tos/profile-customization/managing-your-profile-readme#adding-a-profile-readme).
## Migration from github-readme-stats
To migrate from [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) you only need to change the domain from `github-readme-stats.vercel.app` to `github-stats-extended.vercel.app`:
GitHub-Stats-Extended aims to be fully compatible with github-readme-stats. For details see [Compatibility Notes](/frontend/docs/fork/#compatibility-notes).
- [Cards](/frontend/docs/cards/stats/) — the options each card accepts.
- [Customization](/frontend/docs/customization/common-options/) — options every card shares, plus theming and locales.
- [Available Themes](/frontend/docs/customization/themes/) — the built-in themes, rendered as live examples.
- [Run It Yourself](/frontend/docs/deploy/) — GitHub Actions or a self-hosted Vercel deployment.
- [Fork Information](/frontend/docs/fork/) — what this project adds on top of github-readme-stats.
## Acknowledgements
This project is based on [github-readme-stats](https://github.com/anuraghazra/github-readme-stats). The card wizard is based on [GitHub Trends](https://github.com/avgupta456/github-trends). Big thanks to [@anuraghazra](https://github.com/anuraghazra), [@avgupta456](https://github.com/avgupta456), [@rickstaa](https://github.com/rickstaa), [@qwerty541](https://github.com/qwerty541) and everyone else who worked on these projects! ❤️
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.