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 [![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)](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 ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true) @@ -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` [![Readme Card](https://github-readme-stats.vercel.app/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. [![Readme Card](https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&show_owner=true)](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 [![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](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 [![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod)](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) ![](https://files.catbox.moe/pqub9q.png) 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) ![](https://files.catbox.moe/0ez4g7.png) -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

GitHub Readme Stats

-

Get dynamically generated GitHub stats on your readmes!

+

Get dynamically generated GitHub stats on your READMEs!

@@ -32,6 +32,8 @@ Report Bug · Request Feature + · + Ask Question

Français @@ -65,13 +67,13 @@ Give india logo -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 [![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)](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 :- ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=radical) ``` -#### 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 [![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&exclude_repo=github-readme-stats,anuraghazra.github.io)](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 [![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&hide=javascript,html)](https://github.com/anuraghazra/github-readme-stats) @@ -312,6 +314,8 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username. [![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod)](https://github.com/anuraghazra/github-readme-stats) ``` +> Note: Please be aware that we currently only show data from Wakatime profiles that are public. + ### Demo [![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod)](https://github.com/anuraghazra/github-readme-stats) @@ -409,15 +413,16 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we ![](https://files.catbox.moe/tct1wg.png) 1. Sign in with GitHub by pressing `Continue with GitHub` ![](https://files.catbox.moe/btd78j.jpeg) -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` ![](https://files.catbox.moe/qckos0.png) -1. Select `Import Git Repository` +1. Select `Import Git Repository`. Select root and keep everything as is. ![](https://files.catbox.moe/pqub9q.png) -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). ![](https://files.catbox.moe/0ez4g7.png) 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} - ${flexLayout({ items: statItems, diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js index c8109f36..4e079ff2 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -1,3 +1,4 @@ +// @ts-check const Card = require("../common/Card"); const I18n = require("../common/I18n"); const { langCardLocales } = require("../translations"); @@ -16,6 +17,28 @@ const DEFAULT_LANGS_COUNT = 5; const DEFAULT_LANG_COLOR = "#858585"; const CARD_PADDING = 25; +/** + * @typedef {import("../fetchers/types").Lang} Lang + */ + +/** + * @param {Lang[]} arr + */ + const getLongestLang = (arr) => + arr.reduce( + (savedLang, lang) => + lang.name.length > savedLang.name.length ? lang : savedLang, + { name: "", size: null, color: "" }, + ); + +/** + * @param {{ + * width: number, + * color: string, + * name: string, + * progress: string + * }} props + */ const createProgressTextNode = ({ width, color, name, progress }) => { const paddingRight = 95; const progressTextX = width - paddingRight + 10; @@ -35,6 +58,9 @@ const createProgressTextNode = ({ width, color, name, progress }) => { `; }; +/** + * @param {{ lang: Lang, totalSize: number }} props + */ const createCompactLangNode = ({ lang, totalSize }) => { const percentage = ((lang.size / totalSize) * 100).toFixed(2); const color = lang.color || "#858585"; @@ -49,21 +75,19 @@ const createCompactLangNode = ({ lang, totalSize }) => { `; }; -const getLongestLang = (arr) => - arr.reduce( - (savedLang, lang) => - lang.name.length > savedLang.name.length ? lang : savedLang, - { name: "" }, - ); - +/** + * @param {{ langs: Lang[], totalSize: number }} props + */ const createLanguageTextNode = ({ langs, totalSize }) => { const longestLang = getLongestLang(langs); const chunked = chunkArray(langs, langs.length / 2); const layouts = chunked.map((array) => { + // @ts-ignore const items = array.map((lang, index) => createCompactLangNode({ lang, totalSize, + // @ts-ignore index, }), ); @@ -84,8 +108,7 @@ const createLanguageTextNode = ({ langs, totalSize }) => { }; /** - * - * @param {any[]} langs + * @param {Lang[]} langs * @param {number} width * @param {number} totalLanguageSize * @returns {string} @@ -106,8 +129,7 @@ const renderNormalLayout = (langs, width, totalLanguageSize) => { }; /** - * - * @param {any[]} langs + * @param {Lang[]} langs * @param {number} width * @param {number} totalLanguageSize * @returns {string} @@ -152,7 +174,6 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => { ${createLanguageTextNode({ langs, totalSize: totalLanguageSize, - width, })} `; @@ -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\\" > + +