diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d3ecf0fa..9375a5e1 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -9,7 +9,7 @@ assignees: ""
**Describe the bug**
A clear and concise description of what the bug is.
-**Expected behavior**
+**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots / Live demo link (paste the github-readme-stats link as markdown image)**
@@ -20,7 +20,10 @@ Add any other context about the problem here.
diff --git a/.gitignore b/.gitignore
index 1c96025a..835034e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@ package-lock.json
coverage
vercel_token
+# IDE
+.vscode
+*.code-workspace
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 35bfdbd1..0d4b558a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,50 +2,50 @@
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
-- Reporting a issue
-- Discussing the current state of the code
-- Submitting a fix
-- Proposing new features
-- Becoming a maintainer
+- Reporting an issue
+- Discussing the current state of the code
+- Submitting a fix
+- Proposing new features
+- Becoming a maintainer
## All Changes Happen Through Pull Requests
Pull requests are the best way to propose changes. We actively welcome your pull requests:
-1. Fork the repo and create your branch from `master`.
-1. If you've added code that should be tested, add some tests' example.
-1. If you've changed APIs, update the documentation.
-1. Issue that pull request!
+1. Fork the repo and create your branch from `master`.
+2. If you've added code that should be tested, add some tests' examples.
+3. If you've changed APIs, update the documentation.
+4. Issue that pull request!
## Under the hood of github-readme-stats
-Interested in diving deeper into understanding how github-readme-stats works?
+Interested in diving deeper into understanding how github-readme-stats works?
-[Bohdan](https://github.com/Bogdan-Lyashenko) wrote an amazing in-depth post about it, check it out:
+[Bohdan](https://github.com/Bogdan-Lyashenko) wrote a fantastic in-depth post about it, check it out:
**[Under the hood of github-readme-stats project](https://codecrumbs.io/library/github-readme-stats)**
-
## Local Development
-To run & test github-readme-stats you need to follow few simple steps :-
-_(make sure you already have a [vercel](https://vercel.com/) account)_
+To run & test github-readme-stats, you need to follow a few simple steps:-
+_(make sure you already have a [Vercel](https://vercel.com/) account)_
-1. Install [Vercel CLI](https://vercel.com/download)
-1. Fork the repository and clone the code to your local machine
-1. Run `npm install` in the repository root
-1. Run the command "vercel" in the root and follow the steps there
-1. Create a `.env` file in the root of the directory
-1. In the .env file add a new variable named "PAT_1" with your [github Personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
-1. Run the command "vercel dev" to start a development server at https://localhost:3000
+1. Install [Vercel CLI](https://vercel.com/download).
+2. Fork the repository and clone the code to your local machine.
+3. Run `npm install` in the repository root.
+4. Run the command "vercel" in the root and follow the steps there.
+5. Open `vercel.json` and set the maxDuration to 10.
+6. Create a `.env` file in the root of the directory.
+7. In the .env file add a new variable named "PAT_1" with your [GitHub Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
+8. Run the command "vercel dev" to start a development server at .
## Themes Contribution
-GitHub Readme Stats supports custom theming and you can also contribute new themes!
+GitHub Readme Stats supports custom theming, and you can also contribute new themes!
-All you need to do is edit [themes/index.js](./themes/index.js) file and add your theme at the end of the file.
+All you need to do is edit the [themes/index.js](./themes/index.js) file and add your theme at the end of the file.
-While creating the Pull request to add a new theme **don't forget to add a screenshot of how your theme looks**, you can also test how it looks using custom url parameters like `title_color`, `icon_color`, `bg_color`, `text_color`, `border_color`
+While creating the Pull request to add a new theme **don't forget to add a screenshot of how your theme looks**, you can also test how it looks using custom URL parameters like `title_color`, `icon_color`, `bg_color`, `text_color`, `border_color`
> NOTE: If you are contributing your theme just because you are using it personally, then you can [customize the looks](./readme.md#customization) of your card with URL params instead.
@@ -59,24 +59,24 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue]
## Frequently Asked Questions (FAQs)
-**Q:** How to hide jupyter Notebook?
+**Q:** How to hide Jupyter Notebook?
> **Ans:** &hide=jupyter%20notebook
-**Q:** I could not figure out how to deploy on my own vercel instance
+**Q:** I could not figure out how to deploy on my own Vercel instance
> **Ans:**
>
-> - docs: https://github.com/anuraghazra/github-readme-stats/#deploy-on-your-own-vercel-instance
-> - YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
+> - docs:
+> - YT tutorial by codeSTACKr:
**Q:** Language Card is incorrect
-> **Ans:** Please read all the related issues / comments before opening any issues regarding language card stats:
+> **Ans:** Please read all the related issues/comments before opening any issues regarding language card stats:
>
-> - https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665164174
+> -
>
-> - https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181
+> -
**Q:** How to count private stats?
@@ -86,14 +86,14 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue]
**Great Bug Reports** tend to have:
-- A quick summary and/or background
-- Steps to reproduce
- - Be specific!
- - Share the snapshot, if possible.
- - GitHub Readme Stats' live link
-- What actually happens
-- What you expected would happen
-- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
+- A quick summary and/or background
+- Steps to reproduce
+ - Be specific!
+ - Share the snapshot, if possible.
+ - GitHub Readme Stats' live link
+- What actually happens
+- What you expected would happen
+- Notes (possibly including why you think this might be happening or stuff you tried that didn't work)
People _love_ thorough bug reports. I'm not even kidding.
@@ -101,9 +101,9 @@ People _love_ thorough bug reports. I'm not even kidding.
**Great Feature Requests** tend to have:
-- A quick idea summary
-- What & why you wanted to add the specific feature
-- Additional Context like images, links to resources to implement the feature etc etc.
+- A quick idea summary
+- What & why do you want to add the specific feature
+- Additional context like images, links to resources to implement the feature, etc.
## License
diff --git a/api/index.js b/api/index.js
index 8d50f600..e5dd0ff3 100644
--- a/api/index.js
+++ b/api/index.js
@@ -54,8 +54,8 @@ module.exports = async (req, res) => {
);
const cacheSeconds = clampValue(
- parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),
- CONSTANTS.TWO_HOURS,
+ parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
+ CONSTANTS.FOUR_HOURS,
CONSTANTS.ONE_DAY,
);
diff --git a/api/pin.js b/api/pin.js
index 1df7fd07..f2761cb6 100644
--- a/api/pin.js
+++ b/api/pin.js
@@ -41,16 +41,16 @@ module.exports = async (req, res) => {
const repoData = await fetchRepo(username, repo);
let cacheSeconds = clampValue(
- parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),
- CONSTANTS.TWO_HOURS,
+ parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
+ CONSTANTS.FOUR_HOURS,
CONSTANTS.ONE_DAY,
);
/*
- if star count & fork count is over 1k then we are kFormating the text
- and if both are zero we are not showing the stats
- so we can just make the cache longer, since there is no need to frequent updates
- */
+ if star count & fork count is over 1k then we are kFormating the text
+ and if both are zero we are not showing the stats
+ so we can just make the cache longer, since there is no need to frequent updates
+ */
const stars = repoData.starCount;
const forks = repoData.forkCount;
const isBothOver1K = stars > 1000 && forks > 1000;
diff --git a/api/top-langs.js b/api/top-langs.js
index 068745d9..82635f39 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -50,8 +50,8 @@ module.exports = async (req, res) => {
);
const cacheSeconds = clampValue(
- parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),
- CONSTANTS.TWO_HOURS,
+ parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
+ CONSTANTS.FOUR_HOURS,
CONSTANTS.ONE_DAY,
);
diff --git a/api/wakatime.js b/api/wakatime.js
index d585c4a0..18b52189 100644
--- a/api/wakatime.js
+++ b/api/wakatime.js
@@ -44,8 +44,8 @@ module.exports = async (req, res) => {
const stats = await fetchWakatimeStats({ username, api_domain, range });
let cacheSeconds = clampValue(
- parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),
- CONSTANTS.TWO_HOURS,
+ parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
+ CONSTANTS.FOUR_HOURS,
CONSTANTS.ONE_DAY,
);
diff --git a/docs/readme_cn.md b/docs/readme_cn.md
index 36a5ff93..17fd2b71 100644
--- a/docs/readme_cn.md
+++ b/docs/readme_cn.md
@@ -290,7 +290,7 @@ _注意:热门语言并不表示我的技能水平或类似的水平,它是
你通常无法将图片靠边显示。为此,您可以使用以下方法:
-```md
+```html
diff --git a/docs/readme_de.md b/docs/readme_de.md
index aa0769c3..55523fe3 100644
--- a/docs/readme_de.md
+++ b/docs/readme_de.md
@@ -71,7 +71,7 @@
# GitHub Statistiken-Karte
Kopiere folgendes in deine Readme um die Statistiken zu benutzen.
-Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub Nutzername steht.
+Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub-Nutzername steht.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -91,7 +91,7 @@ Um eine spezifische Statistik auszublenden, kann dem Query-Parameter `?hide=` ei
### Symbole anzeigen
-Um Symbole anzuzeigen kann der URL-Paramter `show_icons=true` wie folgt verwendet werden:
+Um Symbole anzuzeigen kann der URL-Parameter `show_icons=true` wie folgt verwendet werden:
```md

@@ -139,11 +139,11 @@ Du kannst mehrere, mit Kommas separierte, Werte in der bg_color Option angeben,
&bg_color=WINKEL,FARBE1,FARBE2,FARBE3...FARBE10
```
-> Hinweis bzgl. des Caches: Wenn die Anzahl der Forks und Stars geringer als 1 Tsd ist, haben die Repo-Cards eine Standard-Cachezeit von 30 Minuten (1800 Sekunden), ansonsten beträgt diese 2 Stunden (7200 Sekunden). Außerdem ist der Cache auf ein Minimum von 30 Minuten und ein Maximum von 24 Stunden begrenzt.
+> Hinweis bzgl. des Caches: Wenn die Anzahl der Forks und Stars geringer als 1 Tsd. ist, haben die Repo-Cards eine Standard-Cachezeit von 30 Minuten (1800 Sekunden), ansonsten beträgt diese 2 Stunden (7200 Sekunden). Außerdem ist der Cache auf ein Minimum von 30 Minuten und ein Maximum von 24 Stunden begrenzt.
#### Exklusive Optionen der Statistiken-Karte:
-- `hide` - Verbirgt die angegeben Elemente _(mit Komma abgegrenzte Werte)_
+- `hide` - Verbirgt die [angegeben Elemente](#verbergen-individueller-statistiken) _(mit Komma abgegrenzte Werte)_
- `hide_title` - _(Boolean)_
- `hide_rank` - _(Boolean)_
- `show_icons` - _(Boolean)_
@@ -170,12 +170,12 @@ Du kannst mehrere, mit Kommas separierte, Werte in der bg_color Option angeben,
- `hide_title` - _(Boolean)_
- `line_height` - Legt die Zeilenhöhe des Texts fest _(Zahl)_
-- `hide_progress` - Verbirgt die Fortschrittanzeige und Prozentzahl _(Boolean)_
+- `hide_progress` - Verbirgt die Fortschrittsanzeige und Prozentzahl _(Boolean)_
- `custom_title` - Legt einen benutzerdefinierten Titel fest
- `layout` - Wechselt zwischen zwei verschiedenen Layouts: `default` & `compact`
- `langs_count` - Begrenzt die Anzahl der angezeigten Sprachen auf der Karte
- `api_domain` - Legt eine benutzerdefinierte API Domain fest, z.B. für [Hakatime](https://github.com/mujx/hakatime) oder [Wakapi](https://github.com/muety/wakapi)
-- `range` – Fragt eine eine Zeitspanne an, als die standardmäßig in WakaTime hinterlegte, z.B. `last_7_days`. Siehe [WakaTime API Dokumentation](https://wakatime.com/developers#stats).
+- `range` – Fragt eine andere Zeitspanne an, als jene, welche standardmäßig in Wakatime hinterlegt ist. Zum Beispiel `last_7_days`. Siehe [WakaTime API Dokumentation](https://wakatime.com/developers#stats).
---
@@ -188,7 +188,7 @@ Und Bääm! Du bist nicht mehr auf 6 angeheftete Repositories limitiert.
### Benutzung
Füge diesen Code in deine Readme-Datei ein und passe die Links an.
-Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub Nutzername steht.
+Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub-Nutzername steht.
Den Wert des URL-Parameters `?repo=` musst du so anpassen, dass dort der Namen deines Repositorys steht.
Endpunkt: `api/pin?username=anuraghazra&repo=github-readme-stats`
@@ -201,7 +201,7 @@ Endpunkt: `api/pin?username=anuraghazra&repo=github-readme-stats`
[](https://github.com/anuraghazra/github-readme-stats)
-Benutze die [show_owner](#anpassungenpersonalisierung) Variable, um den Nutzernamen des Repo Eigentümers anzuzeigen.
+Benutze die [show_owner](#anpassungenpersonalisierung) Variable, um den Nutzernamen des Repository-Eigentümers anzuzeigen.
[](https://github.com/anuraghazra/github-readme-stats)
@@ -214,7 +214,7 @@ _HINWEIS: Die Top Programmiersprachen treffen keine Aussage über persönliche F
### Benutzung
Füge diesen Code in deine Readme-Datei ein und passe die Links an.
-Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub Nutzername steht.
+Passe den Wert des URL-Parameters `?username=` so an, dass dort dein GitHub-Nutzername steht.
Endpunkt: `api/top-langs?username=anuraghazra`
@@ -232,7 +232,7 @@ Du kannst den `?hide=language1,language2` URL-Parameter benutzen, um einzelne Sp
### Kompaktes Sprachen-Karte Layout
-Du kannst die `&layout=compact` Option nutzen, um das Karten Design zu ändern.
+Du kannst die `&layout=compact` Option nutzen, um das Kartendesign zu ändern.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -248,7 +248,7 @@ Du kannst die `&layout=compact` Option nutzen, um das Karten Design zu ändern.
# Wakatime Wochen-Statistik
-Ändere `?username=` in den eigenen [Wakatime](https://wakatime.com) Benutzernamen.
+Ändere `?username=` in den eigenen [Wakatime](https://wakatime.com)-Benutzernamen.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -312,7 +312,7 @@ Wähle Eines von den [Standard-Themes](#themes)
Üblicherweise ist es in `.md`-Dateien nicht möglich Bilder nebeneinander anzuzeigen. Um dies zu ermöglichen, kannst du folgendes tun:
-```md
+```html
@@ -325,7 +325,7 @@ Wähle Eines von den [Standard-Themes](#themes)
#### [Schritt für Schritt YouTube Tutorial by @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107)
-Da die GitHub API nur 5 Tsd Aufrufe pro Stunde zulässt, kann es passieren, dass meine `https://github-readme-stats.vercel.app/api` dieses Limit erreicht.
+Da die GitHub API nur 5 Tsd. Aufrufe pro Stunde zulässt, kann es passieren, dass meine `https://github-readme-stats.vercel.app/api` dieses Limit erreicht.
Wenn du es auf deinem eigenen Vercel-Server hostest, brauchst du dich darum nicht zu kümmern. Klicke auf den Deploy-Knopf um loszulegen!
Hinweis: Seit [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) sollte es möglich sein, mehr als 5 Tsd Aufrufe pro Stunde ohne Downtimes zu verkraften :D
@@ -349,7 +349,7 @@ Hinweis: Seit [#58](https://github.com/anuraghazra/github-readme-stats/pull/58)

1. Wähle root und füge eine Umgebungsvariable namens PAT_1 (siehe Abbildung) die als Wert deinen persönlichen Access Token (PAT) hat hinzu, den du einfach [hier](https://github.com/settings/tokens/new) erzeugen kannst (lasse alles wie es ist, vergebe einen beliebigen Namen)

-1. Klicke deploy, und das wars. Besuche deine Domains um die API zu benutzen!
+1. Klicke auf `Deploy`, und das wars. Besuche deine Domains um die API zu benutzen!
## :sparkling_heart: Unterstütze das Projekt
diff --git a/docs/readme_es.md b/docs/readme_es.md
index b35e89c1..5ddceec7 100644
--- a/docs/readme_es.md
+++ b/docs/readme_es.md
@@ -157,7 +157,7 @@ Puedes pasar mútliples valores separados por coma en la opción `bg_color` para
#### Opciones exclusivas de la Tarjeta de Estadísticas:
-- `hide` - Oculta de las estadísticas los elementos especificados _ (valores separados por comas) _
+- `hide` - Oculta de las estadísticas [los elementos especificados](#ocultar-estadísticas-individualmente) _(valores separados por comas)_
- `hide_title` - _(booleano)_
- `hide_rank` - _(booleano)_
- `show_icons` - _(booleano)_
@@ -351,7 +351,7 @@ Escoja cualquiera de los [temas por defecto](#themes)
Por lo general, no podrás acomodar las imágenes una al lado de la otra. Para hacerlo, puede usar este enfoque:
-```md
+```html
diff --git a/docs/readme_fr.md b/docs/readme_fr.md
index d69c39b7..20996bd6 100644
--- a/docs/readme_fr.md
+++ b/docs/readme_fr.md
@@ -153,7 +153,7 @@ Vous pouvez fournir plusieurs valeurs (suivie d'une virgule) dans l'option bg_co
#### Stats Card Exclusive Options:
-- `hide` - Masquer les éléments spécifiés dans les statistiques _(Comma seperated values)_
+- `hide` - Masquer [les éléments spécifiés](#cacher-les-statistiques-individuelles) dans les statistiques _(Comma seperated values)_
- `hide_title` - Masquer le titre _(boolean)_
- `hide_rank` - Masquer le rang _(boolean)_
- `show_icons` - Afficher les icônes _(boolean)_
@@ -290,7 +290,7 @@ Choisissez parmi l'un des [thèmes par défaut](#themes)
En général, vous ne pourrez pas mettre les images côte à côte. Pour ce faire, vous pouvez utiliser cette approche :
-```md
+```html
diff --git a/docs/readme_it.md b/docs/readme_it.md
index 8ba49435..1b2df96a 100644
--- a/docs/readme_it.md
+++ b/docs/readme_it.md
@@ -288,7 +288,7 @@ Scegli uno dei [temi di default](#themes)
Per allineare le card una accanto all'altra, puoi adottare questo approccio:
-```md
+```html
diff --git a/docs/readme_ja.md b/docs/readme_ja.md
index 6e7e747f..b00c77a7 100644
--- a/docs/readme_ja.md
+++ b/docs/readme_ja.md
@@ -296,7 +296,7 @@ _NOTE: Top languages は、ユーザのスキルレベルを示すものでは
通常、画像を並べてレイアウトすることはできません。画像を並べるには、以下のような方法があります。
-```md
+```html
diff --git a/docs/readme_kr.md b/docs/readme_kr.md
index 55851fd2..f5dfc9f2 100644
--- a/docs/readme_kr.md
+++ b/docs/readme_kr.md
@@ -367,7 +367,7 @@ _참고:
그럴땐, 이렇게 해보세요!
-```md
+```html
diff --git a/docs/readme_nl.md b/docs/readme_nl.md
index 788f2c8b..597f0c86 100644
--- a/docs/readme_nl.md
+++ b/docs/readme_nl.md
@@ -346,7 +346,7 @@ Kies uit de [standaard thema\'s](#themes)
Meestal kan je de afbeeldingen niet naast elkaar zetten, op deze manier wel:
-```md
+```html
diff --git a/docs/readme_np.md b/docs/readme_np.md
index b8f92967..15bb34ba 100644
--- a/docs/readme_np.md
+++ b/docs/readme_np.md
@@ -340,7 +340,7 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
तपाइले इमेजलाई सइद बय सइद अलीग्न गर्न सक्नु हुदैन तेसैले येसरी गर्नु होस् :
-```md
+```html
diff --git a/docs/readme_pt-BR.md b/docs/readme_pt-BR.md
index 6542f52d..7f4814ce 100644
--- a/docs/readme_pt-BR.md
+++ b/docs/readme_pt-BR.md
@@ -27,7 +27,7 @@
- Ver demonstração
+ Ver demonstração
·
Reportar erros
·
@@ -147,7 +147,7 @@ Personalize a aparência do seu `Stats Card` ou `Repo Card` da maneira que desej
#### Opções exclusivas do cartão de estatísticas:
- `hide` - Oculta itens específicos das estatísticas _(Valores separados por vírgulas)_
-- `hide_title` - Ocutar o título _(boolean)_
+- `hide_title` - Ocultar o título _(boolean)_
- `hide_rank` - Ocultar a classificação _(boolean)_
- `show_icons` - Mostrar ícones _(boolean)_
- `include_all_commits` - Contabiliza todos os commits ao invés de apenas os atual ano _(boolean)_
@@ -295,7 +295,7 @@ Escolha entre um dos [temas predefinidos](#temas)
Por padrão, você não poderá organizar as imagens lado a lado. Para fazer isso, você pode usar a seguinte abordagem:
-```md
+```html
diff --git a/docs/readme_tr.md b/docs/readme_tr.md
index 5a1c974e..35f32f2f 100644
--- a/docs/readme_tr.md
+++ b/docs/readme_tr.md
@@ -351,7 +351,7 @@ Endpoint: `api/top-langs?username=mustafacagri`
Genellikle resimleri yan yana düzenleyemezsiniz. Bunu yapmak için şu yaklaşımı kullanabilirsiniz:
-```md
+```html
diff --git a/package.json b/package.json
index 345388f9..ed7a9ae2 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"test": "jest --coverage",
"test:watch": "jest --watch",
"theme-readme-gen": "node scripts/generate-theme-doc",
- "preview-theme": "node scripts/preview-theme"
+ "preview-theme": "node scripts/preview-theme",
+ "generate-langs-json": "node scripts/generate-langs-json"
},
"author": "Anurag Hazra",
"license": "MIT",
@@ -16,21 +17,22 @@
"@actions/github": "^4.0.0",
"@testing-library/dom": "^7.20.0",
"@testing-library/jest-dom": "^5.11.0",
- "axios": "^0.24.0",
+ "@uppercod/css-to-object": "^1.1.1",
"axios-mock-adapter": "^1.18.1",
"color-contrast-checker": "^2.1.0",
- "css-to-object": "^1.1.0",
"hjson": "^3.2.2",
"husky": "^4.2.5",
"jest": "^26.1.0",
+ "js-yaml": "^4.1.0",
"lodash.snakecase": "^4.1.1",
- "parse-diff": "^0.7.0"
+ "parse-diff": "^0.7.0",
+ "prettier": "^2.1.2"
},
"dependencies": {
+ "axios": "^0.24.0",
"dotenv": "^8.2.0",
"emoji-name-map": "^1.2.8",
"github-username-regex": "^1.0.0",
- "prettier": "^2.1.2",
"word-wrap": "^1.2.3"
},
"husky": {
diff --git a/readme.md b/readme.md
index a6dab596..d1aa23a3 100644
--- a/readme.md
+++ b/readme.md
@@ -1,7 +1,7 @@
GitHub Readme Stats
-
Get dynamically generated GitHub stats on your readmes!
+
Get dynamically generated GitHub stats on your READMEs!
Français
@@ -65,13 +67,13 @@
-Are you considering to support the project by donating to me? Please DON'T!!
+Are you considering supporting the project by donating? Please DON'T!!
-Instead, Help India fight 2nd deadly wave of COVID,
-Thousands of people are dying in India for lack of Oxygen & COVID related necessary infrastructure.
+Instead, Help India fight the 2nd deadly wave of COVID-19.
+Thousands of people are dying in India because of a lack of Oxygen & also COVID-related infrastructure.
-Visit [https://indiafightscorona.giveindia.org](https://indiafightscorona.giveindia.org) and make a small donation to help us fight covid and overcome this crisis.
-Your small help goes a long way. :heart:
+Visit [https://indiafightscorona.giveindia.org](https://indiafightscorona.giveindia.org) and make a small donation to help us fight COVID and overcome this crisis.
+A small donation goes a long way. :heart:
@@ -94,7 +96,7 @@ Your small help goes a long way. :heart:
Copy-paste this into your markdown content, and that's it. Simple!
-Change the `?username=` value to your GitHub's username.
+Change the `?username=` value to your GitHub username.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -102,11 +104,11 @@ Change the `?username=` value to your GitHub's username.
_Note: Available ranks are S+ (top 1%), S (top 25%), A++ (top 45%), A+ (top 60%), and B+ (everyone).
The values are calculated by using the [cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) using commits, contributions, issues, stars, pull requests, followers, and owned repositories.
-The implementation can be investigated at [src/calculateRank.js](./src/calculateRank.js)_
+The implementation can be investigated at [src/calculateRank.js](./src/calculateRank.js)._
### Hiding individual stats
-To hide any specific stats, you can pass a query parameter `?hide=` with comma-separated values.
+To hide any specific stats, you can pass a query parameter `&hide=` with comma-separated values.
> Options: `&hide=stars,commits,prs,issues,contribs`
@@ -116,7 +118,7 @@ To hide any specific stats, you can pass a query parameter `?hide=` with comma-s
### Adding private contributions count to total commits count
-You can add the count of all your private contributions to the total commits count by using the query parameter `?count_private=true`.
+You can add the count of all your private contributions to the total commits count by using the query parameter `&count_private=true`.
_Note: If you are deploying this project yourself, the private contributions will be counted by default. Otherwise, you need to choose to share your private contribution counts._
@@ -144,7 +146,7 @@ Use `&theme=THEME_NAME` parameter like so :-

```
-#### All inbuilt themes :-
+#### All inbuilt themes:-
dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontrast, dracula
@@ -171,7 +173,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
##### Gradient in bg_color
-You can provide multiple comma-separated values in bg_color option to render a gradient, the format of the gradient is :-
+You can provide multiple comma-separated values in the bg_color option to render a gradient, with the following format:
```
&bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10
@@ -181,7 +183,7 @@ You can provide multiple comma-separated values in bg_color option to render a g
#### Stats Card Exclusive Options:
-- `hide` - Hides the specified items from stats _(Comma-separated values)_
+- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_
- `hide_title` - _(boolean)_
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width
- `show_icons` - _(boolean)_
@@ -218,9 +220,9 @@ You can provide multiple comma-separated values in bg_color option to render a g
- `hide_progress` - Hides the progress bar and percentage _(boolean)_
- `custom_title` - Sets a custom title for the card
- `layout` - Switch between two available layouts `default` & `compact`
-- `langs_count` - Limit number of languages on the card, defaults to all reported langauges
+- `langs_count` - Limit the number of languages on the card, defaults to all reported languages
- `api_domain` - Set 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)
-- `range` – Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for list of available options.
+- `range` – Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options.
---
@@ -250,9 +252,9 @@ Use [show_owner](#customization) variable to include the repo's owner username
# Top Languages Card
-The top languages card show a GitHub user's most frequently used top language.
+The top languages card shows a GitHub user's most frequently used top language.
-_NOTE: Top Languages does not indicate my skill level or anything like that, it's a GitHub metric of which languages have the most code on GitHub. It's a new feature of github-readme-stats._
+_NOTE: Top Languages does not indicate my skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It's a new feature of github-readme-stats._
### Usage
@@ -266,7 +268,7 @@ Endpoint: `api/top-langs?username=anuraghazra`
### Exclude individual repositories
-You can use `?exclude_repo=repo1,repo2` parameter to exclude individual repositories.
+You can use `&exclude_repo=repo1,repo2` parameter to exclude individual repositories.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -274,7 +276,7 @@ You can use `?exclude_repo=repo1,repo2` parameter to exclude individual reposito
### Hide individual languages
-You can use `?hide=language1,language2` parameter to hide individual languages.
+You can use `&hide=language1,language2` parameter to hide individual languages.
```md
[](https://github.com/anuraghazra/github-readme-stats)
@@ -312,6 +314,8 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
[](https://github.com/anuraghazra/github-readme-stats)
```
+> Note: Please be aware that we currently only show data from Wakatime profiles that are public.
+
### Demo
[](https://github.com/anuraghazra/github-readme-stats)
@@ -409,15 +413,16 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we

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

-1. Sign into GitHub and allow access to all repositories, if prompted
+1. Sign in to GitHub and allow access to all repositories, if prompted
1. Fork this repo
1. After forking the repo, open the [`vercel.json`](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json#L5) file and change the `maxDuration` field to `10`
1. Go back to your [Vercel dashboard](https://vercel.com/dashboard)
1. Select `Import Project`

-1. Select `Import Git Repository`
+1. Select `Import Git Repository`. Select root and keep everything as is.

-1. Select root and keep everything as is, just add your environment variable named PAT_1 (as shown), which will contain a personal access token (PAT), which you can easily create [here](https://github.com/settings/tokens/new) (leave everything as is, just name it something, it can be anything you want)
+1. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` permissions (this allows access to see private repo stats)
+1. Add the PAT as an environment variable named `PAT_1` (as shown).

1. Click deploy, and you're good to go. See your domains to use the API!
@@ -428,7 +433,7 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we
I open-source almost everything I can, and I try to reply to everyone needing help using these projects. Obviously,
this takes time. You can use this service for free.
-However, if you are using this project and are happy with it or just want to encourage me to continue creating stuff, there are few ways you can do it :-
+However, if you are using this project and are happy with it or just want to encourage me to continue creating stuff, there are a few ways you can do it:-
- Giving proper credit when you use github-readme-stats on your readme, linking back to it :D
- Starring and sharing the project :rocket:
diff --git a/scripts/generate-langs-json.js b/scripts/generate-langs-json.js
new file mode 100644
index 00000000..0705080d
--- /dev/null
+++ b/scripts/generate-langs-json.js
@@ -0,0 +1,26 @@
+const fs = require('fs');
+const jsYaml = require('js-yaml');
+const axios = require('axios');
+
+const LANGS_FILEPATH = "./src/common/languageColors.json"
+
+//Retrieve languages from github linguist repository yaml file
+//@ts-ignore
+axios.get("https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml")
+.then((response) => {
+
+ //and convert them to a JS Object
+ const languages = jsYaml.load(response.data);
+
+ const languageColors = {};
+
+ //Filter only language colors from the whole file
+ Object.keys(languages).forEach((lang) => {
+ languageColors[lang] = languages[lang].color;
+ });
+
+ //Debug Print
+ //console.dir(languageColors);
+ fs.writeFileSync(LANGS_FILEPATH, JSON.stringify(languageColors, null, ' '));
+
+});
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index ca9effae..e4422ecd 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -156,7 +156,7 @@ async function run() {
if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) {
const permalink = getWebAimLink(color1, color2);
warnings.push(
- `\`${key}\` does not passes [AA contrast ratio](${permalink})`,
+ `\`${key}\` does not pass [AA contrast ratio](${permalink})`,
);
}
});
diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js
index 5295b174..bb5c178a 100644
--- a/src/cards/repo-card.js
+++ b/src/cards/repo-card.js
@@ -1,3 +1,4 @@
+// @ts-check
const {
kFormatter,
encodeHTML,
@@ -65,6 +66,11 @@ const iconWithLabel = (icon, label, testid) => {
return flexLayout({ items: [iconSvg, text], gap: 20 }).join("");
};
+/**
+ * @param {import('../fetchers/types').RepositoryData} repo
+ * @param {Partial} options
+ * @returns {string}
+ */
const renderRepoCard = (repo, options = {}) => {
const {
name,
@@ -161,8 +167,10 @@ const renderRepoCard = (repo, options = {}) => {
return card.render(`
${
isTemplate
+ // @ts-ignore
? getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
: isArchived
+ // @ts-ignore
? getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
: ""
}
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index 22e4be76..9db45623 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -1,3 +1,4 @@
+// @ts-check
const I18n = require("../common/I18n");
const Card = require("../common/Card");
const icons = require("../common/icons");
@@ -45,6 +46,11 @@ const createTextNode = ({
`;
};
+/**
+ * @param {Partial} stats
+ * @param {Partial} options
+ * @returns {string}
+ */
const renderStatsCard = (stats = {}, options = { hide: [] }) => {
const {
name,
@@ -75,7 +81,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
disable_animations = false,
} = options;
- const lheight = parseInt(line_height, 10);
+ const lheight = parseInt(String(line_height), 10);
// returns theme based colors with proper overrides and defaults
const { titleColor, textColor, iconColor, bgColor, borderColor } =
@@ -177,8 +183,8 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
{
if (disable_animations) card.disableAnimations();
+ // Accessibility Labels
+ const labels = Object.keys(STATS)
+ .filter((key) => !hide.includes(key))
+ .map((key) => {
+ if (key === "commits") {
+ return `${i18n.t("statcard.commits")} ${
+ include_all_commits ? "" : `in ${new Date().getFullYear()}`
+ } : ${totalStars}`;
+ }
+ return `${STATS[key].label}: ${STATS[key].value}`;
+ })
+ .join(", ");
+
+ card.setAccessibilityLabel({
+ title: `${card.title}, Rank: ${rank.level}`,
+ desc: labels,
+ });
+
return card.render(`
${rankCircle}
-
`;
@@ -174,6 +195,12 @@ const calculateNormalLayoutHeight = (totalLangs) => {
return 45 + (totalLangs + 1) * 40;
};
+/**
+ *
+ * @param {Record} topLangs
+ * @param {string[]} hide
+ * @param {string} langs_count
+ */
const useLanguages = (topLangs, hide, langs_count) => {
let langs = Object.values(topLangs);
let langsToHide = {};
@@ -200,6 +227,11 @@ const useLanguages = (topLangs, hide, langs_count) => {
return { langs, totalLanguageSize };
};
+/**
+ * @param {import('../fetchers/types').TopLangData} topLangs
+ * @param {Partial} options
+ * @returns {string}
+ */
const renderTopLanguages = (topLangs, options = {}) => {
const {
hide_title,
@@ -226,7 +258,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
const { langs, totalLanguageSize } = useLanguages(
topLangs,
hide,
- langs_count,
+ String(langs_count),
);
let width = isNaN(card_width) ? DEFAULT_CARD_WIDTH : card_width;
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
new file mode 100644
index 00000000..4580a2ea
--- /dev/null
+++ b/src/cards/types.d.ts
@@ -0,0 +1,50 @@
+type ThemeNames = keyof typeof import("../../themes");
+
+export type CommonOptions = {
+ title_color: string;
+ icon_color: string;
+ text_color: string;
+ bg_color: string;
+ theme: ThemeNames;
+ border_radius: number;
+ border_color: string;
+ locale: string;
+};
+
+export type StatCardOptions = CommonOptions & {
+ hide: string[];
+ show_icons: boolean;
+ hide_title: boolean;
+ hide_border: boolean;
+ hide_rank: boolean;
+ include_all_commits: boolean;
+ line_height: number | string;
+ custom_title: string;
+ disable_animations: boolean;
+};
+
+export type RepoCardOptions = CommonOptions & {
+ hide_border: boolean;
+ show_owner: boolean;
+};
+
+export type TopLangOptions = CommonOptions & {
+ hide_title: boolean;
+ hide_border: boolean;
+ card_width: number;
+ hide: string[];
+ layout: "compact" | "normal";
+ custom_title: string;
+ langs_count: number;
+};
+
+type WakaTimeOptions = CommonOptions & {
+ hide_title: boolean;
+ hide_border: boolean;
+ hide: string[];
+ line_height: string;
+ hide_progress: boolean;
+ custom_title: string;
+ layout: "compact" | "normal";
+ langs_count: number;
+};
diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js
index 905e40a0..5ab2f29d 100644
--- a/src/cards/wakatime-card.js
+++ b/src/cards/wakatime-card.js
@@ -1,3 +1,4 @@
+// @ts-check
const Card = require("../common/Card");
const I18n = require("../common/I18n");
const { getStyles } = require("../getStyles");
@@ -11,12 +12,24 @@ const {
lowercaseTrim,
} = require("../common/utils");
+/**
+ * @param {{color: string, text: string}} param0
+ */
const noCodingActivityNode = ({ color, text }) => {
return `
${text}
`;
};
+/**
+ *
+ * @param {{
+ * lang: import("../fetchers/types").WakaTimeLang,
+ * totalSize: number,
+ * x: number,
+ * y: number
+ * }} props
+ */
const createCompactLangNode = ({ lang, totalSize, x, y }) => {
const color = languageColors[lang.name] || "#858585";
@@ -30,6 +43,14 @@ const createCompactLangNode = ({ lang, totalSize, x, y }) => {
`;
};
+/**
+ * @param {{
+ * langs: import("../fetchers/types").WakaTimeLang[],
+ * totalSize: number,
+ * x: number,
+ * y: number
+ * }} props
+ */
const createLanguageTextNode = ({ langs, totalSize, x, y }) => {
return langs.map((lang, index) => {
if (index % 2 === 0) {
@@ -38,7 +59,6 @@ const createLanguageTextNode = ({ langs, totalSize, x, y }) => {
x: 25,
y: 12.5 * index + y,
totalSize,
- index,
});
}
return createCompactLangNode({
@@ -46,11 +66,23 @@ const createLanguageTextNode = ({ langs, totalSize, x, y }) => {
x: 230,
y: 12.5 + 12.5 * index,
totalSize,
- index,
});
});
};
+/**
+ *
+ * @param {{
+ * id: string;
+ * label: string;
+ * value: string;
+ * index: number;
+ * percent: number;
+ * hideProgress: boolean;
+ * progressBarColor: string;
+ * progressBarBackgroundColor: string
+ * }} props
+ */
const createTextNode = ({
id,
label,
@@ -71,6 +103,7 @@ const createTextNode = ({
progress: percent,
color: progressBarColor,
width: 220,
+ // @ts-ignore
name: label,
progressBarBackgroundColor,
});
@@ -88,6 +121,9 @@ const createTextNode = ({
`;
};
+/**
+ * @param {import("../fetchers/types").WakaTimeLang[]} languages
+ */
const recalculatePercentages = (languages) => {
// recalculating percentages so that,
// compact layout's progress bar does not break when hiding languages
@@ -95,12 +131,17 @@ const recalculatePercentages = (languages) => {
(totalSum, language) => totalSum + language.percent,
0,
);
- const weight = (100 / totalSum).toFixed(2);
+ const weight = +(100 / totalSum).toFixed(2);
languages.forEach((language) => {
- language.percent = (language.percent * weight).toFixed(2);
+ language.percent = +(language.percent * weight).toFixed(2);
});
};
+/**
+ * @param {Partial} stats
+ * @param {Partial} options
+ * @returns {string}
+ */
const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
let { languages } = stats;
const {
@@ -136,25 +177,20 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
translations: wakatimeCardLocales,
});
- const lheight = parseInt(line_height, 10);
+ const lheight = parseInt(String(line_height), 10);
- const langsCount = clampValue(parseInt(langs_count), 1, langs_count);
+ const langsCount = clampValue(parseInt(String(langs_count)), 1, langs_count);
// returns theme based colors with proper overrides and defaults
- const {
- titleColor,
- textColor,
- iconColor,
- bgColor,
- borderColor,
- } = getCardColors({
- title_color,
- icon_color,
- text_color,
- bg_color,
- border_color,
- theme,
- });
+ const { titleColor, textColor, iconColor, bgColor, borderColor } =
+ getCardColors({
+ title_color,
+ icon_color,
+ text_color,
+ bg_color,
+ border_color,
+ theme,
+ });
const filteredLanguages = languages
? languages
@@ -228,13 +264,16 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
label: language.name,
value: language.text,
percent: language.percent,
+ // @ts-ignore
progressBarColor: titleColor,
+ // @ts-ignore
progressBarBackgroundColor: textColor,
hideProgress: hide_progress,
});
})
: [
noCodingActivityNode({
+ // @ts-ignore
color: textColor,
text: i18n.t("wakatimecard.nocodingactivity"),
}),
diff --git a/src/common/Card.js b/src/common/Card.js
index fd1fa77d..2cc84553 100644
--- a/src/common/Card.js
+++ b/src/common/Card.js
@@ -42,12 +42,22 @@ class Card {
this.paddingY = 35;
this.titlePrefixIcon = titlePrefixIcon;
this.animations = true;
+ this.a11yTitle = "";
+ this.a11yDesc = "";
}
disableAnimations() {
this.animations = false;
}
+ /**
+ * @param {{title: string, desc: string}} prop
+ */
+ setAccessibilityLabel({ title, desc }) {
+ this.a11yTitle = title;
+ this.a11yDesc = desc;
+ }
+
/**
* @param {string} value
*/
@@ -123,8 +133,9 @@ class Card {
? `
${gradients.map((grad, index) => {
let offset = (index * 100) / (gradients.length - 1);
@@ -147,13 +158,21 @@ class Card {
viewBox="0 0 ${this.width} ${this.height}"
fill="none"
xmlns="http://www.w3.org/2000/svg"
+ role="img"
+ aria-labelledby="descId"
>
+ ${this.a11yTitle}
+ ${this.a11yDesc}
- Something went wrong! file an issue at https://git.io/JJmN9
+ Something went wrong! file an issue at https://tiny.one/readme-stats${encodeHTML(message)}${secondaryMessage}
@@ -161,11 +161,11 @@ function flexLayout({ items, gap, direction, sizes = [] }) {
/**
* @typedef {object} CardColors
- * @prop {string} title_color
- * @prop {string} text_color
- * @prop {string} icon_color
- * @prop {string} bg_color
- * @prop {string} border_color
+ * @prop {string?=} title_color
+ * @prop {string?=} text_color
+ * @prop {string?=} icon_color
+ * @prop {string?=} bg_color
+ * @prop {string?=} border_color
* @prop {keyof typeof import('../../themes')?=} fallbackTheme
* @prop {keyof typeof import('../../themes')?=} theme
*/
@@ -273,13 +273,28 @@ class CustomError extends Error {
constructor(message, type) {
super(message);
this.type = type;
- this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || "adsad";
+ this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
}
static MAX_RETRY = "MAX_RETRY";
static USER_NOT_FOUND = "USER_NOT_FOUND";
}
+class MissingParamError extends Error {
+ /**
+ * @param {string[]} missedParams
+ * @param {string?=} secondaryMessage
+ */
+ constructor(missedParams, secondaryMessage) {
+ const msg = `Missing params ${missedParams
+ .map((p) => `"${p}"`)
+ .join(", ")} make sure you pass the parameters in URL`;
+ super(msg);
+ this.missedParams = missedParams;
+ this.secondaryMessage = secondaryMessage;
+ }
+}
+
/**
* @see https://stackoverflow.com/a/48172630/10629172
* @param {string} str
@@ -372,6 +387,7 @@ module.exports = {
logger,
CONSTANTS,
CustomError,
+ MissingParamError,
lowercaseTrim,
chunkArray,
parseEmojis,
diff --git a/src/fetchers/repo-fetcher.js b/src/fetchers/repo-fetcher.js
index 9ddaadfc..0bad5f2b 100644
--- a/src/fetchers/repo-fetcher.js
+++ b/src/fetchers/repo-fetcher.js
@@ -1,6 +1,11 @@
+// @ts-check
const retryer = require("../common/retryer");
-const { request } = require("../common/utils");
+const { request, MissingParamError } = require("../common/utils");
+/**
+ * @param {import('Axios').AxiosRequestHeaders} variables
+ * @param {string} token
+ */
const fetcher = (variables, token) => {
return request(
{
@@ -43,10 +48,19 @@ const fetcher = (variables, token) => {
);
};
+const urlExample = "/api/pin?username=USERNAME&repo=REPO_NAME";
+
+/**
+ * @param {string} username
+ * @param {string} reponame
+ * @returns {Promise}
+ */
async function fetchRepo(username, reponame) {
- if (!username || !reponame) {
- throw new Error("Invalid username or reponame");
+ if (!username && !reponame) {
+ throw new MissingParamError(["username", "repo"], urlExample);
}
+ if (!username) throw new MissingParamError(["username"], urlExample);
+ if (!reponame) throw new MissingParamError(["repo"], urlExample);
let res = await retryer(fetcher, { login: username, repo: reponame });
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index c01db11b..f783d2e1 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -1,12 +1,22 @@
-const axios = require("axios");
+// @ts-check
+const axios = require("axios").default;
const githubUsernameRegex = require("github-username-regex");
const retryer = require("../common/retryer");
const calculateRank = require("../calculateRank");
-const { request, logger, CustomError } = require("../common/utils");
+const {
+ request,
+ logger,
+ CustomError,
+ MissingParamError,
+} = require("../common/utils");
require("dotenv").config();
+/**
+ * @param {import('axios').AxiosRequestHeaders} variables
+ * @param {string} token
+ */
const fetcher = (variables, token) => {
return request(
{
@@ -87,13 +97,19 @@ const totalCommitsFetcher = async (username) => {
}
};
+/**
+ * @param {string} username
+ * @param {boolean} count_private
+ * @param {boolean} include_all_commits
+ * @returns {Promise}
+ */
async function fetchStats(
username,
ownerAffiliations,
count_private = false,
include_all_commits = false,
) {
- if (!username) throw Error("Invalid username");
+ if (!username) throw new MissingParamError(["username"]);
const stats = {
name: "",
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index 50283740..74e1cfcb 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -1,7 +1,12 @@
-const { request, logger } = require("../common/utils");
+// @ts-check
+const { request, logger, MissingParamError } = require("../common/utils");
const retryer = require("../common/retryer");
require("dotenv").config();
+/**
+ * @param {import('Axios').AxiosRequestHeaders} variables
+ * @param {string} token
+ */
const fetcher = (variables, token) => {
return request(
{
@@ -34,8 +39,14 @@ const fetcher = (variables, token) => {
);
};
+/**
+ * @param {string} username
+ * @param {string[]} ownerAffiliations
+ * @param {string[]} exclude_repo
+ * @returns {Promise}
+ */
async function fetchTopLanguages(username, ownerAffiliations, exclude_repo = []) {
- if (!username) throw Error("Invalid username");
+ if (!username) throw new MissingParamError(["username"]);
// Set default value for ownerAffiliations in GraphQL query won't work because
// parseArray() will always return an empty array even nothing was specified
diff --git a/src/fetchers/types.d.ts b/src/fetchers/types.d.ts
new file mode 100644
index 00000000..854e1315
--- /dev/null
+++ b/src/fetchers/types.d.ts
@@ -0,0 +1,104 @@
+export type RepositoryData = {
+ name: string;
+ nameWithOwner: string;
+ isPrivate: boolean;
+ isArchived: boolean;
+ isTemplate: boolean;
+ stargazers: { totalCount: number };
+ description: string;
+ primaryLanguage: {
+ color: string;
+ id: string;
+ name: string;
+ };
+ forkCount: number;
+ starCount: number;
+};
+
+export type StatsData = {
+ name: string;
+ totalPRs: number;
+ totalCommits: number;
+ totalIssues: number;
+ totalStars: number;
+ contributedTo: number;
+ rank: { level: string; score: number };
+};
+
+export type Lang = {
+ name: string;
+ color: string;
+ size: number;
+};
+
+export type TopLangData = Record;
+
+export type WakaTimeData = {
+ categories: {
+ digital: string;
+ hours: number;
+ minutes: number;
+ name: string;
+ percent: number;
+ text: string;
+ total_seconds: number;
+ }[];
+ daily_average: number;
+ daily_average_including_other_language: number;
+ days_including_holidays: number;
+ days_minus_holidays: number;
+ editors: {
+ digital: string;
+ hours: number;
+ minutes: number;
+ name: string;
+ percent: number;
+ text: string;
+ total_seconds: number;
+ }[];
+ holidays: number;
+ human_readable_daily_average: string;
+ human_readable_daily_average_including_other_language: string;
+ human_readable_total: string;
+ human_readable_total_including_other_language: string;
+ id: string;
+ is_already_updating: boolean;
+ is_coding_activity_visible: boolean;
+ is_including_today: boolean;
+ is_other_usage_visible: boolean;
+ is_stuck: boolean;
+ is_up_to_date: boolean;
+ languages: {
+ digital: string;
+ hours: number;
+ minutes: number;
+ name: string;
+ percent: number;
+ text: string;
+ total_seconds: number;
+ }[];
+ operating_systems: {
+ digital: string;
+ hours: number;
+ minutes: number;
+ name: string;
+ percent: number;
+ text: string;
+ total_seconds: number;
+ }[];
+ percent_calculated: number;
+ range: string;
+ status: string;
+ timeout: number;
+ total_seconds: number;
+ total_seconds_including_other_language: number;
+ user_id: string;
+ username: string;
+ writes_only: boolean;
+};
+
+export type WakaTimeLang = {
+ name: string;
+ text: string;
+ percent: number;
+};
diff --git a/src/fetchers/wakatime-fetcher.js b/src/fetchers/wakatime-fetcher.js
index 92371ff5..e9779d60 100644
--- a/src/fetchers/wakatime-fetcher.js
+++ b/src/fetchers/wakatime-fetcher.js
@@ -1,11 +1,18 @@
const axios = require("axios");
+const { MissingParamError } = require("../common/utils");
+/**
+ * @param {{username: string, api_domain: string, range: string}} props
+ * @returns {Promise}
+ */
const fetchWakatimeStats = async ({ username, api_domain, range }) => {
+ if (!username) throw new MissingParamError(["username"]);
+
try {
const { data } = await axios.get(
`https://${
api_domain ? api_domain.replace(/\/$/gi, "") : "wakatime.com"
- }/api/v1/users/${username}/stats/${range || ''}?is_including_today=true`,
+ }/api/v1/users/${username}/stats/${range || ""}?is_including_today=true`,
);
return data.data;
diff --git a/src/getStyles.js b/src/getStyles.js
index fd70c249..e5013e56 100644
--- a/src/getStyles.js
+++ b/src/getStyles.js
@@ -1,3 +1,4 @@
+// @ts-check
/**
* @param {number} value
*/
@@ -53,11 +54,11 @@ const getAnimations = () => {
/**
* @param {{
- * titleColor: string;
- * textColor: string;
- * iconColor: string;
- * show_icons: boolean;
- * progress: number;
+ * titleColor?: string | string[]
+ * textColor?: string | string[]
+ * iconColor?: string | string[]
+ * show_icons?: boolean;
+ * progress?: number;
* }} args
*/
const getStyles = ({
@@ -71,6 +72,10 @@ const getStyles = ({
.stat {
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
}
+ @supports(-moz-appearance: auto) {
+ /* Selector detects Firefox */
+ .stat { font-size:12px; }
+ }
.stagger {
opacity: 0;
animation: fadeInAnimation 0.3s ease-in-out forwards;
diff --git a/src/translations.js b/src/translations.js
index e8a85bd7..38e53f37 100644
--- a/src/translations.js
+++ b/src/translations.js
@@ -6,6 +6,7 @@ const statCardLocales = ({ name, apostrophe }) => {
"statcard.title": {
ar: `${encodedName} إحصائيات غيت هاب`,
cn: `${encodedName} 的 GitHub 统计数据`,
+ "zh-tw": `${encodedName} 的 GitHub 統計數據`,
cs: `GitHub statistiky uživatele ${encodedName}`,
de: `${encodedName + apostrophe} GitHub-Statistiken`,
en: `${encodedName}'${apostrophe} GitHub Stats`,
@@ -16,7 +17,7 @@ const statCardLocales = ({ name, apostrophe }) => {
it: `Statistiche GitHub di ${encodedName}`,
ja: `${encodedName}の GitHub 統計`,
kr: `${encodedName}의 GitHub 통계`,
- nl: `${encodedName}'${apostrophe} GitHub Statistieken`,
+ nl: `${encodedName}'${apostrophe} GitHub-statistieken`,
"pt-pt": `Estatísticas do GitHub de ${encodedName}`,
"pt-br": `Estatísticas do GitHub de ${encodedName}`,
np: `${encodedName}'${apostrophe} गिटहब तथ्याङ्क`,
@@ -24,25 +25,30 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: `Статистика GitHub пользователя ${encodedName}`,
"uk-ua": `Статистика GitHub користувача ${encodedName}`,
id: `Statistik GitHub ${encodedName}`,
+ ml: `${encodedName}'${apostrophe} ഗിറ്റ്ഹബ് സ്ഥിതിവിവരക്കണക്കുകൾ`,
my: `Statistik GitHub ${encodedName}`,
sk: `GitHub štatistiky používateľa ${encodedName}`,
tr: `${encodedName} Hesabının GitHub Yıldızları`,
pl: `Statystyki GitHub użytkownika ${encodedName}`,
+ uz: `${encodedName}ning Github'dagi statistikasi`,
+ vi: `Thống Kê GitHub ${encodedName}`,
+ se: `GitHubstatistik för ${encodedName}`,
},
"statcard.totalstars": {
ar: "مجموع النجوم",
cn: "获标星数(star)",
+ "zh-tw": "獲標星數(star)",
cs: "Celkem hvězd",
de: "Insgesamt erhaltene Sterne",
en: "Total Stars Earned",
- bn: "সর্বমোট Stars",
+ bn: "সর্বমোট Star",
es: "Estrellas totales",
fr: "Total d'étoiles",
hu: "Csillagok",
it: "Stelle totali",
ja: "スターされた数",
kr: "받은 스타 수",
- nl: "Totaal sterren ontvangen",
+ nl: "Totaal Sterren Ontvangen",
"pt-pt": "Total de estrelas",
"pt-br": "Total de estrelas",
np: "कुल ताराहरू",
@@ -50,25 +56,30 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: "Всего звезд",
"uk-ua": "Всього зірок",
id: "Total Bintang",
+ ml: "ആകെ നക്ഷത്രങ്ങൾ",
my: "Jumlah Bintang",
sk: "Hviezdy",
tr: "Toplam Yıldız",
pl: "Liczba Gwiazdek dostanych",
+ uz: "Yulduzchalar",
+ vi: "Tổng Số Sao",
+ se: "Antal intjänade stjärnor",
},
"statcard.commits": {
ar: "مجموع الحفظ",
cn: "累计提交数(commit)",
+ "zh-tw": "累計提交數(commit)",
cs: "Celkem commitů",
de: "Anzahl Commits",
en: "Total Commits",
- bn: "সর্বমোট Commits",
+ bn: "সর্বমোট Commit",
es: "Commits totales",
- fr: "Total des validations",
+ fr: "Total des Commits",
hu: "Összes commit",
it: "Commit totali",
ja: "合計コミット数",
kr: "전체 커밋 수",
- nl: "Totale Commits",
+ nl: "Aantal commits",
"pt-pt": "Total de Commits",
"pt-br": "Total de Commits",
np: "कुल Commits",
@@ -76,25 +87,30 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: "Всего коммитов",
"uk-ua": "Всього коммітов",
id: "Total Komitmen",
+ ml: "ആകെ കമ്മിറ്റുകൾ",
my: "Jumlah Komitmen",
sk: "Všetky commity",
tr: "Toplam Commit",
pl: "Wszystkie commity",
+ uz: "'Commit'lar",
+ vi: "Tổng Số Cam Kết",
+ se: "Totalt antal commits",
},
"statcard.prs": {
ar: "مجموع طلبات السحب",
cn: "拉取请求数(PR)",
+ "zh-tw": "拉取請求數(PR)",
cs: "Celkem PRs",
de: "PRs Insgesamt",
en: "Total PRs",
- bn: "সর্বমোট PRs",
+ bn: "সর্বমোট PR",
es: "PRs totales",
- fr: "Total des PR",
+ fr: "Total des PRs",
hu: "Összes PR",
it: "PR totali",
ja: "合計 PR",
kr: "PR 횟수",
- nl: "Totale PR's",
+ nl: "Aantal PR's",
"pt-pt": "Total de PRs",
"pt-br": "Total de PRs",
np: "कुल PRs",
@@ -102,25 +118,30 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: "Всего pull request`ов",
"uk-ua": "Всього pull request`iв",
id: "Total Permintaan Tarik",
+ ml: "ആകെ പുൾ അഭ്യർത്ഥനകൾ",
my: "Jumlah PR",
sk: "Všetky PR",
tr: "Toplam PR",
- pl: "Wszystkie PR",
+ pl: "Wszystkie PR-y",
+ uz: "'Pull Request'lar",
+ vi: "Tổng Số PR",
+ se: "Totalt antal PR",
},
"statcard.issues": {
ar: "مجموع التحسينات",
cn: "指出问题数(issue)",
+ "zh-tw": "指出問題數(issue)",
cs: "Celkem problémů",
de: "Anzahl Issues",
en: "Total Issues",
- bn: "সর্বমোট Issues",
+ bn: "সর্বমোট Issue",
es: "Issues totales",
fr: "Nombre total d'incidents",
hu: "Összes hibajegy",
it: "Segnalazioni totali",
ja: "合計 issue",
kr: "이슈 개수",
- nl: "Totale Issues",
+ nl: "Aantal kwesties",
"pt-pt": "Total de Issues",
"pt-br": "Total de Issues",
np: "कुल मुद्दाहरू",
@@ -128,14 +149,19 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: "Всего issue",
"uk-ua": "Всього issue",
id: "Total Masalah Dilaporkan",
+ ml: "ആകെ ലക്കങ്ങൾ",
my: "Jumlah Isu Dilaporkan",
sk: "Všetky problémy",
tr: "Toplam Hata",
- pl: "Wszystkie problemy",
+ pl: "Wszystkie Issues",
+ uz: "'Issue'lar",
+ vi: "Tổng Số Vấn Đề",
+ se: "Total antal issues",
},
"statcard.contribs": {
ar: "ساهم في",
cn: "参与项目数",
+ "zh-tw": "參與項目數",
cs: "Přispěl k",
de: "Beigetragen zu",
en: "Contributed to",
@@ -144,7 +170,7 @@ const statCardLocales = ({ name, apostrophe }) => {
fr: "Contribué à",
hu: "Hozzájárulások",
it: "Ha contribuito a",
- ja: "コントリビュートしたリポジトリ",
+ ja: "貢献したリポジトリ",
kr: "전체 기여도",
nl: "Bijgedragen aan",
"pt-pt": "Contribuiu em",
@@ -154,10 +180,14 @@ const statCardLocales = ({ name, apostrophe }) => {
ru: "Внёс вклад в",
"uk-ua": "Вніс внесок у",
id: "Berkontribusi ke",
+ ml: "സമർപ്പിച്ചിരിക്കുന്നത്",
my: "Menyumbang kepada",
sk: "Účasti",
tr: "Katkı Verildi",
- pl: "Udziały",
+ pl: "Kontrybucje",
+ uz: "Hissa qoʻshgan",
+ vi: "Đã Đóng Góp",
+ se: "Bidragit till",
},
};
};
@@ -165,7 +195,9 @@ const statCardLocales = ({ name, apostrophe }) => {
const repoCardLocales = {
"repocard.template": {
ar: "قالب",
+ bn: "টেমপ্লেট",
cn: "模板",
+ "zh-tw": "模板",
cs: "Šablona",
de: "Vorlage",
en: "Template",
@@ -183,14 +215,19 @@ const repoCardLocales = {
ru: "Шаблон",
"uk-ua": "Шаблон",
id: "Pola",
+ ml: "ടെംപ്ലേറ്റ്",
my: "Templat",
sk: "Šablóna",
tr: "Şablon",
pl: "Szablony",
+ vi: "Mẫu",
+ se: "Mall",
},
"repocard.archived": {
ar: "محفوظ",
+ bn: "আর্কাইভড",
cn: "已归档",
+ "zh-tw": "已歸檔",
cs: "Archivováno",
de: "Archiviert",
en: "Archived",
@@ -208,10 +245,13 @@ const repoCardLocales = {
ru: "Архивирован",
"uk-ua": "Архивирован",
id: "Arsip",
+ ml: "ശേഖരിച്ചത്",
my: "Arkib",
sk: "Archivované",
tr: "Arşiv",
pl: "Zarchiwizowano",
+ vi: "Đã Lưu Trữ",
+ se: "Arkiverade",
},
};
@@ -219,8 +259,10 @@ const langCardLocales = {
"langcard.title": {
ar: "أكثر اللغات إستخداماً",
cn: "最常用的语言",
+ "zh-tw": "最常用的語言",
cs: "Nejpoužívanější jazyky",
de: "Meist verwendete Sprachen",
+ bn: "সর্বাধিক ব্যবহৃত ভাষা সমূহ",
en: "Most Used Languages",
es: "Lenguajes más usados",
fr: "Langages les plus utilisés",
@@ -236,10 +278,13 @@ const langCardLocales = {
ru: "Наиболее часто используемые языки",
"uk-ua": "Найбільш часто використовувані мови",
id: "Bahasa Yang Paling Banyak Digunakan",
+ ml: "കൂടുതൽ ഉപയോഗിച്ച ഭാഷകൾ",
my: "Bahasa Paling Digunakan",
sk: "Najviac používané jazyky",
tr: "En Çok Kullanılan Diller",
pl: "Najczęściej używane języki",
+ vi: "Ngôn Ngữ Thường Sử Dụng",
+ se: "Mest använda språken",
},
};
@@ -247,16 +292,18 @@ const wakatimeCardLocales = {
"wakatimecard.title": {
ar: "إحصائيات واكا تايم",
cn: "Wakatime 周统计",
+ "zh-tw": "Wakatime 周統計",
cs: "Statistiky Wakatime",
de: "Wakatime Status",
en: "Wakatime Stats",
+ bn: "Wakatime স্ট্যাটাস",
es: "Estadísticas de Wakatime",
fr: "Statistiques de Wakatime",
hu: "Wakatime statisztika",
it: "Statistiche Wakatime",
ja: "Wakatime ワカタイム統計",
kr: "Wakatime 주간 통계",
- nl: "Takwimu za Wakatime",
+ nl: "Wakatime-statistieken",
"pt-pt": "Estatísticas Wakatime",
"pt-br": "Estatísticas Wakatime",
np: "Wakatime तथ्या .्क",
@@ -264,24 +311,29 @@ const wakatimeCardLocales = {
ru: "Статистика Wakatime",
"uk-ua": "Статистика Wakatime",
id: "Status Wakatime",
+ ml: "വേക്ക് ടൈം സ്ഥിതിവിവരക്കണക്കുകൾ",
my: "Statistik Wakatime",
sk: "Wakatime štatistika",
tr: "Waketime İstatistikler",
pl: "statystyki Wakatime",
+ vi: "Thống Kê Wakatime",
+ se: "Wakatime statistik",
},
"wakatimecard.nocodingactivity": {
ar: "لا يوجد نشاط برمجي لهذا الأسبوع",
cn: "本周没有编程活动",
+ "zh-tw": "本周沒有編程活動",
cs: "Tento týden žádná aktivita v kódování",
de: "Keine Aktivitäten in dieser Woche",
en: "No coding activity this week",
+ bn: "এই সপ্তাহে কোন কোডিং অ্যাক্টিভিটি নেই",
es: "No hay actividad de codificación esta semana",
fr: "Aucune activité de codage cette semaine",
hu: "Nem volt aktivitás ezen a héten",
it: "Nessuna attività in questa settimana",
ja: "今週のコーディング活動はありません",
kr: "이번 주 작업내역 없음",
- nl: "Geen coderings activiet deze week",
+ nl: "Geen programmeeractiviteit deze week",
"pt-pt": "Sem atividade esta semana",
"pt-br": "Nenhuma atividade de codificação esta semana",
np: "यस हप्ता कुनै कोडिंग गतिविधि छैन",
@@ -289,10 +341,14 @@ const wakatimeCardLocales = {
ru: "На этой неделе не было активности",
"uk-ua": "На цьому тижні не було активності",
id: "Tidak ada aktivitas perkodingan minggu ini",
+ ml: "ഈ ആഴ്ച കോഡിംഗ് പ്രവർത്തനങ്ങളൊന്നുമില്ല",
my: "Tiada aktiviti pengekodan minggu ini",
sk: "Žiadna kódovacia aktivita tento týždeň",
tr: "Bu hafta herhangi bir kod yazma aktivitesi olmadı",
pl: "Brak aktywności w tym tygodniu",
+ uz: "Bu hafta faol bo'lmadi",
+ vi: "Không Có Hoạt Động Trong Tuần Này",
+ se: "Ingen aktivitet denna vecka",
},
};
diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap
index c651c62a..aa5641a0 100644
--- a/tests/__snapshots__/renderWakatimeCard.test.js.snap
+++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap
@@ -8,24 +8,36 @@ exports[`Test Render Wakatime Card should render correctly 1`] = `
viewBox=\\"0 0 495 150\\"
fill=\\"none\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
+ role=\\"img\\"
+ aria-labelledby=\\"descId\\"
>
+
+