forked from mirrored/github-readme-stats
Merge branch 'master' into patch-rank
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
github: [anuraghazra] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
|
||||
@@ -5,11 +5,12 @@ title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
<!--PLEASE FIRST READ THE FAQ (#1770) AND COMMON ERROR CODES (#1772)!!!-->
|
||||
|
||||
**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)**
|
||||
@@ -18,9 +19,11 @@ If applicable, add screenshots to help explain your problem.
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
<!--
|
||||
<!-- FAQ
|
||||
Below are some questions that are found in the FAQ. The full FAQ can be found in #1770.
|
||||
|
||||
PLEASE READ THE FAQs!!!
|
||||
Q: My card displays an error
|
||||
Ans: First, check the common error codes (i.e. https://github.com/anuraghazra/github-readme-stats/issues/1772) and existing issues before creating a new one.
|
||||
|
||||
Q: How to hide jupyter Notebook?
|
||||
Ans: &hide=jupyter%20notebook
|
||||
@@ -31,11 +34,10 @@ Ans:
|
||||
- YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
|
||||
|
||||
Q: Language Card is incorrect
|
||||
Ans: Please read all the issues / comments before opening any issues regarding language card stats:
|
||||
Ans: Please read all the 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?
|
||||
Ans: We can only count private commits & we cannot access any other private info of any users, so it's not possible. only way is to deploy on your own instance & use your own PAT (Personal Access Token)
|
||||
|
||||
Ans: We can only count private commits & we cannot access any other private info of any users, so it's impossible. The only way is to deploy on your own instance & use your own PAT (Personal Access Token)
|
||||
-->
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Close empty issues and templates
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- reopened
|
||||
- opened
|
||||
- edited
|
||||
|
||||
jobs:
|
||||
closeEmptyIssuesAndTemplates:
|
||||
name: Close empty issues
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3 # NOTE: Retrieve issue templates.
|
||||
- name: Run empty issues closer action
|
||||
uses: rickstaa/empty-issues-closer-action@v1
|
||||
env:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
close_comment:
|
||||
Closing this issue because it appears to be empty. Please update the
|
||||
issue for it to be reopened.
|
||||
open_comment:
|
||||
Reopening this issue because the author provided more information.
|
||||
check_templates: true
|
||||
template_close_comment:
|
||||
Closing this issue since the issue template was not filled in.
|
||||
Please provide us with more information to have this issue reopened.
|
||||
template_open_comment:
|
||||
Reopening this issue because the author provided more information.
|
||||
@@ -5,8 +5,10 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- master
|
||||
- theme-preview-script
|
||||
- theme_preview_script
|
||||
paths:
|
||||
- "themes/index.js"
|
||||
- "scripts/preview-theme.js"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -20,21 +20,14 @@ jobs:
|
||||
with:
|
||||
node-version: "12.x"
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
path: ~/.npm
|
||||
key:
|
||||
${{ runner.os }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-cache-
|
||||
|
||||
- name: Install & Test
|
||||
run: |
|
||||
npm install
|
||||
npm run test
|
||||
|
||||
- name: Run Prettier
|
||||
run: |
|
||||
npm run format:check
|
||||
|
||||
- name: Code Coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Update top issues dashboard
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 */7 * *"
|
||||
|
||||
jobs:
|
||||
showAndLabelTopIssues:
|
||||
name: Update top issues Dashboard.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run top issues action
|
||||
uses: rickstaa/top-issues-action@v1
|
||||
env:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
label: false
|
||||
dashboard: true
|
||||
dashboard_show_total_reactions: true
|
||||
top_issues: true
|
||||
top_bugs: true
|
||||
top_features: true
|
||||
top_pull_requests: true
|
||||
@@ -8,3 +8,6 @@ package-lock.json
|
||||
coverage
|
||||
vercel_token
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
*.code-workspace
|
||||
|
||||
+49
-40
@@ -2,41 +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?
|
||||
|
||||
[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 <https://localhost:3000>.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -50,41 +59,41 @@ 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: <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>
|
||||
|
||||
**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-665164174>
|
||||
>
|
||||
> - https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181
|
||||
> - <https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181>
|
||||
|
||||
**Q:** How to count private stats?
|
||||
|
||||
> **Ans:** We can only count private commits & we cannot access any other private info of any users, so it's not possible. only way is to deploy on your own instance & use your own PAT (Personal Access Token)
|
||||
> **Ans:** We can only count public commits & we cannot access any other private info of any users, so it's not possible. The only way to count your personal private stats is to deploy on your own instance & use your own PAT (Personal Access Token)
|
||||
|
||||
### Bug Reports
|
||||
|
||||
**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.
|
||||
|
||||
@@ -92,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
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Anurag Hazra
|
||||
Copyright (c) 2020 Anurag Hazra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+9
-5
@@ -17,6 +17,7 @@ module.exports = async (req, res) => {
|
||||
hide,
|
||||
hide_title,
|
||||
hide_border,
|
||||
card_width,
|
||||
hide_rank,
|
||||
show_icons,
|
||||
count_private,
|
||||
@@ -25,17 +26,17 @@ module.exports = async (req, res) => {
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
text_bold,
|
||||
bg_color,
|
||||
theme,
|
||||
cache_seconds,
|
||||
exclude_repo,
|
||||
custom_title,
|
||||
locale,
|
||||
disable_animations,
|
||||
border_radius,
|
||||
border_color,
|
||||
} = req.query;
|
||||
let stats;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
@@ -47,15 +48,16 @@ module.exports = async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
stats = await fetchStats(
|
||||
const stats = await fetchStats(
|
||||
username,
|
||||
parseBoolean(count_private),
|
||||
parseBoolean(include_all_commits),
|
||||
parseArray(exclude_repo),
|
||||
);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
@@ -67,12 +69,14 @@ module.exports = async (req, res) => {
|
||||
show_icons: parseBoolean(show_icons),
|
||||
hide_title: parseBoolean(hide_title),
|
||||
hide_border: parseBoolean(hide_border),
|
||||
card_width: parseInt(card_width, 10),
|
||||
hide_rank: parseBoolean(hide_rank),
|
||||
include_all_commits: parseBoolean(include_all_commits),
|
||||
line_height,
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
text_bold: parseBoolean(text_bold),
|
||||
bg_color,
|
||||
theme,
|
||||
custom_title,
|
||||
|
||||
+8
-10
@@ -27,8 +27,6 @@ module.exports = async (req, res) => {
|
||||
border_color,
|
||||
} = req.query;
|
||||
|
||||
let repoData;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
@@ -40,20 +38,20 @@ module.exports = async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
repoData = await fetchRepo(username, repo);
|
||||
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
|
||||
*/
|
||||
const stars = repoData.stargazers.totalCount;
|
||||
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;
|
||||
const isBothUnder1 = stars < 1 && forks < 1;
|
||||
|
||||
+3
-6
@@ -31,8 +31,6 @@ module.exports = async (req, res) => {
|
||||
border_radius,
|
||||
border_color,
|
||||
} = req.query;
|
||||
let topLangs;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
@@ -44,15 +42,14 @@ module.exports = async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
topLangs = await fetchTopLanguages(
|
||||
const topLangs = await fetchTopLanguages(
|
||||
username,
|
||||
parseArray(exclude_repo),
|
||||
parseArray(hide),
|
||||
);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
|
||||
+6
-3
@@ -3,9 +3,10 @@ const {
|
||||
renderError,
|
||||
parseBoolean,
|
||||
clampValue,
|
||||
parseArray,
|
||||
CONSTANTS,
|
||||
isLocaleAvailable,
|
||||
} = require("../src/common/utils");
|
||||
const { isLocaleAvailable } = require("../src/translations");
|
||||
const { fetchWakatimeStats } = require("../src/fetchers/wakatime-fetcher");
|
||||
const wakatimeCard = require("../src/cards/wakatime-card");
|
||||
|
||||
@@ -26,6 +27,7 @@ module.exports = async (req, res) => {
|
||||
locale,
|
||||
layout,
|
||||
langs_count,
|
||||
hide,
|
||||
api_domain,
|
||||
range,
|
||||
border_radius,
|
||||
@@ -42,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,
|
||||
);
|
||||
|
||||
@@ -58,6 +60,7 @@ module.exports = async (req, res) => {
|
||||
custom_title,
|
||||
hide_title: parseBoolean(hide_title),
|
||||
hide_border: parseBoolean(hide_border),
|
||||
hide: parseArray(hide),
|
||||
line_height,
|
||||
title_color,
|
||||
icon_color,
|
||||
|
||||
+2
-2
@@ -290,7 +290,7 @@ _注意:热门语言并不表示我的技能水平或类似的水平,它是
|
||||
|
||||
你通常无法将图片靠边显示。为此,您可以使用以下方法:
|
||||
|
||||
```md
|
||||
```html
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
@@ -325,7 +325,7 @@ _注意:热门语言并不表示我的技能水平或类似的水平,它是
|
||||
1. 选择 `Import Git Repository`
|
||||

|
||||
1. 选择 root 并将所有内容保持不变,并且只需添加名为 PAT_1 的环境变量(如图所示),其中将包含一个个人访问令牌(PAT),你可以在[这里](https://github.com/settings/tokens/new)轻松创建(保留默认,并且只需要命名下,名字随便)
|
||||

|
||||

|
||||
1. 点击 deploy,这就完成了,查看你的域名就可使用 API 了!
|
||||
|
||||
</details>
|
||||
|
||||
+14
-14
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
@@ -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!
|
||||
</details>
|
||||
|
||||
## :sparkling_heart: Unterstütze das Projekt
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@
|
||||
|
||||
- [Tarjeta de estadísticas de GitHub](#tarjeta-de-estadísticas-de-github)
|
||||
- [Pins adicionales de GitHub](#pines-adicionales-de-github)
|
||||
- [Top Languages Card](#tarjeta-de-lenguajes-principales)
|
||||
- [Tarjeta de Lenguajes Principales](#tarjeta-de-lenguajes-principales)
|
||||
- [Wakatime Week Stats](#estadísticas-de-la-semana-de-wakatime)
|
||||
- [Temas](#temas)
|
||||
- [Personalización](#personalización)
|
||||
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+2
-2
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -296,7 +296,7 @@ _NOTE: Top languages は、ユーザのスキルレベルを示すものでは
|
||||
|
||||
通常、画像を並べてレイアウトすることはできません。画像を並べるには、以下のような方法があります。
|
||||
|
||||
```md
|
||||
```html
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -367,7 +367,7 @@ _참고:
|
||||
|
||||
그럴땐, 이렇게 해보세요!
|
||||
|
||||
```md
|
||||
```html
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -340,7 +340,7 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
|
||||
|
||||
तपाइले इमेजलाई सइद बय सइद अलीग्न गर्न सक्नु हुदैन तेसैले येसरी गर्नु होस् :
|
||||
|
||||
```md
|
||||
```html
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#demo">Ver demonstração</a>
|
||||
<a href="#demonstração">Ver demonstração</a>
|
||||
·
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats/issues/new/choose">Reportar erros</a>
|
||||
·
|
||||
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+1
-1
@@ -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
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats">
|
||||
<img align="center" src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats" />
|
||||
</a>
|
||||
|
||||
+15
-5
@@ -7,27 +7,37 @@
|
||||
"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",
|
||||
"format": "./node_modules/.bin/prettier --write .",
|
||||
"format:check": "./node_modules/.bin/prettier --check ."
|
||||
},
|
||||
"author": "Anurag Hazra",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/core": "^1.2.4",
|
||||
"@actions/github": "^4.0.0",
|
||||
"@testing-library/dom": "^7.20.0",
|
||||
"@testing-library/jest-dom": "^5.11.0",
|
||||
"axios": "^0.19.2",
|
||||
"@uppercod/css-to-object": "^1.1.1",
|
||||
"axios-mock-adapter": "^1.18.1",
|
||||
"css-to-object": "^1.1.0",
|
||||
"color-contrast-checker": "^2.1.0",
|
||||
"hjson": "^3.2.2",
|
||||
"husky": "^4.2.5",
|
||||
"jest": "^26.1.0",
|
||||
"parse-diff": "^0.7.0"
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"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": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img width="100px" src="https://res.cloudinary.com/anuraghazra/image/upload/v1594908242/logo_ccswme.svg" align="center" alt="GitHub Readme Stats" />
|
||||
<h2 align="center">GitHub Readme Stats</h2>
|
||||
<p align="center">Get dynamically generated GitHub stats on your readmes!</p>
|
||||
<p align="center">Get dynamically generated GitHub stats on your READMEs!</p>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats/actions">
|
||||
@@ -32,6 +32,8 @@
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats/issues/new/choose">Report Bug</a>
|
||||
·
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats/issues/new/choose">Request Feature</a>
|
||||
·
|
||||
<a href="https://github.com/anuraghazra/github-readme-stats/discussions">Ask Question</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="/docs/readme_fr.md">Français </a>
|
||||
@@ -65,13 +67,13 @@
|
||||
<img src="https://d2wvdrxmr8p0wf.cloudfront.net/static/giveindia.svg" alt="Give india logo" width="200" />
|
||||
</a>
|
||||
|
||||
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:
|
||||
</p>
|
||||
|
||||
|
||||
@@ -83,13 +85,18 @@ Your small help goes a long way. :heart:
|
||||
- [Wakatime Week Stats](#wakatime-week-stats)
|
||||
- [Themes](#themes)
|
||||
- [Customization](#customization)
|
||||
- [Common Options](#common-options)
|
||||
- [Stats Card Exclusive Options](#stats-card-exclusive-options)
|
||||
- [Repo Card Exclusive Options](#repo-card-exclusive-options)
|
||||
- [Language Card Exclusive Options](#language-card-exclusive-options)
|
||||
- [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
|
||||
- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
|
||||
|
||||
# GitHub Stats Card
|
||||
|
||||
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)
|
||||
@@ -97,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`
|
||||
|
||||
@@ -111,9 +118,9 @@ 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 chose to share your private contribution counts._
|
||||
_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._
|
||||
|
||||
> Options: `&count_private=true`
|
||||
|
||||
@@ -133,13 +140,13 @@ To enable icons, you can pass `show_icons=true` in the query param, like so:
|
||||
|
||||
With inbuilt themes, you can customize the look of the card without doing any [manual customization](#customization).
|
||||
|
||||
Use `?theme=THEME_NAME` parameter like so :-
|
||||
Use `&theme=THEME_NAME` parameter like so :-
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
#### All inbuilt themes :-
|
||||
#### All inbuilt themes:-
|
||||
|
||||
dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontrast, dracula
|
||||
|
||||
@@ -160,13 +167,15 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
|
||||
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_
|
||||
- `hide_border` - Hides the card's border _(boolean)_
|
||||
- `theme` - name of the theme, choose from [all available themes](./themes/README.md)
|
||||
- `cache_seconds` - set the cache header manually _(min: 1800, max: 86400)_
|
||||
- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_
|
||||
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_
|
||||
- `border_radius` - Corner rounding on the card_
|
||||
- `border_radius` - Corner rounding on the card
|
||||
|
||||
> Note: The minimum of cache_seconds is currently 4 hours as a temporary fix for PATs exhaustion.
|
||||
|
||||
##### 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
|
||||
@@ -176,14 +185,17 @@ 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)_
|
||||
- `card_width` - Set the card's width manually _(number)_
|
||||
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width
|
||||
- `show_icons` - _(boolean)_
|
||||
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_
|
||||
- `count_private` - Count private commits _(boolean)_
|
||||
- `line_height` - Sets the line-height between text _(number)_
|
||||
- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_
|
||||
- `custom_title` - Sets a custom title for the card
|
||||
- `text_bold` - Use bold text _(boolean)_
|
||||
- `disable_animations` - Disables all animations in the card _(boolean)_
|
||||
|
||||
#### Repo Card Exclusive Options:
|
||||
@@ -207,14 +219,15 @@ You can provide multiple comma-separated values in bg_color option to render a g
|
||||
|
||||
#### Wakatime Card Exclusive Options:
|
||||
|
||||
- `hide` - Hide the languages specified from the card _(Comma-separated values)_
|
||||
- `hide_title` - _(boolean)_
|
||||
- `line_height` - Sets the line-height between text _(number)_
|
||||
- `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.
|
||||
|
||||
---
|
||||
|
||||
@@ -244,9 +257,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
|
||||
|
||||
@@ -260,7 +273,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)
|
||||
@@ -268,7 +281,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)
|
||||
@@ -306,6 +319,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)
|
||||
@@ -403,14 +418,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!
|
||||
|
||||
@@ -421,7 +438,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:
|
||||
@@ -437,3 +454,4 @@ Thanks! :heart:
|
||||
Contributions are welcome! <3
|
||||
|
||||
Made with :heart: and JavaScript.
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
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, " "),
|
||||
);
|
||||
});
|
||||
@@ -12,7 +12,7 @@ const THEME_TEMPLATE = `## Available Themes
|
||||
|
||||
<!-- DO NOT EDIT THIS FILE DIRECTLY -->
|
||||
|
||||
With inbuilt themes you can customize the look of the card without doing any manual customization.
|
||||
With inbuilt themes, you can customize the look of the card without doing any manual customization.
|
||||
|
||||
Use \`?theme=THEME_NAME\` parameter like so :-
|
||||
|
||||
@@ -43,7 +43,7 @@ ${REPO_CARD_LINKS_FLAG}
|
||||
|
||||
[add-theme]: https://github.com/anuraghazra/github-readme-stats/edit/master/themes/index.js
|
||||
|
||||
Wanted to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
||||
Want to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
||||
`;
|
||||
|
||||
const createRepoMdLink = (theme) => {
|
||||
|
||||
+119
-31
@@ -1,8 +1,16 @@
|
||||
const core = require("@actions/core");
|
||||
const github = require("@actions/github");
|
||||
const parse = require("parse-diff");
|
||||
const Hjson = require("hjson");
|
||||
const snakeCase = require("lodash.snakecase");
|
||||
const ColorContrastChecker = require("color-contrast-checker");
|
||||
|
||||
require("dotenv").config();
|
||||
|
||||
const OWNER = "anuraghazra";
|
||||
const REPO = "github-readme-stats";
|
||||
const COMMENT_TITLE = "Automated Theme Preview";
|
||||
|
||||
function getPrNumber() {
|
||||
const pullRequest = github.context.payload.pull_request;
|
||||
if (!pullRequest) {
|
||||
@@ -12,17 +20,72 @@ function getPrNumber() {
|
||||
return pullRequest.number;
|
||||
}
|
||||
|
||||
function findCommentPredicate(inputs, comment) {
|
||||
return (
|
||||
(inputs.commentAuthor && comment.user
|
||||
? comment.user.login === inputs.commentAuthor
|
||||
: true) &&
|
||||
(inputs.bodyIncludes && comment.body
|
||||
? comment.body.includes(inputs.bodyIncludes)
|
||||
: true)
|
||||
);
|
||||
}
|
||||
|
||||
async function findComment(octokit, issueNumber) {
|
||||
const parameters = {
|
||||
owner: OWNER,
|
||||
repo: REPO,
|
||||
issue_number: issueNumber,
|
||||
};
|
||||
const inputs = {
|
||||
commentAuthor: OWNER,
|
||||
bodyIncludes: COMMENT_TITLE,
|
||||
};
|
||||
|
||||
for await (const { data: comments } of octokit.paginate.iterator(
|
||||
octokit.rest.issues.listComments,
|
||||
parameters,
|
||||
)) {
|
||||
// Search each page for the comment
|
||||
const comment = comments.find((comment) =>
|
||||
findCommentPredicate(inputs, comment),
|
||||
);
|
||||
if (comment) return comment;
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertComment(octokit, props) {
|
||||
if (props.comment_id !== undefined) {
|
||||
await octokit.issues.updateComment(props);
|
||||
} else {
|
||||
await octokit.issues.createComment(props);
|
||||
}
|
||||
}
|
||||
|
||||
function getWebAimLink(color1, color2) {
|
||||
return `https://webaim.org/resources/contrastchecker/?fcolor=${color1}&bcolor=${color2}`;
|
||||
}
|
||||
|
||||
function getGrsLink(colors) {
|
||||
const url = `https://github-readme-stats.vercel.app/api?username=anuraghazra`;
|
||||
const colorString = Object.keys(colors)
|
||||
.map((colorKey) => `${colorKey}=${colors[colorKey]}`)
|
||||
.join("&");
|
||||
|
||||
return `${url}&${colorString}&show_icons=true`;
|
||||
}
|
||||
|
||||
const themeContribGuidelines = `
|
||||
\r> Hi thanks for the theme contribution, please read our theme contribution guidelines
|
||||
\rHi, thanks for the theme contribution, please read our theme [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution).
|
||||
\rWe are currently only accepting color combinations from any VSCode theme or themes which have good color combination to minimize bloating the themes collection.
|
||||
|
||||
\r> We are currently only accepting color combinations from any vscode theme or which has good color combination to minimize bloating the themes collection.
|
||||
|
||||
\r> Also note that if this theme is exclusively for your personal use then instead of adding it to our theme collection you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization)
|
||||
\r> Read our [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md) for more info
|
||||
\r> Also note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization)
|
||||
`;
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const ccc = new ColorContrastChecker();
|
||||
const warnings = [];
|
||||
const token = core.getInput("token");
|
||||
const octokit = github.getOctokit(token || process.env.PERSONAL_TOKEN);
|
||||
const pullRequestId = getPrNumber();
|
||||
@@ -32,65 +95,90 @@ async function run() {
|
||||
return;
|
||||
}
|
||||
|
||||
let res = await octokit.pulls.get({
|
||||
owner: "anuraghazra",
|
||||
repo: "github-readme-stats",
|
||||
const res = await octokit.pulls.get({
|
||||
owner: OWNER,
|
||||
repo: REPO,
|
||||
pull_number: pullRequestId,
|
||||
mediaType: {
|
||||
format: "diff",
|
||||
},
|
||||
});
|
||||
const comment = await findComment(octokit, pullRequestId);
|
||||
|
||||
let diff = parse(res.data);
|
||||
let colorStrings = diff
|
||||
const diff = parse(res.data);
|
||||
const content = diff
|
||||
.find((file) => file.to === "themes/index.js")
|
||||
.chunks[0].changes.filter((c) => c.type === "add")
|
||||
.map((c) => c.content.replace("+", ""))
|
||||
.join("");
|
||||
|
||||
let matches = colorStrings.match(/(title_color:.*bg_color.*\")/);
|
||||
let colors = matches && matches[0].split(",");
|
||||
const themeObject = Hjson.parse(content);
|
||||
const themeName = Object.keys(themeObject)[0];
|
||||
const colors = themeObject[themeName];
|
||||
|
||||
if (themeName !== snakeCase(themeName)) {
|
||||
warnings.push("Theme name isn't in snake_case");
|
||||
}
|
||||
|
||||
if (!colors) {
|
||||
await octokit.issues.createComment({
|
||||
owner: "anuraghazra",
|
||||
repo: "github-readme-stats",
|
||||
await upsertComment({
|
||||
comment_id: comment?.id,
|
||||
owner: OWNER,
|
||||
repo: REPO,
|
||||
issue_number: pullRequestId,
|
||||
body: `
|
||||
\rTheme preview (bot)
|
||||
\r**${COMMENT_TITLE}**
|
||||
|
||||
\rCannot create theme preview
|
||||
|
||||
${themeContribGuidelines}
|
||||
`,
|
||||
issue_number: pullRequestId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
colors = colors.map((color) =>
|
||||
color.replace(/.*\:\s/, "").replace(/\"/g, ""),
|
||||
);
|
||||
|
||||
const titleColor = colors[0];
|
||||
const iconColor = colors[1];
|
||||
const textColor = colors[2];
|
||||
const bgColor = colors[3];
|
||||
const url = `https://github-readme-stats.vercel.app/api?username=anuraghazra&title_color=${titleColor}&icon_color=${iconColor}&text_color=${textColor}&bg_color=${bgColor}&show_icons=true`;
|
||||
const titleColor = colors.title_color;
|
||||
const iconColor = colors.icon_color;
|
||||
const textColor = colors.text_color;
|
||||
const bgColor = colors.bg_color;
|
||||
const url = getGrsLink(colors);
|
||||
|
||||
await octokit.issues.createComment({
|
||||
owner: "anuraghazra",
|
||||
repo: "github-readme-stats",
|
||||
const colorPairs = {
|
||||
title_color: [titleColor, bgColor],
|
||||
icon_color: [iconColor, bgColor],
|
||||
text_color: [textColor, bgColor],
|
||||
};
|
||||
|
||||
// check color contrast
|
||||
Object.keys(colorPairs).forEach((key) => {
|
||||
const color1 = colorPairs[key][0];
|
||||
const color2 = colorPairs[key][1];
|
||||
if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) {
|
||||
const permalink = getWebAimLink(color1, color2);
|
||||
warnings.push(
|
||||
`\`${key}\` does not pass [AA contrast ratio](${permalink})`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
await upsertComment(octokit, {
|
||||
comment_id: comment?.id,
|
||||
issue_number: pullRequestId,
|
||||
owner: OWNER,
|
||||
repo: REPO,
|
||||
body: `
|
||||
\rTheme preview (bot)
|
||||
\r**${COMMENT_TITLE}**
|
||||
|
||||
\r${warnings.map((warning) => `- :warning: ${warning}\n`).join("")}
|
||||
|
||||
\ntitle_color: <code>#${titleColor}</code> | icon_color: <code>#${iconColor}</code> | text_color: <code>#${textColor}</code> | bg_color: <code>#${bgColor}</code>
|
||||
|
||||
\rLink: ${url}
|
||||
\r[Preview Link](${url})
|
||||
|
||||
\r[](${url})
|
||||
|
||||
${themeContribGuidelines}
|
||||
`,
|
||||
issue_number: pullRequestId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
+8
-14
@@ -36,20 +36,14 @@ function calculateRank({
|
||||
const RANK_A = 0.50;
|
||||
const RANK_B_PLUS = 0.75;
|
||||
|
||||
let level = "";
|
||||
|
||||
if (rank <= RANK_S_PLUS)
|
||||
level = "S+";
|
||||
else if (rank <= RANK_S)
|
||||
level = "S";
|
||||
else if (rank <= RANK_A_PLUS)
|
||||
level = "A+";
|
||||
else if (rank <= RANK_A)
|
||||
level = "A";
|
||||
else if (rank <= RANK_B_PLUS)
|
||||
level = "B+";
|
||||
else
|
||||
level = "B";
|
||||
const level = (() => {
|
||||
if (rank <= RANK_S_PLUS) return "S+";
|
||||
if (rank <= RANK_S) return "S";
|
||||
if (rank <= RANK_A_PLUS) return "A+";
|
||||
if (rank <= RANK_A) return "A";
|
||||
if (rank <= RANK_B_PLUS) return "B+";
|
||||
return "B";
|
||||
})();
|
||||
|
||||
return {level, score: rank * 100};
|
||||
}
|
||||
|
||||
+92
-83
@@ -1,25 +1,85 @@
|
||||
const toEmoji = require("emoji-name-map");
|
||||
// @ts-check
|
||||
const {
|
||||
kFormatter,
|
||||
encodeHTML,
|
||||
getCardColors,
|
||||
flexLayout,
|
||||
wrapTextMultiline,
|
||||
measureText,
|
||||
parseEmojis,
|
||||
} = require("../common/utils");
|
||||
const I18n = require("../common/I18n");
|
||||
const Card = require("../common/Card");
|
||||
const icons = require("../common/icons");
|
||||
const { repoCardLocales } = require("../translations");
|
||||
|
||||
/**
|
||||
* @param {string} label
|
||||
* @param {string} textColor
|
||||
* @returns {string}
|
||||
*/
|
||||
const getBadgeSVG = (label, textColor) => `
|
||||
<g data-testid="badge" class="badge" transform="translate(320, -18)">
|
||||
<rect stroke="${textColor}" stroke-width="1" width="70" height="20" x="-12" y="-14" ry="10" rx="10"></rect>
|
||||
<text
|
||||
x="23" y="-5"
|
||||
alignment-baseline="central"
|
||||
dominant-baseline="central"
|
||||
text-anchor="middle"
|
||||
fill="${textColor}"
|
||||
>
|
||||
${label}
|
||||
</text>
|
||||
</g>
|
||||
`;
|
||||
|
||||
/**
|
||||
* @param {string} langName
|
||||
* @param {string} langColor
|
||||
* @returns {string}
|
||||
*/
|
||||
const createLanguageNode = (langName, langColor) => {
|
||||
return `
|
||||
<g data-testid="primary-lang">
|
||||
<circle data-testid="lang-color" cx="0" cy="-5" r="6" fill="${langColor}" />
|
||||
<text data-testid="lang-name" class="gray" x="15">${langName}</text>
|
||||
</g>
|
||||
`;
|
||||
};
|
||||
|
||||
const ICON_SIZE = 16;
|
||||
const iconWithLabel = (icon, label, testid) => {
|
||||
if (label <= 0) return "";
|
||||
const iconSvg = `
|
||||
<svg
|
||||
class="icon"
|
||||
y="-12"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
width="${ICON_SIZE}"
|
||||
height="${ICON_SIZE}"
|
||||
>
|
||||
${icon}
|
||||
</svg>
|
||||
`;
|
||||
const text = `<text data-testid="${testid}" class="gray">${label}</text>`;
|
||||
return flexLayout({ items: [iconSvg, text], gap: 20 }).join("");
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('../fetchers/types').RepositoryData} repo
|
||||
* @param {Partial<import("./types").RepoCardOptions>} options
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderRepoCard = (repo, options = {}) => {
|
||||
const {
|
||||
name,
|
||||
nameWithOwner,
|
||||
description,
|
||||
primaryLanguage,
|
||||
stargazers,
|
||||
isArchived,
|
||||
isTemplate,
|
||||
starCount,
|
||||
forkCount,
|
||||
} = repo;
|
||||
const {
|
||||
@@ -35,22 +95,17 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
locale,
|
||||
} = options;
|
||||
|
||||
const lineHeight = 10;
|
||||
const header = show_owner ? nameWithOwner : name;
|
||||
const langName = (primaryLanguage && primaryLanguage.name) || "Unspecified";
|
||||
const langColor = (primaryLanguage && primaryLanguage.color) || "#333";
|
||||
|
||||
const shiftText = langName.length > 15 ? 0 : 30;
|
||||
|
||||
let desc = description || "No description provided";
|
||||
|
||||
// parse emojis to unicode
|
||||
desc = desc.replace(/:\w+:/gm, (emoji) => {
|
||||
return toEmoji.get(emoji) || "";
|
||||
});
|
||||
|
||||
const desc = parseEmojis(description || "No description provided");
|
||||
const multiLineDescription = wrapTextMultiline(desc);
|
||||
const descriptionLines = multiLineDescription.length;
|
||||
const lineHeight = 10;
|
||||
const descriptionSvg = multiLineDescription
|
||||
.map((line) => `<tspan dy="1.2em" x="25">${encodeHTML(line)}</tspan>`)
|
||||
.join("");
|
||||
|
||||
const height =
|
||||
(descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight;
|
||||
@@ -61,13 +116,7 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
});
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
const {
|
||||
titleColor,
|
||||
textColor,
|
||||
iconColor,
|
||||
bgColor,
|
||||
borderColor,
|
||||
} = getCardColors({
|
||||
const colors = getCardColors({
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
@@ -76,74 +125,41 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
theme,
|
||||
});
|
||||
|
||||
const totalStars = kFormatter(stargazers.totalCount);
|
||||
const totalForks = kFormatter(forkCount);
|
||||
|
||||
const getBadgeSVG = (label) => `
|
||||
<g data-testid="badge" class="badge" transform="translate(320, -18)">
|
||||
<rect stroke="${textColor}" stroke-width="1" width="70" height="20" x="-12" y="-14" ry="10" rx="10"></rect>
|
||||
<text
|
||||
x="23" y="-5"
|
||||
alignment-baseline="central"
|
||||
dominant-baseline="central"
|
||||
text-anchor="middle"
|
||||
fill="${textColor}"
|
||||
>
|
||||
${label}
|
||||
</text>
|
||||
</g>
|
||||
`;
|
||||
|
||||
const svgLanguage = primaryLanguage
|
||||
? `
|
||||
<g data-testid="primary-lang" transform="translate(30, 0)">
|
||||
<circle data-testid="lang-color" cx="0" cy="-5" r="6" fill="${langColor}" />
|
||||
<text data-testid="lang-name" class="gray" x="15">${langName}</text>
|
||||
</g>
|
||||
`
|
||||
? createLanguageNode(langName, langColor)
|
||||
: "";
|
||||
|
||||
const iconWithLabel = (icon, label, testid) => {
|
||||
return `
|
||||
<svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16">
|
||||
${icon}
|
||||
</svg>
|
||||
<text data-testid="${testid}" class="gray" x="25">${label}</text>
|
||||
`;
|
||||
};
|
||||
const svgStars =
|
||||
stargazers.totalCount > 0 &&
|
||||
iconWithLabel(icons.star, totalStars, "stargazers");
|
||||
const svgForks =
|
||||
forkCount > 0 && iconWithLabel(icons.fork, totalForks, "forkcount");
|
||||
const totalStars = kFormatter(starCount);
|
||||
const totalForks = kFormatter(forkCount);
|
||||
const svgStars = iconWithLabel(icons.star, totalStars, "stargazers");
|
||||
const svgForks = iconWithLabel(icons.fork, totalForks, "forkcount");
|
||||
|
||||
const starAndForkCount = flexLayout({
|
||||
items: [svgStars, svgForks],
|
||||
gap: 65,
|
||||
items: [svgLanguage, svgStars, svgForks],
|
||||
sizes: [
|
||||
measureText(langName, 12),
|
||||
ICON_SIZE + measureText(`${totalStars}`, 12),
|
||||
ICON_SIZE + measureText(`${totalForks}`, 12),
|
||||
],
|
||||
gap: 25,
|
||||
}).join("");
|
||||
|
||||
const card = new Card({
|
||||
defaultTitle: header,
|
||||
defaultTitle: header.length > 35 ? `${header.slice(0, 35)}...` : header,
|
||||
titlePrefixIcon: icons.contribs,
|
||||
width: 400,
|
||||
height,
|
||||
border_radius,
|
||||
colors: {
|
||||
titleColor,
|
||||
textColor,
|
||||
iconColor,
|
||||
bgColor,
|
||||
borderColor,
|
||||
},
|
||||
colors,
|
||||
});
|
||||
|
||||
card.disableAnimations();
|
||||
card.setHideBorder(hide_border);
|
||||
card.setHideTitle(false);
|
||||
card.setCSS(`
|
||||
.description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
|
||||
.gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
|
||||
.icon { fill: ${iconColor} }
|
||||
.description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
|
||||
.gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
|
||||
.icon { fill: ${colors.iconColor} }
|
||||
.badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; }
|
||||
.badge rect { opacity: 0.2 }
|
||||
`);
|
||||
@@ -151,27 +167,20 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
return card.render(`
|
||||
${
|
||||
isTemplate
|
||||
? getBadgeSVG(i18n.t("repocard.template"))
|
||||
? // @ts-ignore
|
||||
getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
|
||||
: isArchived
|
||||
? getBadgeSVG(i18n.t("repocard.archived"))
|
||||
? // @ts-ignore
|
||||
getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
|
||||
: ""
|
||||
}
|
||||
|
||||
<text class="description" x="25" y="-5">
|
||||
${multiLineDescription
|
||||
.map((line) => `<tspan dy="1.2em" x="25">${encodeHTML(line)}</tspan>`)
|
||||
.join("")}
|
||||
${descriptionSvg}
|
||||
</text>
|
||||
|
||||
<g transform="translate(0, ${height - 75})">
|
||||
${svgLanguage}
|
||||
|
||||
<g
|
||||
data-testid="star-fork-group"
|
||||
transform="translate(${primaryLanguage ? 155 - shiftText : 25}, 0)"
|
||||
>
|
||||
${starAndForkCount}
|
||||
</g>
|
||||
<g transform="translate(30, ${height - 75})">
|
||||
${starAndForkCount}
|
||||
</g>
|
||||
`);
|
||||
};
|
||||
|
||||
+102
-50
@@ -1,3 +1,4 @@
|
||||
// @ts-check
|
||||
const I18n = require("../common/I18n");
|
||||
const Card = require("../common/Card");
|
||||
const icons = require("../common/icons");
|
||||
@@ -19,6 +20,7 @@ const createTextNode = ({
|
||||
index,
|
||||
showIcons,
|
||||
shiftValuePos,
|
||||
bold,
|
||||
}) => {
|
||||
const kValue = kFormatter(value);
|
||||
const staggerDelay = (index + 3) * 150;
|
||||
@@ -34,17 +36,24 @@ const createTextNode = ({
|
||||
return `
|
||||
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
|
||||
${iconSvg}
|
||||
<text class="stat bold" ${labelOffset} y="12.5">${label}:</text>
|
||||
<text
|
||||
class="stat"
|
||||
x="${(showIcons ? 140 : 120) + shiftValuePos}"
|
||||
y="12.5"
|
||||
<text class="stat ${
|
||||
bold ? " bold" : "not_bold"
|
||||
}" ${labelOffset} y="12.5">${label}:</text>
|
||||
<text
|
||||
class="stat ${bold ? " bold" : "not_bold"}"
|
||||
x="${(showIcons ? 140 : 120) + shiftValuePos}"
|
||||
y="12.5"
|
||||
data-testid="${id}"
|
||||
>${kValue}</text>
|
||||
</g>
|
||||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Partial<import('../fetchers/types').StatsData>} stats
|
||||
* @param {Partial<import("./types").StatCardOptions>} options
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
const {
|
||||
name,
|
||||
@@ -60,12 +69,14 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
show_icons = false,
|
||||
hide_title = false,
|
||||
hide_border = false,
|
||||
card_width,
|
||||
hide_rank = false,
|
||||
include_all_commits = false,
|
||||
line_height = 25,
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
text_bold = true,
|
||||
bg_color,
|
||||
theme = "default",
|
||||
custom_title,
|
||||
@@ -75,23 +86,18 @@ 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,
|
||||
} = 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 apostrophe = ["x", "s"].includes(name.slice(-1).toLocaleLowerCase())
|
||||
? ""
|
||||
@@ -147,6 +153,8 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
"id",
|
||||
"my",
|
||||
"pl",
|
||||
"de",
|
||||
"nl",
|
||||
];
|
||||
const isLongLocale = longLocales.includes(locale) === true;
|
||||
|
||||
@@ -160,7 +168,8 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
index,
|
||||
showIcons: show_icons,
|
||||
shiftValuePos:
|
||||
(!include_all_commits ? 50 : 20) + (isLongLocale ? 50 : 0),
|
||||
(!include_all_commits ? 50 : 35) + (isLongLocale ? 50 : 0),
|
||||
bold: text_bold,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -171,26 +180,6 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
hide_rank ? 0 : 150,
|
||||
);
|
||||
|
||||
// Conditionally rendered elements
|
||||
const rankCircle = hide_rank
|
||||
? ""
|
||||
: `<g data-testid="rank-circle"
|
||||
transform="translate(400, ${height / 2 - 50})">
|
||||
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
|
||||
<circle class="rank-circle" cx="-10" cy="8" r="40" />
|
||||
<g class="rank-text">
|
||||
<text
|
||||
x="${rank.level.length === 1 ? "-4" : "0"}"
|
||||
y="0"
|
||||
alignment-baseline="central"
|
||||
dominant-baseline="central"
|
||||
text-anchor="middle"
|
||||
>
|
||||
${rank.level}
|
||||
</text>
|
||||
</g>
|
||||
</g>`;
|
||||
|
||||
// the better user's score the the rank will be closer to zero so
|
||||
// subtracting 100 to get the progress in 100%
|
||||
const progress = 100 - rank.score;
|
||||
@@ -206,13 +195,20 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
return measureText(custom_title ? custom_title : i18n.t("statcard.title"));
|
||||
};
|
||||
|
||||
const width = hide_rank
|
||||
? clampValue(
|
||||
50 /* padding */ + calculateTextWidth() * 2,
|
||||
270 /* min */,
|
||||
Infinity,
|
||||
)
|
||||
: 495;
|
||||
/*
|
||||
When hide_rank=true, the minimum card width is 270 px + the title length and padding.
|
||||
When hide_rank=false, the minimum card_width is 340 px + the icon width (if show_icons=true).
|
||||
Numbers are picked by looking at existing dimensions on production.
|
||||
*/
|
||||
const iconWidth = show_icons ? 16 : 0;
|
||||
const minCardWidth = hide_rank
|
||||
? clampValue(50 /* padding */ + calculateTextWidth() * 2, 270, Infinity)
|
||||
: 340 + iconWidth;
|
||||
const defaultCardWidth = hide_rank ? 270 : 495;
|
||||
let width = isNaN(card_width) ? defaultCardWidth : card_width;
|
||||
if (width < minCardWidth) {
|
||||
width = minCardWidth;
|
||||
}
|
||||
|
||||
const card = new Card({
|
||||
customTitle: custom_title,
|
||||
@@ -235,16 +231,72 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
|
||||
if (disable_animations) card.disableAnimations();
|
||||
|
||||
/**
|
||||
* Calculates the right rank circle translation values such that the rank circle
|
||||
* keeps respecting the padding.
|
||||
*
|
||||
* width > 450: The default left padding of 50 px will be used.
|
||||
* width < 450: The left and right padding will shrink equally.
|
||||
*
|
||||
* @returns {number} - Rank circle translation value.
|
||||
*/
|
||||
const calculateRankXTranslation = () => {
|
||||
if (width < 450) {
|
||||
return width - 95 + (45 * (450 - 340)) / 110;
|
||||
} else {
|
||||
return width - 95;
|
||||
}
|
||||
};
|
||||
|
||||
// Conditionally rendered elements
|
||||
const rankCircle = hide_rank
|
||||
? ""
|
||||
: `<g data-testid="rank-circle"
|
||||
transform="translate(${calculateRankXTranslation()}, ${
|
||||
height / 2 - 50
|
||||
})">
|
||||
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
|
||||
<circle class="rank-circle" cx="-10" cy="8" r="40" />
|
||||
<g class="rank-text">
|
||||
<text
|
||||
x="-5"
|
||||
y="3"
|
||||
alignment-baseline="central"
|
||||
dominant-baseline="central"
|
||||
text-anchor="middle"
|
||||
>
|
||||
${rank.level}
|
||||
</text>
|
||||
</g>
|
||||
</g>`;
|
||||
|
||||
// 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}
|
||||
|
||||
<svg x="0" y="0">
|
||||
${flexLayout({
|
||||
items: statItems,
|
||||
gap: lheight,
|
||||
direction: "column",
|
||||
}).join("")}
|
||||
</svg>
|
||||
</svg>
|
||||
`);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,45 @@
|
||||
// @ts-check
|
||||
const Card = require("../common/Card");
|
||||
const I18n = require("../common/I18n");
|
||||
const { langCardLocales } = require("../translations");
|
||||
const { createProgressNode } = require("../common/createProgressNode");
|
||||
const { clampValue, getCardColors, flexLayout } = require("../common/utils");
|
||||
const {
|
||||
clampValue,
|
||||
getCardColors,
|
||||
flexLayout,
|
||||
lowercaseTrim,
|
||||
measureText,
|
||||
chunkArray,
|
||||
} = require("../common/utils");
|
||||
|
||||
const DEFAULT_CARD_WIDTH = 300;
|
||||
const MIN_CARD_WIDTH = 230;
|
||||
const DEFAULT_LANGS_COUNT = 5;
|
||||
const DEFAULT_LANG_COLOR = "#858585";
|
||||
const CARD_PADDING = 25;
|
||||
|
||||
const lowercaseTrim = (name) => name.toLowerCase().trim();
|
||||
/**
|
||||
* @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;
|
||||
@@ -30,12 +59,15 @@ const createProgressTextNode = ({ width, color, name, progress }) => {
|
||||
`;
|
||||
};
|
||||
|
||||
const createCompactLangNode = ({ lang, totalSize, x, y }) => {
|
||||
/**
|
||||
* @param {{ lang: Lang, totalSize: number }} props
|
||||
*/
|
||||
const createCompactLangNode = ({ lang, totalSize }) => {
|
||||
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
|
||||
const color = lang.color || "#858585";
|
||||
|
||||
return `
|
||||
<g transform="translate(${x}, ${y})">
|
||||
<g>
|
||||
<circle cx="5" cy="6" r="5" fill="${color}" />
|
||||
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
|
||||
${lang.name} ${percentage}%
|
||||
@@ -44,30 +76,40 @@ const createCompactLangNode = ({ lang, totalSize, x, y }) => {
|
||||
`;
|
||||
};
|
||||
|
||||
const createLanguageTextNode = ({ langs, totalSize, x, y }) => {
|
||||
return langs.map((lang, index) => {
|
||||
if (index % 2 === 0) {
|
||||
return createCompactLangNode({
|
||||
/**
|
||||
* @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,
|
||||
x,
|
||||
y: 12.5 * index + y,
|
||||
totalSize,
|
||||
// @ts-ignore
|
||||
index,
|
||||
});
|
||||
}
|
||||
return createCompactLangNode({
|
||||
lang,
|
||||
x: 150,
|
||||
y: 12.5 + 12.5 * index,
|
||||
totalSize,
|
||||
index,
|
||||
});
|
||||
}),
|
||||
);
|
||||
return flexLayout({
|
||||
items,
|
||||
gap: 25,
|
||||
direction: "column",
|
||||
}).join("");
|
||||
});
|
||||
|
||||
const percent = ((longestLang.size / totalSize) * 100).toFixed(2);
|
||||
const minGap = 150;
|
||||
const maxGap = 20 + measureText(`${longestLang.name} ${percent}%`, 11);
|
||||
return flexLayout({
|
||||
items: layouts,
|
||||
gap: maxGap < minGap ? minGap : maxGap,
|
||||
}).join("");
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any[]} langs
|
||||
* @param {Lang[]} langs
|
||||
* @param {number} width
|
||||
* @param {number} totalLanguageSize
|
||||
* @returns {string}
|
||||
@@ -88,8 +130,7 @@ const renderNormalLayout = (langs, width, totalLanguageSize) => {
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any[]} langs
|
||||
* @param {Lang[]} langs
|
||||
* @param {number} width
|
||||
* @param {number} totalLanguageSize
|
||||
* @returns {string}
|
||||
@@ -129,12 +170,13 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
|
||||
<rect x="0" y="0" width="${offsetWidth}" height="8" fill="white" rx="5" />
|
||||
</mask>
|
||||
${compactProgressBar}
|
||||
${createLanguageTextNode({
|
||||
x: 0,
|
||||
y: 25,
|
||||
langs,
|
||||
totalSize: totalLanguageSize,
|
||||
}).join("")}
|
||||
|
||||
<g transform="translate(0, 25)">
|
||||
${createLanguageTextNode({
|
||||
langs,
|
||||
totalSize: totalLanguageSize,
|
||||
})}
|
||||
</g>
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -154,6 +196,12 @@ const calculateNormalLayoutHeight = (totalLangs) => {
|
||||
return 45 + (totalLangs + 1) * 40;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Record<string, Lang>} topLangs
|
||||
* @param {string[]} hide
|
||||
* @param {string} langs_count
|
||||
*/
|
||||
const useLanguages = (topLangs, hide, langs_count) => {
|
||||
let langs = Object.values(topLangs);
|
||||
let langsToHide = {};
|
||||
@@ -167,7 +215,7 @@ const useLanguages = (topLangs, hide, langs_count) => {
|
||||
});
|
||||
}
|
||||
|
||||
// filter out langauges to be hidden
|
||||
// filter out languages to be hidden
|
||||
langs = langs
|
||||
.sort((a, b) => b.size - a.size)
|
||||
.filter((lang) => {
|
||||
@@ -180,6 +228,11 @@ const useLanguages = (topLangs, hide, langs_count) => {
|
||||
return { langs, totalLanguageSize };
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('../fetchers/types').TopLangData} topLangs
|
||||
* @param {Partial<import("./types").TopLangOptions>} options
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderTopLanguages = (topLangs, options = {}) => {
|
||||
const {
|
||||
hide_title,
|
||||
@@ -206,10 +259,14 @@ 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;
|
||||
let width = isNaN(card_width)
|
||||
? DEFAULT_CARD_WIDTH
|
||||
: card_width < MIN_CARD_WIDTH
|
||||
? MIN_CARD_WIDTH
|
||||
: card_width;
|
||||
let height = calculateNormalLayoutHeight(langs.length);
|
||||
|
||||
let finalLayout = "";
|
||||
@@ -255,3 +312,4 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
||||
};
|
||||
|
||||
module.exports = renderTopLanguages;
|
||||
module.exports.MIN_CARD_WIDTH = MIN_CARD_WIDTH;
|
||||
|
||||
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
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;
|
||||
card_width: number;
|
||||
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;
|
||||
};
|
||||
+109
-44
@@ -1,17 +1,35 @@
|
||||
// @ts-check
|
||||
const Card = require("../common/Card");
|
||||
const I18n = require("../common/I18n");
|
||||
const { getStyles } = require("../getStyles");
|
||||
const { wakatimeCardLocales } = require("../translations");
|
||||
const languageColors = require("../common/languageColors.json");
|
||||
const { createProgressNode } = require("../common/createProgressNode");
|
||||
const { clampValue, getCardColors, flexLayout } = require("../common/utils");
|
||||
const {
|
||||
clampValue,
|
||||
getCardColors,
|
||||
flexLayout,
|
||||
lowercaseTrim,
|
||||
} = require("../common/utils");
|
||||
|
||||
/**
|
||||
* @param {{color: string, text: string}} param0
|
||||
*/
|
||||
const noCodingActivityNode = ({ color, text }) => {
|
||||
return `
|
||||
<text x="25" y="11" class="stat bold" fill="${color}">${text}</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";
|
||||
|
||||
@@ -25,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) {
|
||||
@@ -33,7 +59,6 @@ const createLanguageTextNode = ({ langs, totalSize, x, y }) => {
|
||||
x: 25,
|
||||
y: 12.5 * index + y,
|
||||
totalSize,
|
||||
index,
|
||||
});
|
||||
}
|
||||
return createCompactLangNode({
|
||||
@@ -41,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,
|
||||
@@ -61,34 +98,56 @@ const createTextNode = ({
|
||||
const cardProgress = hideProgress
|
||||
? null
|
||||
: createProgressNode({
|
||||
x: 110,
|
||||
y: 4,
|
||||
progress: percent,
|
||||
color: progressBarColor,
|
||||
width: 220,
|
||||
name: label,
|
||||
progressBarBackgroundColor,
|
||||
});
|
||||
x: 110,
|
||||
y: 4,
|
||||
progress: percent,
|
||||
color: progressBarColor,
|
||||
width: 220,
|
||||
// @ts-ignore
|
||||
name: label,
|
||||
progressBarBackgroundColor,
|
||||
});
|
||||
|
||||
return `
|
||||
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
|
||||
<text class="stat bold" y="12.5">${label}:</text>
|
||||
<text class="stat bold" y="12.5" data-testid="${id}">${label}:</text>
|
||||
<text
|
||||
class="stat"
|
||||
x="${hideProgress ? 170 : 350}"
|
||||
y="12.5"
|
||||
data-testid="${id}"
|
||||
>${value}</text>
|
||||
${cardProgress}
|
||||
</g>
|
||||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import("../fetchers/types").WakaTimeLang[]} languages
|
||||
*/
|
||||
const recalculatePercentages = (languages) => {
|
||||
// recalculating percentages so that,
|
||||
// compact layout's progress bar does not break when hiding languages
|
||||
const totalSum = languages.reduce(
|
||||
(totalSum, language) => totalSum + language.percent,
|
||||
0,
|
||||
);
|
||||
const weight = +(100 / totalSum).toFixed(2);
|
||||
languages.forEach((language) => {
|
||||
language.percent = +(language.percent * weight).toFixed(2);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Partial<import('../fetchers/types').WakaTimeData>} stats
|
||||
* @param {Partial<import('./types').WakaTimeOptions>} options
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
|
||||
const { languages } = stats;
|
||||
let { languages } = stats;
|
||||
const {
|
||||
hide_title = false,
|
||||
hide_border = false,
|
||||
hide,
|
||||
line_height = 25,
|
||||
title_color,
|
||||
icon_color,
|
||||
@@ -104,35 +163,39 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
|
||||
border_color,
|
||||
} = options;
|
||||
|
||||
const shouldHideLangs = Array.isArray(hide) && hide.length > 0;
|
||||
if (shouldHideLangs && languages !== undefined) {
|
||||
const languagesToHide = new Set(hide.map((lang) => lowercaseTrim(lang)));
|
||||
languages = languages.filter(
|
||||
(lang) => !languagesToHide.has(lowercaseTrim(lang.name)),
|
||||
);
|
||||
recalculatePercentages(languages);
|
||||
}
|
||||
|
||||
const i18n = new I18n({
|
||||
locale,
|
||||
translations: wakatimeCardLocales,
|
||||
});
|
||||
|
||||
const lheight = parseInt(line_height, 10);
|
||||
const lheight = parseInt(String(line_height), 10);
|
||||
|
||||
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
|
||||
.filter((language) => language.hours || language.minutes)
|
||||
.slice(0, langsCount)
|
||||
.filter((language) => language.hours || language.minutes)
|
||||
.slice(0, langsCount)
|
||||
: [];
|
||||
|
||||
// Calculate the card height depending on how many items there are
|
||||
@@ -186,33 +249,35 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
|
||||
</mask>
|
||||
${compactProgressBar}
|
||||
${createLanguageTextNode({
|
||||
x: 0,
|
||||
y: 25,
|
||||
langs: filteredLanguages,
|
||||
totalSize: 100,
|
||||
}).join("")}
|
||||
x: 0,
|
||||
y: 25,
|
||||
langs: filteredLanguages,
|
||||
totalSize: 100,
|
||||
}).join("")}
|
||||
`;
|
||||
} else {
|
||||
finalLayout = flexLayout({
|
||||
items: filteredLanguages.length
|
||||
? filteredLanguages
|
||||
.map((language) => {
|
||||
? filteredLanguages.map((language) => {
|
||||
return createTextNode({
|
||||
id: language.name,
|
||||
label: language.name,
|
||||
value: language.text,
|
||||
percent: language.percent,
|
||||
// @ts-ignore
|
||||
progressBarColor: titleColor,
|
||||
// @ts-ignore
|
||||
progressBarBackgroundColor: textColor,
|
||||
hideProgress: hide_progress,
|
||||
});
|
||||
})
|
||||
: [
|
||||
noCodingActivityNode({
|
||||
color: textColor,
|
||||
text: i18n.t("wakatimecard.nocodingactivity"),
|
||||
}),
|
||||
],
|
||||
noCodingActivityNode({
|
||||
// @ts-ignore
|
||||
color: textColor,
|
||||
text: i18n.t("wakatimecard.nocodingactivity"),
|
||||
}),
|
||||
],
|
||||
gap: lheight,
|
||||
direction: "column",
|
||||
}).join("");
|
||||
|
||||
+45
-1
@@ -2,6 +2,16 @@ const { getAnimations } = require("../getStyles");
|
||||
const { flexLayout, encodeHTML } = require("../common/utils");
|
||||
|
||||
class Card {
|
||||
/**
|
||||
* @param {object} args
|
||||
* @param {number?=} args.width
|
||||
* @param {number?=} args.height
|
||||
* @param {number?=} args.border_radius
|
||||
* @param {string?=} args.customTitle
|
||||
* @param {string?=} args.defaultTitle
|
||||
* @param {string?=} args.titlePrefixIcon
|
||||
* @param {ReturnType<import('../common/utils').getCardColors>?=} args.colors
|
||||
*/
|
||||
constructor({
|
||||
width = 100,
|
||||
height = 100,
|
||||
@@ -32,20 +42,39 @@ 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
|
||||
*/
|
||||
setCSS(value) {
|
||||
this.css = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
*/
|
||||
setHideBorder(value) {
|
||||
this.hideBorder = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
*/
|
||||
setHideTitle(value) {
|
||||
this.hideTitle = value;
|
||||
if (value) {
|
||||
@@ -53,6 +82,9 @@ class Card {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
setTitle(text) {
|
||||
this.title = text;
|
||||
}
|
||||
@@ -101,8 +133,9 @@ class Card {
|
||||
? `
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="gradient"
|
||||
id="gradient"
|
||||
gradientTransform="rotate(${this.colors.bgColor[0]})"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
${gradients.map((grad, index) => {
|
||||
let offset = (index * 100) / (gradients.length - 1);
|
||||
@@ -114,6 +147,9 @@ class Card {
|
||||
: "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} body
|
||||
*/
|
||||
render(body) {
|
||||
return `
|
||||
<svg
|
||||
@@ -122,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"
|
||||
>
|
||||
<title id="titleId">${this.a11yTitle}</title>
|
||||
<desc id="descId">${this.a11yDesc}</desc>
|
||||
<style>
|
||||
.header {
|
||||
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||
fill: ${this.colors.titleColor};
|
||||
animation: fadeInAnimation 0.8s ease-in-out forwards;
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.header { font-size: 15.5px; }
|
||||
}
|
||||
${this.css}
|
||||
|
||||
${process.env.NODE_ENV === "test" ? "" : getAnimations()}
|
||||
|
||||
+273
-201
@@ -1,430 +1,502 @@
|
||||
{
|
||||
"1C Enterprise": "#814CCC",
|
||||
"4D": null,
|
||||
"2-Dimensional Array": "#38761D",
|
||||
"4D": "#004289",
|
||||
"ABAP": "#E8274B",
|
||||
"ActionScript": "#882B0F",
|
||||
"Ada": "#02f88c",
|
||||
"Agda": "#315665",
|
||||
"ABAP CDS": "#555e25",
|
||||
"AGS Script": "#B9D9FF",
|
||||
"AIDL": "#34EB6B",
|
||||
"AL": "#3AA2B5",
|
||||
"Alloy": "#64C800",
|
||||
"Alpine Abuild": null,
|
||||
"AMPL": "#E6EFBB",
|
||||
"AngelScript": "#C7D7DC",
|
||||
"ANTLR": "#9DC3FF",
|
||||
"Apex": "#1797c0",
|
||||
"API Blueprint": "#2ACCA8",
|
||||
"APL": "#5A8164",
|
||||
"ASP.NET": "#9400ff",
|
||||
"ATS": "#1ac620",
|
||||
"ActionScript": "#882B0F",
|
||||
"Ada": "#02f88c",
|
||||
"Adobe Font Metrics": "#fa0f00",
|
||||
"Agda": "#315665",
|
||||
"Alloy": "#64C800",
|
||||
"Alpine Abuild": "#0D597F",
|
||||
"Altium Designer": "#A89663",
|
||||
"AngelScript": "#C7D7DC",
|
||||
"Ant Build System": "#A9157E",
|
||||
"ApacheConf": "#d12127",
|
||||
"Apex": "#1797c0",
|
||||
"Apollo Guidance Computer": "#0B3D91",
|
||||
"AppleScript": "#101F1F",
|
||||
"Arc": "#aa2afe",
|
||||
"ASL": null,
|
||||
"ASP.NET": "#9400ff",
|
||||
"AsciiDoc": "#73a0c5",
|
||||
"AspectJ": "#a957b0",
|
||||
"Assembly": "#6E4C13",
|
||||
"Astro": "#ff5a03",
|
||||
"Asymptote": "#ff0000",
|
||||
"ATS": "#1ac620",
|
||||
"Augeas": null,
|
||||
"Augeas": "#9CC134",
|
||||
"AutoHotkey": "#6594b9",
|
||||
"AutoIt": "#1C3552",
|
||||
"Awk": null,
|
||||
"Avro IDL": "#0040FF",
|
||||
"Awk": "#c30e9b",
|
||||
"BASIC": "#ff0000",
|
||||
"Ballerina": "#FF5000",
|
||||
"Batchfile": "#C1F12E",
|
||||
"Befunge": null,
|
||||
"Beef": "#a52f4e",
|
||||
"BibTeX": "#778899",
|
||||
"Bicep": "#519aba",
|
||||
"Bison": "#6A463F",
|
||||
"BitBake": null,
|
||||
"BitBake": "#00bce4",
|
||||
"Blade": "#f7523f",
|
||||
"BlitzBasic": null,
|
||||
"BlitzBasic": "#00FFAE",
|
||||
"BlitzMax": "#cd6400",
|
||||
"Bluespec": null,
|
||||
"Bluespec": "#12223c",
|
||||
"Boo": "#d4bec1",
|
||||
"Boogie": "#c80fa0",
|
||||
"Brainfuck": "#2F2530",
|
||||
"Brightscript": null,
|
||||
"Brightscript": "#662D91",
|
||||
"Browserslist": "#ffd539",
|
||||
"C": "#555555",
|
||||
"C#": "#178600",
|
||||
"C++": "#f34b7d",
|
||||
"C2hs Haskell": null,
|
||||
"Cap'n Proto": null,
|
||||
"CartoCSS": null,
|
||||
"CLIPS": "#00A300",
|
||||
"CMake": "#DA3434",
|
||||
"COLLADA": "#F1A42B",
|
||||
"CSON": "#244776",
|
||||
"CSS": "#563d7c",
|
||||
"CSV": "#237346",
|
||||
"CUE": "#5886E1",
|
||||
"CWeb": "#00007a",
|
||||
"Cabal Config": "#483465",
|
||||
"Cairo": "#ff4a48",
|
||||
"Cap'n Proto": "#c42727",
|
||||
"Ceylon": "#dfa535",
|
||||
"Chapel": "#8dc63f",
|
||||
"Charity": null,
|
||||
"ChucK": null,
|
||||
"ChucK": "#3f8000",
|
||||
"Cirru": "#ccccff",
|
||||
"Clarion": "#db901e",
|
||||
"Clarity": "#5546ff",
|
||||
"Classic ASP": "#6a40fd",
|
||||
"Clean": "#3F85AF",
|
||||
"Click": "#E4E6F3",
|
||||
"CLIPS": null,
|
||||
"Clojure": "#db5855",
|
||||
"CMake": null,
|
||||
"COBOL": null,
|
||||
"CodeQL": null,
|
||||
"Closure Templates": "#0d948f",
|
||||
"Cloud Firestore Security Rules": "#FFA000",
|
||||
"CodeQL": "#140f46",
|
||||
"CoffeeScript": "#244776",
|
||||
"ColdFusion": "#ed2cd6",
|
||||
"ColdFusion CFC": "#ed2cd6",
|
||||
"Common Lisp": "#3fb68b",
|
||||
"Common Workflow Language": "#B5314C",
|
||||
"Component Pascal": "#B0CE4E",
|
||||
"Cool": null,
|
||||
"Coq": null,
|
||||
"Coq": "#d0b68c",
|
||||
"Crystal": "#000100",
|
||||
"CSON": "#244776",
|
||||
"Csound": null,
|
||||
"Csound Document": null,
|
||||
"Csound Score": null,
|
||||
"CSS": "#563d7c",
|
||||
"Csound": "#1a1a1a",
|
||||
"Csound Document": "#1a1a1a",
|
||||
"Csound Score": "#1a1a1a",
|
||||
"Cuda": "#3A4E3A",
|
||||
"CWeb": null,
|
||||
"Cycript": null,
|
||||
"Cython": null,
|
||||
"Curry": "#531242",
|
||||
"Cython": "#fedf5b",
|
||||
"D": "#ba595e",
|
||||
"DM": "#447265",
|
||||
"Dafny": "#FFEC25",
|
||||
"Darcs Patch": "#8eff23",
|
||||
"Dart": "#00B4AB",
|
||||
"DataWeave": "#003a52",
|
||||
"Debian Package Control File": "#D70751",
|
||||
"DenizenScript": "#FBEE96",
|
||||
"Dhall": "#dfafff",
|
||||
"DIGITAL Command Language": null,
|
||||
"DM": "#447265",
|
||||
"DirectX 3D File": "#aace60",
|
||||
"Dockerfile": "#384d54",
|
||||
"Dogescript": "#cca760",
|
||||
"DTrace": null,
|
||||
"Dylan": "#6c616e",
|
||||
"E": "#ccce35",
|
||||
"eC": "#913960",
|
||||
"ECL": "#8a1267",
|
||||
"ECLiPSe": null,
|
||||
"Eiffel": "#4d6977",
|
||||
"ECLiPSe": "#001d9d",
|
||||
"EJS": "#a91e50",
|
||||
"EQ": "#a78649",
|
||||
"Earthly": "#2af0ff",
|
||||
"Easybuild": "#069406",
|
||||
"Ecere Projects": "#913960",
|
||||
"EditorConfig": "#fff1f2",
|
||||
"Eiffel": "#4d6977",
|
||||
"Elixir": "#6e4a7e",
|
||||
"Elm": "#60B5CC",
|
||||
"Emacs Lisp": "#c065db",
|
||||
"EmberScript": "#FFF4F3",
|
||||
"EQ": "#a78649",
|
||||
"Erlang": "#B83998",
|
||||
"Euphoria": "#FF790B",
|
||||
"F#": "#b845fc",
|
||||
"F*": "#572e30",
|
||||
"FIGlet Font": "#FFDDBB",
|
||||
"FLUX": "#88ccff",
|
||||
"Factor": "#636746",
|
||||
"Fancy": "#7b9db4",
|
||||
"Fantom": "#14253c",
|
||||
"Faust": "#c37240",
|
||||
"Filebench WML": null,
|
||||
"Filterscript": null,
|
||||
"fish": null,
|
||||
"FLUX": "#88ccff",
|
||||
"Fennel": "#fff3d7",
|
||||
"Filebench WML": "#F6B900",
|
||||
"Fluent": "#ffcc33",
|
||||
"Forth": "#341708",
|
||||
"Fortran": "#4d41b1",
|
||||
"Fortran Free Form": null,
|
||||
"Fortran Free Form": "#4d41b1",
|
||||
"FreeBasic": "#867db1",
|
||||
"FreeMarker": "#0050b2",
|
||||
"Frege": "#00cafe",
|
||||
"Futhark": "#5f021f",
|
||||
"G-code": "#D08CF2",
|
||||
"Game Maker Language": "#71b417",
|
||||
"GAML": "#FFC766",
|
||||
"GAMS": null,
|
||||
"GAP": null,
|
||||
"GCC Machine Description": null,
|
||||
"GDB": null,
|
||||
"GAMS": "#f49a22",
|
||||
"GAP": "#0000cc",
|
||||
"GCC Machine Description": "#FFCFAB",
|
||||
"GDScript": "#355570",
|
||||
"GEDCOM": "#003058",
|
||||
"GLSL": "#5686a5",
|
||||
"GSC": "#FF6800",
|
||||
"Game Maker Language": "#71b417",
|
||||
"Gemfile.lock": "#701516",
|
||||
"Genie": "#fb855d",
|
||||
"Genshi": null,
|
||||
"Gentoo Ebuild": null,
|
||||
"Gentoo Eclass": null,
|
||||
"Genshi": "#951531",
|
||||
"Gentoo Ebuild": "#9400ff",
|
||||
"Gentoo Eclass": "#9400ff",
|
||||
"Gerber Image": "#d20b00",
|
||||
"Gherkin": "#5B2063",
|
||||
"GLSL": null,
|
||||
"Git Attributes": "#F44D27",
|
||||
"Git Config": "#F44D27",
|
||||
"Gleam": "#ffaff3",
|
||||
"Glyph": "#c1ac7f",
|
||||
"Gnuplot": "#f0a9f0",
|
||||
"Go": "#00ADD8",
|
||||
"Go Checksums": "#00ADD8",
|
||||
"Go Module": "#00ADD8",
|
||||
"Golo": "#88562A",
|
||||
"Gosu": "#82937f",
|
||||
"Grace": null,
|
||||
"Grace": "#615f8b",
|
||||
"Gradle": "#02303a",
|
||||
"Grammatical Framework": "#ff0000",
|
||||
"GraphQL": "#e10098",
|
||||
"Groovy": "#e69f56",
|
||||
"Groovy Server Pages": null,
|
||||
"Graphviz (DOT)": "#2596be",
|
||||
"Groovy": "#4298b8",
|
||||
"Groovy Server Pages": "#4298b8",
|
||||
"HAProxy": "#106da9",
|
||||
"HLSL": "#aace60",
|
||||
"HTML": "#e34c26",
|
||||
"HTML+ECR": "#2e1052",
|
||||
"HTML+EEX": "#6e4a7e",
|
||||
"HTML+ERB": "#701516",
|
||||
"HTML+PHP": "#4f5d95",
|
||||
"HTML+Razor": "#512be4",
|
||||
"HTTP": "#005C9C",
|
||||
"HXML": "#f68712",
|
||||
"Hack": "#878787",
|
||||
"Haml": "#ece2a9",
|
||||
"Handlebars": "#f7931e",
|
||||
"Harbour": "#0e60e3",
|
||||
"Haskell": "#5e5086",
|
||||
"Haxe": "#df7900",
|
||||
"HCL": null,
|
||||
"HiveQL": "#dce200",
|
||||
"HLSL": null,
|
||||
"HolyC": "#ffefaf",
|
||||
"HTML": "#e34c26",
|
||||
"Hy": "#7790B2",
|
||||
"HyPhy": null,
|
||||
"IDL": "#a3522f",
|
||||
"Idris": "#b30000",
|
||||
"IGOR Pro": "#0000cc",
|
||||
"Inform 7": null,
|
||||
"Inno Setup": null,
|
||||
"INI": "#d1dbe0",
|
||||
"Idris": "#b30000",
|
||||
"Ignore List": "#000000",
|
||||
"ImageJ Macro": "#99AAFF",
|
||||
"Inno Setup": "#264b99",
|
||||
"Io": "#a9188d",
|
||||
"Ioke": "#078193",
|
||||
"Isabelle": "#FEFE00",
|
||||
"Isabelle ROOT": null,
|
||||
"Isabelle ROOT": "#FEFE00",
|
||||
"J": "#9EEDFF",
|
||||
"Jasmin": null,
|
||||
"Java": "#b07219",
|
||||
"Java Server Pages": null,
|
||||
"JavaScript": "#f1e05a",
|
||||
"JavaScript+ERB": null,
|
||||
"JAR Manifest": "#b07219",
|
||||
"JFlex": "#DBCA00",
|
||||
"Jison": null,
|
||||
"Jison Lex": null,
|
||||
"Jolie": "#843179",
|
||||
"JSON": "#292929",
|
||||
"JSON with Comments": "#292929",
|
||||
"JSON5": "#267CB9",
|
||||
"JSONLD": "#0c479c",
|
||||
"JSONiq": "#40d47e",
|
||||
"Janet": "#0886a5",
|
||||
"Jasmin": "#d03600",
|
||||
"Java": "#b07219",
|
||||
"Java Properties": "#2A6277",
|
||||
"Java Server Pages": "#2A6277",
|
||||
"JavaScript": "#f1e05a",
|
||||
"JavaScript+ERB": "#f1e05a",
|
||||
"Jest Snapshot": "#15c213",
|
||||
"Jinja": "#a52a22",
|
||||
"Jison": "#56b3cb",
|
||||
"Jison Lex": "#56b3cb",
|
||||
"Jolie": "#843179",
|
||||
"Jsonnet": "#0064bd",
|
||||
"JSX": null,
|
||||
"Julia": "#a270ba",
|
||||
"Jupyter Notebook": "#DA5B0B",
|
||||
"Kaitai Struct": "#773b37",
|
||||
"Kotlin": "#F18E33",
|
||||
"KRL": "#28430A",
|
||||
"LabVIEW": null,
|
||||
"Kaitai Struct": "#773b37",
|
||||
"KakouneScript": "#6f8042",
|
||||
"KiCad Layout": "#2f4aab",
|
||||
"KiCad Legacy Layout": "#2f4aab",
|
||||
"KiCad Schematic": "#2f4aab",
|
||||
"Kotlin": "#A97BFF",
|
||||
"LFE": "#4C3023",
|
||||
"LLVM": "#185619",
|
||||
"LOLCODE": "#cc9900",
|
||||
"LSL": "#3d9970",
|
||||
"LabVIEW": "#fede06",
|
||||
"Lark": "#2980B9",
|
||||
"Lasso": "#999999",
|
||||
"Latte": "#f2a542",
|
||||
"Lean": null,
|
||||
"Less": "#1d365d",
|
||||
"Lex": "#DBCA00",
|
||||
"LFE": "#4C3023",
|
||||
"LilyPond": null,
|
||||
"Limbo": null,
|
||||
"Literate Agda": null,
|
||||
"Literate CoffeeScript": null,
|
||||
"Literate Haskell": null,
|
||||
"LilyPond": "#9ccc7c",
|
||||
"Liquid": "#67b8de",
|
||||
"Literate Agda": "#315665",
|
||||
"Literate CoffeeScript": "#244776",
|
||||
"Literate Haskell": "#5e5086",
|
||||
"LiveScript": "#499886",
|
||||
"LLVM": "#185619",
|
||||
"Logos": null,
|
||||
"Logtalk": null,
|
||||
"LOLCODE": "#cc9900",
|
||||
"Logtalk": "#295b9a",
|
||||
"LookML": "#652B81",
|
||||
"LoomScript": null,
|
||||
"LSL": "#3d9970",
|
||||
"Lua": "#000080",
|
||||
"M": null,
|
||||
"M4": null,
|
||||
"M4Sugar": null,
|
||||
"Macaulay2": "#d8ffff",
|
||||
"Makefile": "#427819",
|
||||
"Mako": null,
|
||||
"Markdown": "#083fa1",
|
||||
"Marko": "#42bff2",
|
||||
"Mask": "#f97732",
|
||||
"Mathematica": null,
|
||||
"MATLAB": "#e16737",
|
||||
"Max": "#c4a79c",
|
||||
"MAXScript": "#00a6a6",
|
||||
"mcfunction": "#E22837",
|
||||
"Mercury": "#ff2b2b",
|
||||
"Meson": "#007800",
|
||||
"Metal": "#8f14e9",
|
||||
"MiniD": null,
|
||||
"Mirah": "#c7a938",
|
||||
"mIRC Script": "#3d57c3",
|
||||
"MLIR": "#5EC8DB",
|
||||
"Modelica": null,
|
||||
"Modula-2": null,
|
||||
"Modula-3": "#223388",
|
||||
"Module Management System": null,
|
||||
"Monkey": null,
|
||||
"Moocode": null,
|
||||
"MoonScript": null,
|
||||
"Motorola 68K Assembly": null,
|
||||
"MQL4": "#62A8D6",
|
||||
"MQL5": "#4A76B8",
|
||||
"MTML": "#b7e1f4",
|
||||
"MUF": null,
|
||||
"mupad": null,
|
||||
"Myghty": null,
|
||||
"NASL": null,
|
||||
"Macaulay2": "#d8ffff",
|
||||
"Makefile": "#427819",
|
||||
"Mako": "#7e858d",
|
||||
"Markdown": "#083fa1",
|
||||
"Marko": "#42bff2",
|
||||
"Mask": "#f97732",
|
||||
"Mathematica": "#dd1100",
|
||||
"Max": "#c4a79c",
|
||||
"Mercury": "#ff2b2b",
|
||||
"Meson": "#007800",
|
||||
"Metal": "#8f14e9",
|
||||
"MiniYAML": "#ff1111",
|
||||
"Mint": "#02b046",
|
||||
"Mirah": "#c7a938",
|
||||
"Modelica": "#de1d31",
|
||||
"Modula-2": "#10253f",
|
||||
"Modula-3": "#223388",
|
||||
"MoonScript": "#ff4585",
|
||||
"Motoko": "#fbb03b",
|
||||
"Motorola 68K Assembly": "#005daa",
|
||||
"Mustache": "#724b3b",
|
||||
"NCL": "#28431f",
|
||||
"NPM Config": "#cb3837",
|
||||
"NWScript": "#111522",
|
||||
"Nearley": "#990000",
|
||||
"Nemerle": "#3d3c6e",
|
||||
"nesC": "#94B0C7",
|
||||
"NetLinx": "#0aa0ff",
|
||||
"NetLinx+ERB": "#747faa",
|
||||
"NetLogo": "#ff6375",
|
||||
"NewLisp": "#87AED7",
|
||||
"Nextflow": "#3ac486",
|
||||
"Nginx": "#009639",
|
||||
"Nim": "#ffc200",
|
||||
"Nit": "#009917",
|
||||
"Nix": "#7e7eff",
|
||||
"NSIS": null,
|
||||
"Nu": "#c9df40",
|
||||
"NumPy": "#9C8AF9",
|
||||
"Nunjucks": "#3d8137",
|
||||
"OCaml": "#3be133",
|
||||
"ObjectScript": "#424893",
|
||||
"Objective-C": "#438eff",
|
||||
"Objective-C++": "#6866fb",
|
||||
"Objective-J": "#ff0c5a",
|
||||
"ObjectScript": "#424893",
|
||||
"OCaml": "#3be133",
|
||||
"Odin": "#60AFFE",
|
||||
"Omgrofl": "#cabbff",
|
||||
"ooc": "#b0b77e",
|
||||
"Opa": null,
|
||||
"Opal": "#f7ede0",
|
||||
"Open Policy Agent": null,
|
||||
"OpenCL": null,
|
||||
"OpenEdge ABL": null,
|
||||
"Open Policy Agent": "#7d9199",
|
||||
"OpenCL": "#ed2e2d",
|
||||
"OpenEdge ABL": "#5ce600",
|
||||
"OpenQASM": "#AA70FF",
|
||||
"OpenRC runscript": null,
|
||||
"OpenSCAD": null,
|
||||
"Ox": null,
|
||||
"OpenSCAD": "#e5cd45",
|
||||
"Org": "#77aa99",
|
||||
"Oxygene": "#cdd0e3",
|
||||
"Oz": "#fab738",
|
||||
"P4": "#7055b5",
|
||||
"PEG.js": "#234d6b",
|
||||
"PHP": "#4F5D95",
|
||||
"PLSQL": "#dad8d8",
|
||||
"PLpgSQL": "#336790",
|
||||
"POV-Ray SDL": "#6bac65",
|
||||
"Pan": "#cc0000",
|
||||
"Papyrus": "#6600cc",
|
||||
"Parrot": "#f3ca0a",
|
||||
"Parrot Assembly": null,
|
||||
"Parrot Internal Representation": null,
|
||||
"Pascal": "#E3F171",
|
||||
"Pawn": "#dbb284",
|
||||
"Pep8": "#C76F5B",
|
||||
"Perl": "#0298c3",
|
||||
"PHP": "#4F5D95",
|
||||
"PicoLisp": null,
|
||||
"PicoLisp": "#6067af",
|
||||
"PigLatin": "#fcd7de",
|
||||
"Pike": "#005390",
|
||||
"PLpgSQL": null,
|
||||
"PLSQL": "#dad8d8",
|
||||
"PogoScript": "#d80074",
|
||||
"Pony": null,
|
||||
"PostCSS": "#dc3a0c",
|
||||
"PostScript": "#da291c",
|
||||
"POV-Ray SDL": null,
|
||||
"PowerBuilder": "#8f0f8d",
|
||||
"PowerShell": "#012456",
|
||||
"Prisma": "#0c344b",
|
||||
"Processing": "#0096D8",
|
||||
"Procfile": "#3B2F63",
|
||||
"Prolog": "#74283c",
|
||||
"Promela": "#de0000",
|
||||
"Propeller Spin": "#7fa2a7",
|
||||
"Pug": "#a86454",
|
||||
"Puppet": "#302B6D",
|
||||
"PureBasic": "#5a6986",
|
||||
"PureScript": "#1D222D",
|
||||
"Python": "#3572A5",
|
||||
"Python console": null,
|
||||
"q": "#0040cd",
|
||||
"Python console": "#3572A5",
|
||||
"Python traceback": "#3572A5",
|
||||
"Q#": "#fed659",
|
||||
"QMake": null,
|
||||
"QML": "#44a51c",
|
||||
"Qt Script": "#00b841",
|
||||
"Quake": "#882233",
|
||||
"R": "#198CE7",
|
||||
"RAML": "#77d9fb",
|
||||
"RDoc": "#701516",
|
||||
"REXX": "#d90e09",
|
||||
"RMarkdown": "#198ce7",
|
||||
"RPGLE": "#2BDE21",
|
||||
"RUNOFF": "#665a4e",
|
||||
"Racket": "#3c5caa",
|
||||
"Ragel": "#9d5200",
|
||||
"Raku": "#0000fb",
|
||||
"RAML": "#77d9fb",
|
||||
"Rascal": "#fffaa0",
|
||||
"REALbasic": null,
|
||||
"ReScript": "#ed5051",
|
||||
"Reason": "#ff5847",
|
||||
"Rebol": "#358a5b",
|
||||
"Record Jar": "#0673ba",
|
||||
"Red": "#f50000",
|
||||
"Redcode": null,
|
||||
"Regular Expression": "#009a00",
|
||||
"Ren'Py": "#ff7f7f",
|
||||
"RenderScript": null,
|
||||
"REXX": null,
|
||||
"Ring": "#2D54CB",
|
||||
"Riot": "#A71E49",
|
||||
"RobotFramework": null,
|
||||
"RobotFramework": "#00c0b5",
|
||||
"Roff": "#ecdebe",
|
||||
"Roff Manpage": "#ecdebe",
|
||||
"Rouge": "#cc0088",
|
||||
"RPC": null,
|
||||
"Ruby": "#701516",
|
||||
"RUNOFF": "#665a4e",
|
||||
"Rust": "#dea584",
|
||||
"Sage": null,
|
||||
"SaltStack": "#646464",
|
||||
"SAS": "#B34936",
|
||||
"SCSS": "#c6538c",
|
||||
"SPARQL": "#0C4597",
|
||||
"SQF": "#3F3F3F",
|
||||
"SQL": "#e38c00",
|
||||
"SQLPL": "#e38c00",
|
||||
"SRecode Template": "#348a34",
|
||||
"SVG": "#ff9900",
|
||||
"SaltStack": "#646464",
|
||||
"Sass": "#a53b70",
|
||||
"Scala": "#c22d40",
|
||||
"Scaml": "#bd181a",
|
||||
"Scheme": "#1e4aec",
|
||||
"Scilab": null,
|
||||
"SCSS": "#c6538c",
|
||||
"sed": "#64b970",
|
||||
"Scilab": "#ca0f21",
|
||||
"Self": "#0579aa",
|
||||
"ShaderLab": null,
|
||||
"ShaderLab": "#222c37",
|
||||
"Shell": "#89e051",
|
||||
"ShellSession": null,
|
||||
"ShellCheck Config": "#cecfcb",
|
||||
"Shen": "#120F14",
|
||||
"Sieve": null,
|
||||
"Singularity": "#64E6AD",
|
||||
"Slash": "#007eff",
|
||||
"Slice": "#003fa2",
|
||||
"Slim": "#2b2b2b",
|
||||
"Smali": null,
|
||||
"Smalltalk": "#596706",
|
||||
"Smarty": null,
|
||||
"SmPL": "#c94949",
|
||||
"SMT": null,
|
||||
"Smalltalk": "#596706",
|
||||
"Smarty": "#f0c040",
|
||||
"Solidity": "#AA6746",
|
||||
"SourcePawn": "#f69e1d",
|
||||
"SQF": "#3F3F3F",
|
||||
"SQLPL": null,
|
||||
"Squirrel": "#800000",
|
||||
"SRecode Template": "#348a34",
|
||||
"Stan": "#b2011d",
|
||||
"Standard ML": "#dc566d",
|
||||
"Starlark": "#76d275",
|
||||
"Stata": null,
|
||||
"Stata": "#1a5f91",
|
||||
"StringTemplate": "#3fb34f",
|
||||
"Stylus": "#ff6347",
|
||||
"SubRip Text": "#9e0101",
|
||||
"SugarSS": "#2fcc9f",
|
||||
"SuperCollider": "#46390b",
|
||||
"Svelte": "#ff3e00",
|
||||
"SVG": "#ff9900",
|
||||
"Swift": "#ffac45",
|
||||
"SWIG": null,
|
||||
"Swift": "#F05138",
|
||||
"SystemVerilog": "#DAE1C2",
|
||||
"Tcl": "#e4cc98",
|
||||
"Tcsh": null,
|
||||
"Terra": "#00004c",
|
||||
"TeX": "#3D6117",
|
||||
"Thrift": null,
|
||||
"TI Program": "#A0AA87",
|
||||
"TLA": null,
|
||||
"TSQL": null,
|
||||
"TSX": null,
|
||||
"TLA": "#4b0079",
|
||||
"TOML": "#9c4221",
|
||||
"TSQL": "#e38c00",
|
||||
"TSV": "#237346",
|
||||
"TSX": "#2b7489",
|
||||
"TXL": "#0178b8",
|
||||
"Tcl": "#e4cc98",
|
||||
"TeX": "#3D6117",
|
||||
"Terra": "#00004c",
|
||||
"TextMate Properties": "#df66e4",
|
||||
"Textile": "#ffe7ac",
|
||||
"Thrift": "#D12127",
|
||||
"Turing": "#cf142b",
|
||||
"Twig": "#c1d026",
|
||||
"TXL": null,
|
||||
"TypeScript": "#2b7489",
|
||||
"Unified Parallel C": "#4e3617",
|
||||
"Unix Assembly": null,
|
||||
"Unity3D Asset": "#222c37",
|
||||
"Uno": "#9933cc",
|
||||
"UnrealScript": "#a54c4d",
|
||||
"UrWeb": null,
|
||||
"UrWeb": "#ccccee",
|
||||
"V": "#4f87c4",
|
||||
"Vala": "#fbe5cd",
|
||||
"VBA": "#867db1",
|
||||
"VBScript": "#15dcdc",
|
||||
"VCL": "#148AA8",
|
||||
"Verilog": "#b2b7f8",
|
||||
"VHDL": "#adb2cb",
|
||||
"Vim script": "#199f4b",
|
||||
"Vala": "#fbe5cd",
|
||||
"Valve Data Format": "#f26025",
|
||||
"Verilog": "#b2b7f8",
|
||||
"Vim Help File": "#199f4b",
|
||||
"Vim Script": "#199f4b",
|
||||
"Vim Snippet": "#199f4b",
|
||||
"Visual Basic .NET": "#945db7",
|
||||
"Volt": "#1F1F1F",
|
||||
"Vue": "#2c3e50",
|
||||
"wdl": "#42f1f4",
|
||||
"Vue": "#41b883",
|
||||
"Vyper": "#2980b9",
|
||||
"Web Ontology Language": "#5b70bd",
|
||||
"WebAssembly": "#04133b",
|
||||
"WebIDL": null,
|
||||
"wisp": "#7582D1",
|
||||
"Wikitext": "#fc5757",
|
||||
"Windows Registry Entries": "#52d5ff",
|
||||
"Witcher Script": "#ff0000",
|
||||
"Wollok": "#a23738",
|
||||
"World of Warcraft Addon Data": "#f7e43f",
|
||||
"X10": "#4B6BEF",
|
||||
"xBase": "#403a40",
|
||||
"XC": "#99DA07",
|
||||
"Xojo": null,
|
||||
"XProc": null,
|
||||
"XML": "#0060ac",
|
||||
"XML Property List": "#0060ac",
|
||||
"XQuery": "#5232e7",
|
||||
"XS": null,
|
||||
"XSLT": "#EB8CEB",
|
||||
"Xtend": null,
|
||||
"Yacc": "#4B6C4B",
|
||||
"Xojo": "#81bd41",
|
||||
"Xonsh": "#285EEF",
|
||||
"Xtend": "#24255d",
|
||||
"YAML": "#cb171e",
|
||||
"YARA": "#220000",
|
||||
"YASnippet": "#32AB90",
|
||||
"Yacc": "#4B6C4B",
|
||||
"ZAP": "#0d665e",
|
||||
"Zeek": null,
|
||||
"ZIL": "#dc75e5",
|
||||
"ZenScript": "#00BCD1",
|
||||
"Zephir": "#118f9e",
|
||||
"Zig": "#ec915c",
|
||||
"ZIL": "#dc75e5",
|
||||
"Zimpl": null
|
||||
"Zimpl": "#d67711",
|
||||
"eC": "#913960",
|
||||
"fish": "#4aae47",
|
||||
"hoon": "#00b171",
|
||||
"jq": "#c7254e",
|
||||
"kvlang": "#1da6e0",
|
||||
"mIRC Script": "#3d57c3",
|
||||
"mcfunction": "#E22837",
|
||||
"mupad": "#244963",
|
||||
"nanorc": "#2d004d",
|
||||
"nesC": "#94B0C7",
|
||||
"ooc": "#b0b77e",
|
||||
"q": "#0040cd",
|
||||
"reStructuredText": "#141414",
|
||||
"sed": "#64b970",
|
||||
"wdl": "#42f1f4",
|
||||
"wisp": "#7582D1",
|
||||
"xBase": "#403a40"
|
||||
}
|
||||
+161
-18
@@ -1,7 +1,14 @@
|
||||
// @ts-check
|
||||
const axios = require("axios");
|
||||
const wrap = require("word-wrap");
|
||||
const themes = require("../../themes");
|
||||
const toEmoji = require("emoji-name-map");
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {string} secondaryMessage
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderError = (message, secondaryMessage = "") => {
|
||||
return `
|
||||
<svg width="495" height="120" viewBox="0 0 495 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -11,7 +18,7 @@ const renderError = (message, secondaryMessage = "") => {
|
||||
.gray { fill: #858585 }
|
||||
</style>
|
||||
<rect x="0.5" y="0.5" width="494" height="99%" rx="4.5" fill="#FFFEFE" stroke="#E4E2E2"/>
|
||||
<text x="25" y="45" class="text">Something went wrong! file an issue at https://git.io/JJmN9</text>
|
||||
<text x="25" y="45" class="text">Something went wrong! file an issue at https://tiny.one/readme-stats</text>
|
||||
<text data-testid="message" x="25" y="55" class="text small">
|
||||
<tspan x="25" dy="18">${encodeHTML(message)}</tspan>
|
||||
<tspan x="25" dy="18" class="gray">${secondaryMessage}</tspan>
|
||||
@@ -20,7 +27,11 @@ const renderError = (message, secondaryMessage = "") => {
|
||||
`;
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/a/48073476/10629172
|
||||
/**
|
||||
* @see https://stackoverflow.com/a/48073476/10629172
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function encodeHTML(str) {
|
||||
return str
|
||||
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
|
||||
@@ -29,18 +40,29 @@ function encodeHTML(str) {
|
||||
.replace(/\u0008/gim, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} num
|
||||
*/
|
||||
function kFormatter(num) {
|
||||
return Math.abs(num) > 999
|
||||
? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k"
|
||||
? Math.sign(num) * parseFloat((Math.abs(num) / 1000).toFixed(1)) + "k"
|
||||
: Math.sign(num) * Math.abs(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} hexColor
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isValidHexColor(hexColor) {
|
||||
return new RegExp(
|
||||
/^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/,
|
||||
).test(hexColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {boolean | string}
|
||||
*/
|
||||
function parseBoolean(value) {
|
||||
if (value === "true") {
|
||||
return true;
|
||||
@@ -51,19 +73,37 @@ function parseBoolean(value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
*/
|
||||
function parseArray(str) {
|
||||
if (!str) return [];
|
||||
return str.split(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} number
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
*/
|
||||
function clampValue(number, min, max) {
|
||||
// @ts-ignore
|
||||
if (Number.isNaN(parseInt(number))) return min;
|
||||
return Math.max(min, Math.min(number, max));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} colors
|
||||
*/
|
||||
function isValidGradient(colors) {
|
||||
return isValidHexColor(colors[1]) && isValidHexColor(colors[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} color
|
||||
* @param {string} fallbackColor
|
||||
* @returns {string | string[]}
|
||||
*/
|
||||
function fallbackColor(color, fallbackColor) {
|
||||
let colors = color.split(",");
|
||||
let gradient = null;
|
||||
@@ -78,7 +118,12 @@ function fallbackColor(color, fallbackColor) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('axios').AxiosRequestConfig['data']} data
|
||||
* @param {import('axios').AxiosRequestConfig['headers']} headers
|
||||
*/
|
||||
function request(data, headers) {
|
||||
// @ts-ignore
|
||||
return axios({
|
||||
url: "https://api.github.com/graphql",
|
||||
method: "post",
|
||||
@@ -88,34 +133,53 @@ function request(data, headers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string[]} props.items
|
||||
* @param {number} props.gap
|
||||
* @param {number[]?=} props.sizes
|
||||
* @param {"column" | "row"?=} props.direction
|
||||
*
|
||||
* @param {String[]} items
|
||||
* @param {Number} gap
|
||||
* @param {string} direction
|
||||
* @returns {string[]}
|
||||
*
|
||||
* @description
|
||||
* Auto layout utility, allows us to layout things
|
||||
* vertically or horizontally with proper gaping
|
||||
*/
|
||||
function flexLayout({ items, gap, direction }) {
|
||||
function flexLayout({ items, gap, direction, sizes = [] }) {
|
||||
let lastSize = 0;
|
||||
// filter() for filtering out empty strings
|
||||
return items.filter(Boolean).map((item, i) => {
|
||||
let transform = `translate(${gap * i}, 0)`;
|
||||
const size = sizes[i] || 0;
|
||||
let transform = `translate(${lastSize}, 0)`;
|
||||
if (direction === "column") {
|
||||
transform = `translate(0, ${gap * i})`;
|
||||
transform = `translate(0, ${lastSize})`;
|
||||
}
|
||||
lastSize += size + gap;
|
||||
return `<g transform="${transform}">${item}</g>`;
|
||||
});
|
||||
}
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
/**
|
||||
* @typedef {object} CardColors
|
||||
* @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
|
||||
*/
|
||||
/**
|
||||
* returns theme based colors with proper overrides and defaults
|
||||
* @param {CardColors} options
|
||||
*/
|
||||
function getCardColors({
|
||||
title_color,
|
||||
text_color,
|
||||
icon_color,
|
||||
bg_color,
|
||||
theme,
|
||||
border_color,
|
||||
theme,
|
||||
fallbackTheme = "default",
|
||||
}) {
|
||||
const defaultTheme = themes[fallbackTheme];
|
||||
@@ -150,12 +214,28 @@ function getCardColors({
|
||||
return { titleColor, iconColor, textColor, bgColor, borderColor };
|
||||
}
|
||||
|
||||
function wrapTextMultiline(text, width = 60, maxLines = 3) {
|
||||
const wrapped = wrap(encodeHTML(text), { width })
|
||||
.split("\n") // Split wrapped lines to get an array of lines
|
||||
.map((line) => line.trim()); // Remove leading and trailing whitespace of each line
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} width
|
||||
* @param {number} maxLines
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function wrapTextMultiline(text, width = 59, maxLines = 3) {
|
||||
const fullWidthComma = ",";
|
||||
const encoded = encodeHTML(text);
|
||||
const isChinese = encoded.includes(fullWidthComma);
|
||||
|
||||
const lines = wrapped.slice(0, maxLines); // Only consider maxLines lines
|
||||
let wrapped = [];
|
||||
|
||||
if (isChinese) {
|
||||
wrapped = encoded.split(fullWidthComma); // Chinese full punctuation
|
||||
} else {
|
||||
wrapped = wrap(encoded, {
|
||||
width,
|
||||
}).split("\n"); // Split wrapped lines to get an array of lines
|
||||
}
|
||||
|
||||
const lines = wrapped.map((line) => line.trim()).slice(0, maxLines); // Only consider maxLines lines
|
||||
|
||||
// Add "..." to the last line if the text exceeds maxLines
|
||||
if (wrapped.length > maxLines) {
|
||||
@@ -186,17 +266,41 @@ const SECONDARY_ERROR_MESSAGES = {
|
||||
};
|
||||
|
||||
class CustomError extends Error {
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {string} type
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/48172630/10629172
|
||||
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
|
||||
* @param {number} fontSize
|
||||
* @returns
|
||||
*/
|
||||
function measureText(str, fontSize = 10) {
|
||||
// prettier-ignore
|
||||
const widths = [
|
||||
@@ -231,6 +335,41 @@ function measureText(str, fontSize = 10) {
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {string} name */
|
||||
const lowercaseTrim = (name) => name.toLowerCase().trim();
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<T>} arr
|
||||
* @param {number} perChunk
|
||||
* @returns {Array<T>}
|
||||
*/
|
||||
function chunkArray(arr, perChunk) {
|
||||
return arr.reduce((resultArray, item, index) => {
|
||||
const chunkIndex = Math.floor(index / perChunk);
|
||||
|
||||
if (!resultArray[chunkIndex]) {
|
||||
resultArray[chunkIndex] = []; // start a new chunk
|
||||
}
|
||||
|
||||
resultArray[chunkIndex].push(item);
|
||||
|
||||
return resultArray;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function parseEmojis(str) {
|
||||
if (!str) throw new Error("[parseEmoji]: str argument not provided");
|
||||
return str.replace(/:\w+:/gm, (emoji) => {
|
||||
return toEmoji.get(emoji) || "";
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
renderError,
|
||||
kFormatter,
|
||||
@@ -248,4 +387,8 @@ module.exports = {
|
||||
logger,
|
||||
CONSTANTS,
|
||||
CustomError,
|
||||
MissingParamError,
|
||||
lowercaseTrim,
|
||||
chunkArray,
|
||||
parseEmojis,
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
@@ -38,15 +43,24 @@ const fetcher = (variables, token) => {
|
||||
variables,
|
||||
},
|
||||
{
|
||||
Authorization: `bearer ${token}`,
|
||||
Authorization: `token ${token}`,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const urlExample = "/api/pin?username=USERNAME&repo=REPO_NAME";
|
||||
|
||||
/**
|
||||
* @param {string} username
|
||||
* @param {string} reponame
|
||||
* @returns {Promise<import("./types").RepositoryData>}
|
||||
*/
|
||||
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 });
|
||||
|
||||
@@ -63,7 +77,10 @@ async function fetchRepo(username, reponame) {
|
||||
if (!data.user.repository || data.user.repository.isPrivate) {
|
||||
throw new Error("User Repository Not found");
|
||||
}
|
||||
return data.user.repository;
|
||||
return {
|
||||
...data.user.repository,
|
||||
starCount: data.user.repository.stargazers.totalCount,
|
||||
};
|
||||
}
|
||||
|
||||
if (isOrg) {
|
||||
@@ -73,7 +90,10 @@ async function fetchRepo(username, reponame) {
|
||||
) {
|
||||
throw new Error("Organization Repository Not found");
|
||||
}
|
||||
return data.organization.repository;
|
||||
return {
|
||||
...data.organization.repository,
|
||||
starCount: data.organization.repository.stargazers.totalCount,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
@@ -25,7 +35,10 @@ const fetcher = (variables, token) => {
|
||||
pullRequests(first: 1) {
|
||||
totalCount
|
||||
}
|
||||
issues(first: 1) {
|
||||
openIssues: issues(states: OPEN) {
|
||||
totalCount
|
||||
}
|
||||
closedIssues: issues(states: CLOSED) {
|
||||
totalCount
|
||||
}
|
||||
followers {
|
||||
@@ -34,6 +47,7 @@ const fetcher = (variables, token) => {
|
||||
repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}) {
|
||||
totalCount
|
||||
nodes {
|
||||
name
|
||||
stargazers {
|
||||
totalCount
|
||||
}
|
||||
@@ -66,30 +80,38 @@ const totalCommitsFetcher = async (username) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/vnd.github.cloak-preview",
|
||||
Authorization: `bearer ${token}`,
|
||||
Authorization: `token ${token}`,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
let res = await retryer(fetchTotalCommits, { login: username });
|
||||
if (res.data.total_count) {
|
||||
let total_count = res.data.total_count;
|
||||
if (!!total_count && !isNaN(total_count)) {
|
||||
return res.data.total_count;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.log(err);
|
||||
// just return 0 if there is something wrong so that
|
||||
// we don't break the whole app
|
||||
return 0;
|
||||
}
|
||||
// just return 0 if there is something wrong so that
|
||||
// we don't break the whole app
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} username
|
||||
* @param {boolean} count_private
|
||||
* @param {boolean} include_all_commits
|
||||
* @returns {Promise<import("./types").StatsData>}
|
||||
*/
|
||||
async function fetchStats(
|
||||
username,
|
||||
count_private = false,
|
||||
include_all_commits = false,
|
||||
exclude_repo = [],
|
||||
) {
|
||||
if (!username) throw Error("Invalid username");
|
||||
if (!username) throw new MissingParamError(["username"]);
|
||||
|
||||
const stats = {
|
||||
name: "",
|
||||
@@ -113,8 +135,17 @@ async function fetchStats(
|
||||
|
||||
const user = res.data.data.user;
|
||||
|
||||
// populate repoToHide map for quick lookup
|
||||
// while filtering out
|
||||
let repoToHide = {};
|
||||
if (exclude_repo) {
|
||||
exclude_repo.forEach((repoName) => {
|
||||
repoToHide[repoName] = true;
|
||||
});
|
||||
}
|
||||
|
||||
stats.name = user.name || user.login;
|
||||
stats.totalIssues = user.issues.totalCount;
|
||||
stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount;
|
||||
|
||||
// normal commits
|
||||
stats.totalCommits = user.contributionsCollection.totalCommitContributions;
|
||||
@@ -134,9 +165,14 @@ async function fetchStats(
|
||||
stats.totalPRs = user.pullRequests.totalCount;
|
||||
stats.contributedTo = user.repositoriesContributedTo.totalCount;
|
||||
|
||||
stats.totalStars = user.repositories.nodes.reduce((prev, curr) => {
|
||||
return prev + curr.stargazers.totalCount;
|
||||
}, 0);
|
||||
// Retrieve stars while filtering out repositories to be hidden
|
||||
stats.totalStars = user.repositories.nodes
|
||||
.filter((data) => {
|
||||
return !repoToHide[data.name];
|
||||
})
|
||||
.reduce((prev, curr) => {
|
||||
return prev + curr.stargazers.totalCount;
|
||||
}, 0);
|
||||
|
||||
stats.rank = calculateRank({
|
||||
totalCommits: stats.totalCommits,
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
@@ -29,13 +34,18 @@ const fetcher = (variables, token) => {
|
||||
variables,
|
||||
},
|
||||
{
|
||||
Authorization: `bearer ${token}`,
|
||||
Authorization: `token ${token}`,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} username
|
||||
* @param {string[]} exclude_repo
|
||||
* @returns {Promise<import("./types").TopLangData>}
|
||||
*/
|
||||
async function fetchTopLanguages(username, exclude_repo = []) {
|
||||
if (!username) throw Error("Invalid username");
|
||||
if (!username) throw new MissingParamError(["username"]);
|
||||
|
||||
const res = await retryer(fetcher, { login: username });
|
||||
|
||||
@@ -58,14 +68,10 @@ async function fetchTopLanguages(username, exclude_repo = []) {
|
||||
// filter out repositories to be hidden
|
||||
repoNodes = repoNodes
|
||||
.sort((a, b) => b.size - a.size)
|
||||
.filter((name) => {
|
||||
return !repoToHide[name.name];
|
||||
});
|
||||
.filter((name) => !repoToHide[name.name]);
|
||||
|
||||
repoNodes = repoNodes
|
||||
.filter((node) => {
|
||||
return node.languages.edges.length > 0;
|
||||
})
|
||||
.filter((node) => node.languages.edges.length > 0)
|
||||
// flatten the list of language nodes
|
||||
.reduce((acc, curr) => curr.languages.edges.concat(acc), [])
|
||||
.reduce((acc, prev) => {
|
||||
|
||||
Vendored
+104
@@ -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<string, Lang>;
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -1,11 +1,18 @@
|
||||
const axios = require("axios");
|
||||
const { MissingParamError } = require("../common/utils");
|
||||
|
||||
/**
|
||||
* @param {{username: string, api_domain: string, range: string}} props
|
||||
* @returns {Promise<WakaTimeData>}
|
||||
*/
|
||||
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(/[^a-z-.0-9]/gi, "") : "wakatime.com"
|
||||
}/api/v1/users/${username}/stats/${range || ''}?is_including_today=true`,
|
||||
api_domain ? api_domain.replace(/\/$/gi, "") : "wakatime.com"
|
||||
}/api/v1/users/${username}/stats/${range || ""}?is_including_today=true`,
|
||||
);
|
||||
|
||||
return data.data;
|
||||
|
||||
+26
-4
@@ -1,14 +1,22 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* @param {number} value
|
||||
*/
|
||||
const calculateCircleProgress = (value) => {
|
||||
let radius = 40;
|
||||
let c = Math.PI * (radius * 2);
|
||||
const radius = 40;
|
||||
const c = Math.PI * (radius * 2);
|
||||
|
||||
if (value < 0) value = 0;
|
||||
if (value > 100) value = 100;
|
||||
|
||||
let percentage = ((100 - value) / 100) * c;
|
||||
return percentage;
|
||||
return ((100 - value) / 100) * c;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{progress: number}} param0
|
||||
* @returns
|
||||
*/
|
||||
const getProgressAnimation = ({ progress }) => {
|
||||
return `
|
||||
@keyframes rankAnimation {
|
||||
@@ -44,6 +52,15 @@ const getAnimations = () => {
|
||||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* titleColor?: string | string[]
|
||||
* textColor?: string | string[]
|
||||
* iconColor?: string | string[]
|
||||
* show_icons?: boolean;
|
||||
* progress?: number;
|
||||
* }} args
|
||||
*/
|
||||
const getStyles = ({
|
||||
titleColor,
|
||||
textColor,
|
||||
@@ -55,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;
|
||||
@@ -64,6 +85,7 @@ const getStyles = ({
|
||||
animation: scaleInAnimation 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.not_bold { font-weight: 400 }
|
||||
.bold { font-weight: 700 }
|
||||
.icon {
|
||||
fill: ${iconColor};
|
||||
|
||||
+77
-21
@@ -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: "Sterne Insgesamt",
|
||||
en: "Total Stars",
|
||||
bn: "সর্বমোট Stars",
|
||||
de: "Insgesamt erhaltene Sterne",
|
||||
en: "Total Stars Earned",
|
||||
bn: "সর্বমোট Star",
|
||||
es: "Estrellas totales",
|
||||
fr: "Total d'étoiles",
|
||||
hu: "Csillagok",
|
||||
it: "Stelle totali",
|
||||
ja: "スターされた数",
|
||||
kr: "받은 스타 수",
|
||||
nl: "Totale Sterren",
|
||||
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",
|
||||
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,11 +195,13 @@ const statCardLocales = ({ name, apostrophe }) => {
|
||||
const repoCardLocales = {
|
||||
"repocard.template": {
|
||||
ar: "قالب",
|
||||
bn: "টেমপ্লেট",
|
||||
cn: "模板",
|
||||
"zh-tw": "模板",
|
||||
cs: "Šablona",
|
||||
de: "Vorlage",
|
||||
en: "Template",
|
||||
es: "Planitlla",
|
||||
es: "Plantilla",
|
||||
fr: "Modèle",
|
||||
hu: "Sablon",
|
||||
it: "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",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -8,27 +8,40 @@ 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\\"
|
||||
>
|
||||
<title id=\\"titleId\\"></title>
|
||||
<desc id=\\"descId\\"></desc>
|
||||
<style>
|
||||
.header {
|
||||
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||
fill: #2f80ed;
|
||||
animation: fadeInAnimation 0.8s ease-in-out forwards;
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.header { font-size: 15.5px; }
|
||||
}
|
||||
|
||||
|
||||
.stat {
|
||||
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #333;
|
||||
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #434d58;
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.stat { font-size:12px; }
|
||||
}
|
||||
.stagger {
|
||||
opacity: 0;
|
||||
animation: fadeInAnimation 0.3s ease-in-out forwards;
|
||||
}
|
||||
.rank-text {
|
||||
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #333;
|
||||
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58;
|
||||
animation: scaleInAnimation 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.not_bold { font-weight: 400 }
|
||||
.bold { font-weight: 700 }
|
||||
.icon {
|
||||
fill: #4c71f2;
|
||||
@@ -54,7 +67,7 @@ exports[`Test Render Wakatime Card should render correctly 1`] = `
|
||||
}
|
||||
|
||||
|
||||
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #333 }
|
||||
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58 }
|
||||
|
||||
|
||||
|
||||
@@ -99,16 +112,15 @@ exports[`Test Render Wakatime Card should render correctly 1`] = `
|
||||
<svg x=\\"0\\" y=\\"0\\" width=\\"100%\\">
|
||||
<g transform=\\"translate(0, 0)\\">
|
||||
<g class=\\"stagger\\" style=\\"animation-delay: NaNms\\" transform=\\"translate(25, 0)\\">
|
||||
<text class=\\"stat bold\\" y=\\"12.5\\">Other:</text>
|
||||
<text class=\\"stat bold\\" y=\\"12.5\\" data-testid=\\"Other\\">Other:</text>
|
||||
<text
|
||||
class=\\"stat\\"
|
||||
x=\\"350\\"
|
||||
y=\\"12.5\\"
|
||||
data-testid=\\"Other\\"
|
||||
>19 mins</text>
|
||||
|
||||
<svg width=\\"220\\" x=\\"110\\" y=\\"4\\">
|
||||
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#333\\"></rect>
|
||||
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#434d58\\"></rect>
|
||||
<rect
|
||||
height=\\"8\\"
|
||||
fill=\\"#2f80ed\\"
|
||||
@@ -122,16 +134,15 @@ exports[`Test Render Wakatime Card should render correctly 1`] = `
|
||||
</g>
|
||||
</g><g transform=\\"translate(0, 25)\\">
|
||||
<g class=\\"stagger\\" style=\\"animation-delay: NaNms\\" transform=\\"translate(25, 0)\\">
|
||||
<text class=\\"stat bold\\" y=\\"12.5\\">TypeScript:</text>
|
||||
<text class=\\"stat bold\\" y=\\"12.5\\" data-testid=\\"TypeScript\\">TypeScript:</text>
|
||||
<text
|
||||
class=\\"stat\\"
|
||||
x=\\"350\\"
|
||||
y=\\"12.5\\"
|
||||
data-testid=\\"TypeScript\\"
|
||||
>1 min</text>
|
||||
|
||||
<svg width=\\"220\\" x=\\"110\\" y=\\"4\\">
|
||||
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#333\\"></rect>
|
||||
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#434d58\\"></rect>
|
||||
<rect
|
||||
height=\\"8\\"
|
||||
fill=\\"#2f80ed\\"
|
||||
@@ -159,27 +170,40 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
|
||||
viewBox=\\"0 0 495 115\\"
|
||||
fill=\\"none\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
role=\\"img\\"
|
||||
aria-labelledby=\\"descId\\"
|
||||
>
|
||||
<title id=\\"titleId\\"></title>
|
||||
<desc id=\\"descId\\"></desc>
|
||||
<style>
|
||||
.header {
|
||||
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||
fill: #2f80ed;
|
||||
animation: fadeInAnimation 0.8s ease-in-out forwards;
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.header { font-size: 15.5px; }
|
||||
}
|
||||
|
||||
|
||||
.stat {
|
||||
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #333;
|
||||
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #434d58;
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.stat { font-size:12px; }
|
||||
}
|
||||
.stagger {
|
||||
opacity: 0;
|
||||
animation: fadeInAnimation 0.3s ease-in-out forwards;
|
||||
}
|
||||
.rank-text {
|
||||
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #333;
|
||||
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58;
|
||||
animation: scaleInAnimation 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.not_bold { font-weight: 400 }
|
||||
.bold { font-weight: 700 }
|
||||
.icon {
|
||||
fill: #4c71f2;
|
||||
@@ -205,7 +229,7 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
|
||||
}
|
||||
|
||||
|
||||
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #333 }
|
||||
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58 }
|
||||
|
||||
|
||||
|
||||
|
||||
+7
-6
@@ -35,7 +35,8 @@ const data = {
|
||||
restrictedContributionsCount: 100,
|
||||
},
|
||||
pullRequests: { totalCount: stats.totalPRs },
|
||||
issues: { totalCount: stats.totalIssues },
|
||||
openIssues: { totalCount: stats.totalIssues },
|
||||
closedIssues: { totalCount: 0 },
|
||||
followers: { totalCount: 0 },
|
||||
repositories: {
|
||||
totalCount: 1,
|
||||
@@ -143,17 +144,17 @@ describe("Test /api/", () => {
|
||||
|
||||
expect(res.setHeader.mock.calls).toEqual([
|
||||
["Content-Type", "image/svg+xml"],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
|
||||
]);
|
||||
});
|
||||
|
||||
it("should set proper cache", async () => {
|
||||
const { req, res } = faker({ cache_seconds: 8000 }, data);
|
||||
const { req, res } = faker({ cache_seconds: 15000 }, data);
|
||||
await api(req, res);
|
||||
|
||||
expect(res.setHeader.mock.calls).toEqual([
|
||||
["Content-Type", "image/svg+xml"],
|
||||
["Cache-Control", `public, max-age=${8000}`],
|
||||
["Cache-Control", `public, max-age=${15000}`],
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -175,7 +176,7 @@ describe("Test /api/", () => {
|
||||
|
||||
expect(res.setHeader.mock.calls).toEqual([
|
||||
["Content-Type", "image/svg+xml"],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -185,7 +186,7 @@ describe("Test /api/", () => {
|
||||
|
||||
expect(res.setHeader.mock.calls).toEqual([
|
||||
["Content-Type", "image/svg+xml"],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`],
|
||||
["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
require("@testing-library/jest-dom");
|
||||
const cssToObject = require("css-to-object");
|
||||
const cssToObject = require("@uppercod/css-to-object").cssToObject;
|
||||
const Card = require("../src/common/Card");
|
||||
const icons = require("../src/common/icons");
|
||||
const { getCardColors } = require("../src/common/utils");
|
||||
@@ -137,9 +137,9 @@ describe("Card", () => {
|
||||
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe("#f00");
|
||||
expect(headerClassStyles["fill"].trim()).toBe("#f00");
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#fff",
|
||||
@@ -168,18 +168,18 @@ describe("Card", () => {
|
||||
"fill",
|
||||
"url(#gradient)",
|
||||
);
|
||||
expect(document.querySelector("defs linearGradient")).toHaveAttribute(
|
||||
expect(document.querySelector("defs #gradient")).toHaveAttribute(
|
||||
"gradientTransform",
|
||||
"rotate(90)",
|
||||
);
|
||||
expect(
|
||||
document.querySelector("defs linearGradient stop:nth-child(1)"),
|
||||
document.querySelector("defs #gradient stop:nth-child(1)"),
|
||||
).toHaveAttribute("stop-color", "#fff");
|
||||
expect(
|
||||
document.querySelector("defs linearGradient stop:nth-child(2)"),
|
||||
document.querySelector("defs #gradient stop:nth-child(2)"),
|
||||
).toHaveAttribute("stop-color", "#000");
|
||||
expect(
|
||||
document.querySelector("defs linearGradient stop:nth-child(3)"),
|
||||
document.querySelector("defs #gradient stop:nth-child(3)"),
|
||||
).toHaveAttribute("stop-color", "#f00");
|
||||
});
|
||||
});
|
||||
|
||||
+11
-4
@@ -19,14 +19,14 @@ const data_repo = {
|
||||
|
||||
const data_user = {
|
||||
data: {
|
||||
user: { repository: data_repo },
|
||||
user: { repository: data_repo.repository },
|
||||
organization: null,
|
||||
},
|
||||
};
|
||||
const data_org = {
|
||||
data: {
|
||||
user: null,
|
||||
organization: { repository: data_repo },
|
||||
organization: { repository: data_repo.repository },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -41,14 +41,21 @@ describe("Test fetchRepo", () => {
|
||||
mock.onPost("https://api.github.com/graphql").reply(200, data_user);
|
||||
|
||||
let repo = await fetchRepo("anuraghazra", "convoychat");
|
||||
expect(repo).toStrictEqual(data_repo);
|
||||
|
||||
expect(repo).toStrictEqual({
|
||||
...data_repo.repository,
|
||||
starCount: data_repo.repository.stargazers.totalCount,
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch correct org repo", async () => {
|
||||
mock.onPost("https://api.github.com/graphql").reply(200, data_org);
|
||||
|
||||
let repo = await fetchRepo("anuraghazra", "convoychat");
|
||||
expect(repo).toStrictEqual(data_repo);
|
||||
expect(repo).toStrictEqual({
|
||||
...data_repo.repository,
|
||||
starCount: data_repo.repository.stargazers.totalCount,
|
||||
});
|
||||
});
|
||||
|
||||
it("should throw error if user is found but repo is null", async () => {
|
||||
|
||||
@@ -14,16 +14,17 @@ const data = {
|
||||
restrictedContributionsCount: 50,
|
||||
},
|
||||
pullRequests: { totalCount: 300 },
|
||||
issues: { totalCount: 200 },
|
||||
openIssues: { totalCount: 100 },
|
||||
closedIssues: { totalCount: 100 },
|
||||
followers: { totalCount: 100 },
|
||||
repositories: {
|
||||
totalCount: 5,
|
||||
nodes: [
|
||||
{ stargazers: { totalCount: 100 } },
|
||||
{ stargazers: { totalCount: 100 } },
|
||||
{ stargazers: { totalCount: 100 } },
|
||||
{ stargazers: { totalCount: 50 } },
|
||||
{ stargazers: { totalCount: 50 } },
|
||||
{ name: "test-repo-1", stargazers: { totalCount: 100 } },
|
||||
{ name: "test-repo-2", stargazers: { totalCount: 100 } },
|
||||
{ name: "test-repo-3", stargazers: { totalCount: 100 } },
|
||||
{ name: "test-repo-4", stargazers: { totalCount: 50 } },
|
||||
{ name: "test-repo-5", stargazers: { totalCount: 50 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -133,4 +134,37 @@ describe("Test fetchStats", () => {
|
||||
rank,
|
||||
});
|
||||
});
|
||||
|
||||
it("should exclude stars of the `test-repo-1` repository", async () => {
|
||||
mock.onPost("https://api.github.com/graphql").reply(200, data);
|
||||
mock
|
||||
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
|
||||
.reply(200, { total_count: 1000 });
|
||||
|
||||
let stats = await fetchStats(
|
||||
"anuraghazra",
|
||||
true,
|
||||
true,
|
||||
(exclude_repo = ["test-repo-1"]),
|
||||
);
|
||||
const rank = calculateRank({
|
||||
totalCommits: 1050,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
contributedTo: 61,
|
||||
name: "Anurag Hazra",
|
||||
totalCommits: 1050,
|
||||
totalIssues: 200,
|
||||
totalPRs: 300,
|
||||
totalStars: 300,
|
||||
rank,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,16 +15,19 @@ const data_langs = {
|
||||
repositories: {
|
||||
nodes: [
|
||||
{
|
||||
name: "test-repo-1",
|
||||
languages: {
|
||||
edges: [{ size: 100, node: { color: "#0f0", name: "HTML" } }],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test-repo-2",
|
||||
languages: {
|
||||
edges: [{ size: 100, node: { color: "#0f0", name: "HTML" } }],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test-repo-3",
|
||||
languages: {
|
||||
edges: [
|
||||
{ size: 100, node: { color: "#0ff", name: "javascript" } },
|
||||
@@ -32,6 +35,7 @@ const data_langs = {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test-repo-4",
|
||||
languages: {
|
||||
edges: [
|
||||
{ size: 100, node: { color: "#0ff", name: "javascript" } },
|
||||
@@ -74,6 +78,27 @@ describe("FetchTopLanguages", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch correct language data while excluding the 'test-repo-1' repository", async () => {
|
||||
mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
|
||||
|
||||
let repo = await fetchTopLanguages(
|
||||
"anuraghazra",
|
||||
(exclude_repo = ["test-repo-1"]),
|
||||
);
|
||||
expect(repo).toStrictEqual({
|
||||
HTML: {
|
||||
color: "#0f0",
|
||||
name: "HTML",
|
||||
size: 100,
|
||||
},
|
||||
javascript: {
|
||||
color: "#0ff",
|
||||
name: "javascript",
|
||||
size: 200,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should throw error", async () => {
|
||||
mock.onPost("https://api.github.com/graphql").reply(200, error);
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ describe("Wakatime fetcher", () => {
|
||||
mock.onGet(/\/https:\/\/wakatime\.com\/api/).reply(404, wakaTimeData);
|
||||
|
||||
await expect(fetchWakatimeStats("noone")).rejects.toThrow(
|
||||
"Wakatime user not found, make sure you have a wakatime profile",
|
||||
'Missing params "username" make sure you pass the parameters in URL',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
const { flexLayout } = require("../src/common/utils");
|
||||
|
||||
describe("flexLayout", () => {
|
||||
it("should work with row & col layouts", () => {
|
||||
const layout = flexLayout({
|
||||
items: ["<text>1</text>", "<text>2</text>"],
|
||||
gap: 60,
|
||||
});
|
||||
|
||||
expect(layout).toStrictEqual([
|
||||
`<g transform="translate(0, 0)"><text>1</text></g>`,
|
||||
`<g transform="translate(60, 0)"><text>2</text></g>`,
|
||||
]);
|
||||
|
||||
const columns = flexLayout({
|
||||
items: ["<text>1</text>", "<text>2</text>"],
|
||||
gap: 60,
|
||||
direction: "column",
|
||||
});
|
||||
|
||||
expect(columns).toStrictEqual([
|
||||
`<g transform="translate(0, 0)"><text>1</text></g>`,
|
||||
`<g transform="translate(0, 60)"><text>2</text></g>`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("should work with sizes", () => {
|
||||
const layout = flexLayout({
|
||||
items: [
|
||||
"<text>1</text>",
|
||||
"<text>2</text>",
|
||||
"<text>3</text>",
|
||||
"<text>4</text>",
|
||||
],
|
||||
gap: 20,
|
||||
sizes: [200, 100, 55, 25],
|
||||
});
|
||||
|
||||
expect(layout).toStrictEqual([
|
||||
`<g transform="translate(0, 0)"><text>1</text></g>`,
|
||||
`<g transform="translate(220, 0)"><text>2</text></g>`,
|
||||
`<g transform="translate(340, 0)"><text>3</text></g>`,
|
||||
`<g transform="translate(415, 0)"><text>4</text></g>`,
|
||||
]);
|
||||
});
|
||||
});
|
||||
+16
-3
@@ -9,7 +9,9 @@ const data_repo = {
|
||||
repository: {
|
||||
username: "anuraghazra",
|
||||
name: "convoychat",
|
||||
stargazers: { totalCount: 38000 },
|
||||
stargazers: {
|
||||
totalCount: 38000,
|
||||
},
|
||||
description: "Help us take over the world! React + TS + GraphQL Chat App",
|
||||
primaryLanguage: {
|
||||
color: "#2b7489",
|
||||
@@ -51,7 +53,12 @@ describe("Test /api/pin", () => {
|
||||
await pin(req, res);
|
||||
|
||||
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
|
||||
expect(res.send).toBeCalledWith(renderRepoCard(data_repo.repository));
|
||||
expect(res.send).toBeCalledWith(
|
||||
renderRepoCard({
|
||||
...data_repo.repository,
|
||||
starCount: data_repo.repository.stargazers.totalCount,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("should get the query options", async () => {
|
||||
@@ -76,7 +83,13 @@ describe("Test /api/pin", () => {
|
||||
|
||||
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
|
||||
expect(res.send).toBeCalledWith(
|
||||
renderRepoCard(data_repo.repository, { ...req.query }),
|
||||
renderRepoCard(
|
||||
{
|
||||
...data_repo.repository,
|
||||
starCount: data_repo.repository.stargazers.totalCount,
|
||||
},
|
||||
{ ...req.query },
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require("@testing-library/jest-dom");
|
||||
const cssToObject = require("css-to-object");
|
||||
const cssToObject = require("@uppercod/css-to-object").cssToObject;
|
||||
const renderRepoCard = require("../src/cards/repo-card");
|
||||
|
||||
const { queryByTestId } = require("@testing-library/dom");
|
||||
@@ -9,13 +9,13 @@ const data_repo = {
|
||||
repository: {
|
||||
nameWithOwner: "anuraghazra/convoychat",
|
||||
name: "convoychat",
|
||||
stargazers: { totalCount: 38000 },
|
||||
description: "Help us take over the world! React + TS + GraphQL Chat App",
|
||||
primaryLanguage: {
|
||||
color: "#2b7489",
|
||||
id: "MDg6TGFuZ3VhZ2UyODc=",
|
||||
name: "TypeScript",
|
||||
},
|
||||
starCount: 38000,
|
||||
forkCount: 100,
|
||||
},
|
||||
};
|
||||
@@ -51,6 +51,17 @@ describe("Test renderRepoCard", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should trim header", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
name: "some-really-long-repo-name-for-test-purposes",
|
||||
});
|
||||
|
||||
expect(document.getElementsByClassName("header")[0].textContent).toBe(
|
||||
"some-really-long-repo-name-for-test...",
|
||||
);
|
||||
});
|
||||
|
||||
it("should trim description", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
@@ -89,36 +100,6 @@ describe("Test renderRepoCard", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should shift the text position depending on language length", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
primaryLanguage: {
|
||||
...data_repo.repository.primaryLanguage,
|
||||
name: "Jupyter Notebook",
|
||||
},
|
||||
});
|
||||
|
||||
expect(queryByTestId(document.body, "primary-lang")).toBeInTheDocument();
|
||||
expect(queryByTestId(document.body, "star-fork-group")).toHaveAttribute(
|
||||
"transform",
|
||||
"translate(155, 0)",
|
||||
);
|
||||
|
||||
// Small lang
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
primaryLanguage: {
|
||||
...data_repo.repository.primaryLanguage,
|
||||
name: "Ruby",
|
||||
},
|
||||
});
|
||||
|
||||
expect(queryByTestId(document.body, "star-fork-group")).toHaveAttribute(
|
||||
"transform",
|
||||
"translate(125, 0)",
|
||||
);
|
||||
});
|
||||
|
||||
it("should hide language if primaryLanguage is null & fallback to correct values", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
@@ -149,13 +130,13 @@ describe("Test renderRepoCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const descClassStyles = stylesObject[".description"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const descClassStyles = stylesObject[":host"][".description "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe("#2f80ed");
|
||||
expect(descClassStyles.fill).toBe("#333");
|
||||
expect(iconClassStyles.fill).toBe("#586069");
|
||||
expect(headerClassStyles.fill.trim()).toBe("#2f80ed");
|
||||
expect(descClassStyles.fill.trim()).toBe("#434d58");
|
||||
expect(iconClassStyles.fill.trim()).toBe("#586069");
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#fffefe",
|
||||
@@ -177,13 +158,13 @@ describe("Test renderRepoCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const descClassStyles = stylesObject[".description"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const descClassStyles = stylesObject[":host"][".description "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${customColors.title_color}`);
|
||||
expect(descClassStyles.fill).toBe(`#${customColors.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${customColors.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(`#${customColors.title_color}`);
|
||||
expect(descClassStyles.fill.trim()).toBe(`#${customColors.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${customColors.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#252525",
|
||||
@@ -199,13 +180,15 @@ describe("Test renderRepoCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const descClassStyles = stylesObject[".description"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const descClassStyles = stylesObject[":host"][".description "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${themes[name].title_color}`);
|
||||
expect(descClassStyles.fill).toBe(`#${themes[name].text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes[name].icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(
|
||||
`#${themes[name].title_color}`,
|
||||
);
|
||||
expect(descClassStyles.fill.trim()).toBe(`#${themes[name].text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes[name].icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes[name].bg_color}`,
|
||||
@@ -222,13 +205,13 @@ describe("Test renderRepoCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const descClassStyles = stylesObject[".description"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const descClassStyles = stylesObject[":host"][".description "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe("#5a0");
|
||||
expect(descClassStyles.fill).toBe(`#${themes.radical.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe("#5a0");
|
||||
expect(descClassStyles.fill.trim()).toBe(`#${themes.radical.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes.radical.bg_color}`,
|
||||
@@ -245,13 +228,15 @@ describe("Test renderRepoCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const descClassStyles = stylesObject[".description"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const descClassStyles = stylesObject[":host"][".description "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${themes.default.title_color}`);
|
||||
expect(descClassStyles.fill).toBe(`#${themes.default.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(
|
||||
`#${themes.default.title_color}`,
|
||||
);
|
||||
expect(descClassStyles.fill.trim()).toBe(`#${themes.default.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes.radical.bg_color}`,
|
||||
@@ -261,7 +246,7 @@ describe("Test renderRepoCard", () => {
|
||||
it("should not render star count or fork count if either of the are zero", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
stargazers: { totalCount: 0 },
|
||||
starCount: 0,
|
||||
});
|
||||
|
||||
expect(queryByTestId(document.body, "stargazers")).toBeNull();
|
||||
@@ -269,7 +254,7 @@ describe("Test renderRepoCard", () => {
|
||||
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
stargazers: { totalCount: 1 },
|
||||
starCount: 1,
|
||||
forkCount: 0,
|
||||
});
|
||||
|
||||
@@ -278,7 +263,7 @@ describe("Test renderRepoCard", () => {
|
||||
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
stargazers: { totalCount: 0 },
|
||||
starCount: 0,
|
||||
forkCount: 0,
|
||||
});
|
||||
|
||||
@@ -332,11 +317,24 @@ describe("Test renderRepoCard", () => {
|
||||
);
|
||||
expect(queryByTestId(document.body, "badge")).toHaveTextContent("模板");
|
||||
});
|
||||
|
||||
|
||||
it("should render without rounding", () => {
|
||||
document.body.innerHTML = renderRepoCard(data_repo.repository, { border_radius: "0" });
|
||||
document.body.innerHTML = renderRepoCard(data_repo.repository, {
|
||||
border_radius: "0",
|
||||
});
|
||||
expect(document.querySelector("rect")).toHaveAttribute("rx", "0");
|
||||
document.body.innerHTML = renderRepoCard(data_repo.repository, { });
|
||||
document.body.innerHTML = renderRepoCard(data_repo.repository, {});
|
||||
expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5");
|
||||
});
|
||||
|
||||
it("should fallback to default description", () => {
|
||||
document.body.innerHTML = renderRepoCard({
|
||||
...data_repo.repository,
|
||||
description: undefined,
|
||||
isArchived: true,
|
||||
});
|
||||
expect(document.getElementsByClassName("description")[0]).toHaveTextContent(
|
||||
"No description provided",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require("@testing-library/jest-dom");
|
||||
const cssToObject = require("css-to-object");
|
||||
const cssToObject = require("@uppercod/css-to-object").cssToObject;
|
||||
const renderStatsCard = require("../src/cards/stats-card");
|
||||
|
||||
const {
|
||||
@@ -75,19 +75,65 @@ describe("Test renderStatsCard", () => {
|
||||
expect(queryByTestId(document.body, "rank-circle")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render with custom width set", () => {
|
||||
document.body.innerHTML = renderStatsCard(stats);
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "495");
|
||||
|
||||
document.body.innerHTML = renderStatsCard(stats, { card_width: 400 });
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "400");
|
||||
});
|
||||
|
||||
it("should render with custom width set and limit minimum width", () => {
|
||||
document.body.innerHTML = renderStatsCard(stats, { card_width: 1 });
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "340");
|
||||
|
||||
document.body.innerHTML = renderStatsCard(stats, {
|
||||
card_width: 1,
|
||||
hide_rank: true,
|
||||
});
|
||||
expect(document.querySelector("svg")).toHaveAttribute(
|
||||
"width",
|
||||
"305.81250000000006",
|
||||
);
|
||||
|
||||
document.body.innerHTML = renderStatsCard(stats, {
|
||||
card_width: 1,
|
||||
hide_rank: true,
|
||||
show_icons: true,
|
||||
});
|
||||
expect(document.querySelector("svg")).toHaveAttribute(
|
||||
"width",
|
||||
"305.81250000000006",
|
||||
);
|
||||
|
||||
document.body.innerHTML = renderStatsCard(stats, {
|
||||
card_width: 1,
|
||||
hide_rank: false,
|
||||
show_icons: true,
|
||||
});
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "356");
|
||||
|
||||
document.body.innerHTML = renderStatsCard(stats, {
|
||||
card_width: 1,
|
||||
hide_rank: false,
|
||||
show_icons: false,
|
||||
});
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "340");
|
||||
});
|
||||
|
||||
it("should render default colors properly", () => {
|
||||
document.body.innerHTML = renderStatsCard(stats);
|
||||
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.textContent);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const statClassStyles = stylesObject[".stat"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const statClassStyles = stylesObject[":host"][".stat "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe("#2f80ed");
|
||||
expect(statClassStyles.fill).toBe("#333");
|
||||
expect(iconClassStyles.fill).toBe("#4c71f2");
|
||||
expect(headerClassStyles.fill.trim()).toBe("#2f80ed");
|
||||
expect(statClassStyles.fill.trim()).toBe("#434d58");
|
||||
expect(iconClassStyles.fill.trim()).toBe("#4c71f2");
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#fffefe",
|
||||
@@ -107,13 +153,13 @@ describe("Test renderStatsCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const statClassStyles = stylesObject[".stat"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const statClassStyles = stylesObject[":host"][".stat "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${customColors.title_color}`);
|
||||
expect(statClassStyles.fill).toBe(`#${customColors.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${customColors.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(`#${customColors.title_color}`);
|
||||
expect(statClassStyles.fill.trim()).toBe(`#${customColors.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${customColors.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#252525",
|
||||
@@ -129,13 +175,13 @@ describe("Test renderStatsCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const statClassStyles = stylesObject[".stat"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const statClassStyles = stylesObject[":host"][".stat "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe("#5a0");
|
||||
expect(statClassStyles.fill).toBe(`#${themes.radical.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe("#5a0");
|
||||
expect(statClassStyles.fill.trim()).toBe(`#${themes.radical.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes.radical.bg_color}`,
|
||||
@@ -151,13 +197,15 @@ describe("Test renderStatsCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const statClassStyles = stylesObject[".stat"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const statClassStyles = stylesObject[":host"][".stat "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${themes[name].title_color}`);
|
||||
expect(statClassStyles.fill).toBe(`#${themes[name].text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes[name].icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(
|
||||
`#${themes[name].title_color}`,
|
||||
);
|
||||
expect(statClassStyles.fill.trim()).toBe(`#${themes[name].text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes[name].icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes[name].bg_color}`,
|
||||
@@ -175,13 +223,15 @@ describe("Test renderStatsCard", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerClassStyles = stylesObject[".header"];
|
||||
const statClassStyles = stylesObject[".stat"];
|
||||
const iconClassStyles = stylesObject[".icon"];
|
||||
const headerClassStyles = stylesObject[":host"][".header "];
|
||||
const statClassStyles = stylesObject[":host"][".stat "];
|
||||
const iconClassStyles = stylesObject[":host"][".icon "];
|
||||
|
||||
expect(headerClassStyles.fill).toBe(`#${themes.default.title_color}`);
|
||||
expect(statClassStyles.fill).toBe(`#${themes.default.text_color}`);
|
||||
expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(headerClassStyles.fill.trim()).toBe(
|
||||
`#${themes.default.title_color}`,
|
||||
);
|
||||
expect(statClassStyles.fill.trim()).toBe(`#${themes.default.text_color}`);
|
||||
expect(iconClassStyles.fill.trim()).toBe(`#${themes.radical.icon_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes.radical.bg_color}`,
|
||||
@@ -245,7 +295,7 @@ describe("Test renderStatsCard", () => {
|
||||
document.querySelector(
|
||||
'g[transform="translate(0, 25)"]>.stagger>.stat.bold',
|
||||
).textContent,
|
||||
).toMatchInlineSnapshot(`"累计提交数(commit) (2021):"`);
|
||||
).toMatchInlineSnapshot(`"累计提交数(commit) (2022):"`);
|
||||
expect(
|
||||
document.querySelector(
|
||||
'g[transform="translate(0, 50)"]>.stagger>.stat.bold',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
require("@testing-library/jest-dom");
|
||||
const cssToObject = require("css-to-object");
|
||||
const fetchTopLanguages = require("../src/fetchers/top-languages-fetcher");
|
||||
const cssToObject = require("@uppercod/css-to-object").cssToObject;
|
||||
const renderTopLanguages = require("../src/cards/top-languages-card");
|
||||
|
||||
const { queryByTestId, queryAllByTestId } = require("@testing-library/dom");
|
||||
@@ -104,17 +103,32 @@ describe("Test renderTopLanguages", () => {
|
||||
expect(document.querySelector("svg")).toHaveAttribute("width", "400");
|
||||
});
|
||||
|
||||
it("should render with min width", () => {
|
||||
document.body.innerHTML = renderTopLanguages(langs, { card_width: 190 });
|
||||
|
||||
expect(document.querySelector("svg")).toHaveAttribute(
|
||||
"width",
|
||||
renderTopLanguages.MIN_CARD_WIDTH.toString(),
|
||||
);
|
||||
|
||||
document.body.innerHTML = renderTopLanguages(langs, { card_width: 100 });
|
||||
expect(document.querySelector("svg")).toHaveAttribute(
|
||||
"width",
|
||||
renderTopLanguages.MIN_CARD_WIDTH.toString(),
|
||||
);
|
||||
});
|
||||
|
||||
it("should render default colors properly", () => {
|
||||
document.body.innerHTML = renderTopLanguages(langs);
|
||||
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.textContent);
|
||||
|
||||
const headerStyles = stylesObject[".header"];
|
||||
const langNameStyles = stylesObject[".lang-name"];
|
||||
const headerStyles = stylesObject[":host"][".header "];
|
||||
const langNameStyles = stylesObject[":host"][".lang-name "];
|
||||
|
||||
expect(headerStyles.fill).toBe("#2f80ed");
|
||||
expect(langNameStyles.fill).toBe("#333");
|
||||
expect(headerStyles.fill.trim()).toBe("#2f80ed");
|
||||
expect(langNameStyles.fill.trim()).toBe("#434d58");
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#fffefe",
|
||||
@@ -134,11 +148,11 @@ describe("Test renderTopLanguages", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerStyles = stylesObject[".header"];
|
||||
const langNameStyles = stylesObject[".lang-name"];
|
||||
const headerStyles = stylesObject[":host"][".header "];
|
||||
const langNameStyles = stylesObject[":host"][".lang-name "];
|
||||
|
||||
expect(headerStyles.fill).toBe(`#${customColors.title_color}`);
|
||||
expect(langNameStyles.fill).toBe(`#${customColors.text_color}`);
|
||||
expect(headerStyles.fill.trim()).toBe(`#${customColors.title_color}`);
|
||||
expect(langNameStyles.fill.trim()).toBe(`#${customColors.text_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
"#252525",
|
||||
@@ -154,11 +168,11 @@ describe("Test renderTopLanguages", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerStyles = stylesObject[".header"];
|
||||
const langNameStyles = stylesObject[".lang-name"];
|
||||
const headerStyles = stylesObject[":host"][".header "];
|
||||
const langNameStyles = stylesObject[":host"][".lang-name "];
|
||||
|
||||
expect(headerStyles.fill).toBe("#5a0");
|
||||
expect(langNameStyles.fill).toBe(`#${themes.radical.text_color}`);
|
||||
expect(headerStyles.fill.trim()).toBe("#5a0");
|
||||
expect(langNameStyles.fill.trim()).toBe(`#${themes.radical.text_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes.radical.bg_color}`,
|
||||
@@ -174,11 +188,11 @@ describe("Test renderTopLanguages", () => {
|
||||
const styleTag = document.querySelector("style");
|
||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
||||
|
||||
const headerStyles = stylesObject[".header"];
|
||||
const langNameStyles = stylesObject[".lang-name"];
|
||||
const headerStyles = stylesObject[":host"][".header "];
|
||||
const langNameStyles = stylesObject[":host"][".lang-name "];
|
||||
|
||||
expect(headerStyles.fill).toBe(`#${themes[name].title_color}`);
|
||||
expect(langNameStyles.fill).toBe(`#${themes[name].text_color}`);
|
||||
expect(headerStyles.fill.trim()).toBe(`#${themes[name].title_color}`);
|
||||
expect(langNameStyles.fill.trim()).toBe(`#${themes[name].text_color}`);
|
||||
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
|
||||
"fill",
|
||||
`#${themes[name].bg_color}`,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require("@testing-library/jest-dom");
|
||||
const renderWakatimeCard = require("../src/cards/wakatime-card");
|
||||
const { queryByTestId } = require("@testing-library/dom");
|
||||
|
||||
const renderWakatimeCard = require("../src/cards/wakatime-card");
|
||||
const { wakaTimeData } = require("./fetchWakatime.test");
|
||||
|
||||
describe("Test Render Wakatime Card", () => {
|
||||
@@ -16,6 +17,16 @@ describe("Test Render Wakatime Card", () => {
|
||||
expect(card).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hide languages when hide is passed", () => {
|
||||
document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, {
|
||||
hide: ["YAML", "Other"],
|
||||
});
|
||||
|
||||
expect(queryByTestId(document.body, /YAML/i)).toBeNull();
|
||||
expect(queryByTestId(document.body, /Other/i)).toBeNull();
|
||||
expect(queryByTestId(document.body, /TypeScript/i)).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should render translations", () => {
|
||||
document.body.innerHTML = renderWakatimeCard({}, { locale: "cn" });
|
||||
expect(document.getElementsByClassName("header")[0].textContent).toBe(
|
||||
@@ -28,9 +39,24 @@ describe("Test Render Wakatime Card", () => {
|
||||
});
|
||||
|
||||
it("should render without rounding", () => {
|
||||
document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, { border_radius: "0" });
|
||||
document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, {
|
||||
border_radius: "0",
|
||||
});
|
||||
expect(document.querySelector("rect")).toHaveAttribute("rx", "0");
|
||||
document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, { });
|
||||
document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, {});
|
||||
expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5");
|
||||
});
|
||||
|
||||
it('should show "no coding activitiy this week" message when there hasn not been activity', () => {
|
||||
document.body.innerHTML = renderWakatimeCard(
|
||||
{
|
||||
...wakaTimeData.data,
|
||||
languages: undefined,
|
||||
},
|
||||
{},
|
||||
);
|
||||
expect(document.querySelector(".stat").textContent).toBe(
|
||||
"No coding activity this week",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+7
-21
@@ -44,27 +44,6 @@ describe("Test utils.js", () => {
|
||||
).toHaveTextContent(/Secondary Message/gim);
|
||||
});
|
||||
|
||||
it("should test flexLayout", () => {
|
||||
const layout = flexLayout({
|
||||
items: ["<text>1</text>", "<text>2</text>"],
|
||||
gap: 60,
|
||||
}).join("");
|
||||
|
||||
expect(layout).toBe(
|
||||
`<g transform=\"translate(0, 0)\"><text>1</text></g><g transform=\"translate(60, 0)\"><text>2</text></g>`,
|
||||
);
|
||||
|
||||
const columns = flexLayout({
|
||||
items: ["<text>1</text>", "<text>2</text>"],
|
||||
gap: 60,
|
||||
direction: "column",
|
||||
}).join("");
|
||||
|
||||
expect(columns).toBe(
|
||||
`<g transform=\"translate(0, 0)\"><text>1</text></g><g transform=\"translate(0, 60)\"><text>2</text></g>`,
|
||||
);
|
||||
});
|
||||
|
||||
it("getCardColors: should return expected values", () => {
|
||||
let colors = getCardColors({
|
||||
title_color: "f00",
|
||||
@@ -138,4 +117,11 @@ describe("wrapTextMultiline", () => {
|
||||
);
|
||||
expect(multiLineText).toEqual(["Hello", "world long..."]);
|
||||
});
|
||||
it("should wrap chinese by punctuation", () => {
|
||||
let multiLineText = wrapTextMultiline(
|
||||
"专门为刚开始刷题的同学准备的算法基地,没有最细只有更细,立志用动画将晦涩难懂的算法说的通俗易懂!",
|
||||
);
|
||||
expect(multiLineText.length).toEqual(3);
|
||||
expect(multiLineText[0].length).toEqual(18 * 8); // &#xxxxx; x 8
|
||||
});
|
||||
});
|
||||
|
||||
+70
-30
@@ -2,7 +2,7 @@
|
||||
|
||||
<!-- DO NOT EDIT THIS FILE DIRECTLY -->
|
||||
|
||||
With inbuilt themes you can customize the look of the card without doing any manual customization.
|
||||
With inbuilt themes, you can customize the look of the card without doing any manual customization.
|
||||
|
||||
Use `?theme=THEME_NAME` parameter like so :-
|
||||
|
||||
@@ -17,20 +17,25 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
| | | |
|
||||
| :--: | :--: | :--: |
|
||||
| `default` ![default][default] | `dark` ![dark][dark] | `radical` ![radical][radical] |
|
||||
| `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | `tokyonight` ![tokyonight][tokyonight] |
|
||||
| `onedark` ![onedark][onedark] | `cobalt` ![cobalt][cobalt] | `synthwave` ![synthwave][synthwave] |
|
||||
| `highcontrast` ![highcontrast][highcontrast] | `dracula` ![dracula][dracula] | `prussian` ![prussian][prussian] |
|
||||
| `monokai` ![monokai][monokai] | `vue` ![vue][vue] | `vue-dark` ![vue-dark][vue-dark] |
|
||||
| `shades-of-purple` ![shades-of-purple][shades-of-purple] | `nightowl` ![nightowl][nightowl] | `buefy` ![buefy][buefy] |
|
||||
| `blue-green` ![blue-green][blue-green] | `algolia` ![algolia][algolia] | `great-gatsby` ![great-gatsby][great-gatsby] |
|
||||
| `darcula` ![darcula][darcula] | `bear` ![bear][bear] | `solarized-dark` ![solarized-dark][solarized-dark] |
|
||||
| `solarized-light` ![solarized-light][solarized-light] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] | `nord` ![nord][nord] |
|
||||
| `gotham` ![gotham][gotham] | `material-palenight` ![material-palenight][material-palenight] | `graywhite` ![graywhite][graywhite] |
|
||||
| `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | `ayu-mirage` ![ayu-mirage][ayu-mirage] | `midnight-purple` ![midnight-purple][midnight-purple] |
|
||||
| `calm` ![calm][calm] | `flag-india` ![flag-india][flag-india] | `omni` ![omni][omni] |
|
||||
| `react` ![react][react] | `jolly` ![jolly][jolly] | `maroongold` ![maroongold][maroongold] |
|
||||
| `yeblu` ![yeblu][yeblu] | `blueberry` ![blueberry][blueberry] | `slateorange` ![slateorange][slateorange] |
|
||||
| `kacho_ga` ![kacho_ga][kacho_ga] | `outrun` ![outrun][outrun] | [Add your theme][add-theme] |
|
||||
| `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | `gruvbox_light` ![gruvbox_light][gruvbox_light] |
|
||||
| `tokyonight` ![tokyonight][tokyonight] | `onedark` ![onedark][onedark] | `cobalt` ![cobalt][cobalt] |
|
||||
| `synthwave` ![synthwave][synthwave] | `highcontrast` ![highcontrast][highcontrast] | `dracula` ![dracula][dracula] |
|
||||
| `prussian` ![prussian][prussian] | `monokai` ![monokai][monokai] | `vue` ![vue][vue] |
|
||||
| `vue-dark` ![vue-dark][vue-dark] | `shades-of-purple` ![shades-of-purple][shades-of-purple] | `nightowl` ![nightowl][nightowl] |
|
||||
| `buefy` ![buefy][buefy] | `blue-green` ![blue-green][blue-green] | `algolia` ![algolia][algolia] |
|
||||
| `great-gatsby` ![great-gatsby][great-gatsby] | `darcula` ![darcula][darcula] | `bear` ![bear][bear] |
|
||||
| `solarized-dark` ![solarized-dark][solarized-dark] | `solarized-light` ![solarized-light][solarized-light] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] |
|
||||
| `nord` ![nord][nord] | `gotham` ![gotham][gotham] | `material-palenight` ![material-palenight][material-palenight] |
|
||||
| `graywhite` ![graywhite][graywhite] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | `ayu-mirage` ![ayu-mirage][ayu-mirage] |
|
||||
| `midnight-purple` ![midnight-purple][midnight-purple] | `calm` ![calm][calm] | `flag-india` ![flag-india][flag-india] |
|
||||
| `omni` ![omni][omni] | `react` ![react][react] | `jolly` ![jolly][jolly] |
|
||||
| `maroongold` ![maroongold][maroongold] | `yeblu` ![yeblu][yeblu] | `blueberry` ![blueberry][blueberry] |
|
||||
| `slateorange` ![slateorange][slateorange] | `kacho_ga` ![kacho_ga][kacho_ga] | `outrun` ![outrun][outrun] |
|
||||
| `ocean_dark` ![ocean_dark][ocean_dark] | `city_lights` ![city_lights][city_lights] | `github_dark` ![github_dark][github_dark] |
|
||||
| `discord_old_blurple` ![discord_old_blurple][discord_old_blurple] | `aura_dark` ![aura_dark][aura_dark] | `panda` ![panda][panda] |
|
||||
| `noctis_minimus` ![noctis_minimus][noctis_minimus] | `cobalt2` ![cobalt2][cobalt2] | `swift` ![swift][swift] |
|
||||
| `aura` ![aura][aura] | `apprentice` ![apprentice][apprentice] | `moltack` ![moltack][moltack] |
|
||||
| `codeSTACKr` ![codeSTACKr][codeSTACKr] | `rose_pine` ![rose_pine][rose_pine] | [Add your theme][add-theme] |
|
||||
|
||||
## Repo Card
|
||||
|
||||
@@ -39,20 +44,25 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
| | | |
|
||||
| :--: | :--: | :--: |
|
||||
| `default_repocard` ![default_repocard][default_repocard_repo] | `dark` ![dark][dark_repo] | `radical` ![radical][radical_repo] |
|
||||
| `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | `tokyonight` ![tokyonight][tokyonight_repo] |
|
||||
| `onedark` ![onedark][onedark_repo] | `cobalt` ![cobalt][cobalt_repo] | `synthwave` ![synthwave][synthwave_repo] |
|
||||
| `highcontrast` ![highcontrast][highcontrast_repo] | `dracula` ![dracula][dracula_repo] | `prussian` ![prussian][prussian_repo] |
|
||||
| `monokai` ![monokai][monokai_repo] | `vue` ![vue][vue_repo] | `vue-dark` ![vue-dark][vue-dark_repo] |
|
||||
| `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | `nightowl` ![nightowl][nightowl_repo] | `buefy` ![buefy][buefy_repo] |
|
||||
| `blue-green` ![blue-green][blue-green_repo] | `algolia` ![algolia][algolia_repo] | `great-gatsby` ![great-gatsby][great-gatsby_repo] |
|
||||
| `darcula` ![darcula][darcula_repo] | `bear` ![bear][bear_repo] | `solarized-dark` ![solarized-dark][solarized-dark_repo] |
|
||||
| `solarized-light` ![solarized-light][solarized-light_repo] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] | `nord` ![nord][nord_repo] |
|
||||
| `gotham` ![gotham][gotham_repo] | `material-palenight` ![material-palenight][material-palenight_repo] | `graywhite` ![graywhite][graywhite_repo] |
|
||||
| `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] | `midnight-purple` ![midnight-purple][midnight-purple_repo] |
|
||||
| `calm` ![calm][calm_repo] | `flag-india` ![flag-india][flag-india_repo] | `omni` ![omni][omni_repo] |
|
||||
| `react` ![react][react_repo] | `jolly` ![jolly][jolly_repo] | `maroongold` ![maroongold][maroongold_repo] |
|
||||
| `yeblu` ![yeblu][yeblu_repo] | `blueberry` ![blueberry][blueberry_repo] | `slateorange` ![slateorange][slateorange_repo] |
|
||||
| `kacho_ga` ![kacho_ga][kacho_ga_repo] | `outrun` ![outrun][outrun_repo] | [Add your theme][add-theme] |
|
||||
| `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | `gruvbox_light` ![gruvbox_light][gruvbox_light_repo] |
|
||||
| `tokyonight` ![tokyonight][tokyonight_repo] | `onedark` ![onedark][onedark_repo] | `cobalt` ![cobalt][cobalt_repo] |
|
||||
| `synthwave` ![synthwave][synthwave_repo] | `highcontrast` ![highcontrast][highcontrast_repo] | `dracula` ![dracula][dracula_repo] |
|
||||
| `prussian` ![prussian][prussian_repo] | `monokai` ![monokai][monokai_repo] | `vue` ![vue][vue_repo] |
|
||||
| `vue-dark` ![vue-dark][vue-dark_repo] | `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | `nightowl` ![nightowl][nightowl_repo] |
|
||||
| `buefy` ![buefy][buefy_repo] | `blue-green` ![blue-green][blue-green_repo] | `algolia` ![algolia][algolia_repo] |
|
||||
| `great-gatsby` ![great-gatsby][great-gatsby_repo] | `darcula` ![darcula][darcula_repo] | `bear` ![bear][bear_repo] |
|
||||
| `solarized-dark` ![solarized-dark][solarized-dark_repo] | `solarized-light` ![solarized-light][solarized-light_repo] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] |
|
||||
| `nord` ![nord][nord_repo] | `gotham` ![gotham][gotham_repo] | `material-palenight` ![material-palenight][material-palenight_repo] |
|
||||
| `graywhite` ![graywhite][graywhite_repo] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] |
|
||||
| `midnight-purple` ![midnight-purple][midnight-purple_repo] | `calm` ![calm][calm_repo] | `flag-india` ![flag-india][flag-india_repo] |
|
||||
| `omni` ![omni][omni_repo] | `react` ![react][react_repo] | `jolly` ![jolly][jolly_repo] |
|
||||
| `maroongold` ![maroongold][maroongold_repo] | `yeblu` ![yeblu][yeblu_repo] | `blueberry` ![blueberry][blueberry_repo] |
|
||||
| `slateorange` ![slateorange][slateorange_repo] | `kacho_ga` ![kacho_ga][kacho_ga_repo] | `outrun` ![outrun][outrun_repo] |
|
||||
| `ocean_dark` ![ocean_dark][ocean_dark_repo] | `city_lights` ![city_lights][city_lights_repo] | `github_dark` ![github_dark][github_dark_repo] |
|
||||
| `discord_old_blurple` ![discord_old_blurple][discord_old_blurple_repo] | `aura_dark` ![aura_dark][aura_dark_repo] | `panda` ![panda][panda_repo] |
|
||||
| `noctis_minimus` ![noctis_minimus][noctis_minimus_repo] | `cobalt2` ![cobalt2][cobalt2_repo] | `swift` ![swift][swift_repo] |
|
||||
| `aura` ![aura][aura_repo] | `apprentice` ![apprentice][apprentice_repo] | `moltack` ![moltack][moltack_repo] |
|
||||
| `codeSTACKr` ![codeSTACKr][codeSTACKr_repo] | `rose_pine` ![rose_pine][rose_pine_repo] | [Add your theme][add-theme] |
|
||||
|
||||
|
||||
[default]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=default
|
||||
@@ -61,6 +71,7 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
[radical]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=radical
|
||||
[merko]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=merko
|
||||
[gruvbox]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=gruvbox
|
||||
[gruvbox_light]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=gruvbox_light
|
||||
[tokyonight]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=tokyonight
|
||||
[onedark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=onedark
|
||||
[cobalt]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=cobalt
|
||||
@@ -100,6 +111,20 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
[slateorange]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=slateorange
|
||||
[kacho_ga]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=kacho_ga
|
||||
[outrun]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=outrun
|
||||
[ocean_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=ocean_dark
|
||||
[city_lights]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=city_lights
|
||||
[github_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=github_dark
|
||||
[discord_old_blurple]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=discord_old_blurple
|
||||
[aura_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=aura_dark
|
||||
[panda]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=panda
|
||||
[noctis_minimus]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=noctis_minimus
|
||||
[cobalt2]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=cobalt2
|
||||
[swift]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=swift
|
||||
[aura]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=aura
|
||||
[apprentice]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=apprentice
|
||||
[moltack]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=moltack
|
||||
[codeSTACKr]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=codeSTACKr
|
||||
[rose_pine]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=rose_pine
|
||||
|
||||
|
||||
[default_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=default
|
||||
@@ -108,6 +133,7 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
[radical_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=radical
|
||||
[merko_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=merko
|
||||
[gruvbox_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=gruvbox
|
||||
[gruvbox_light_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=gruvbox_light
|
||||
[tokyonight_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=tokyonight
|
||||
[onedark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=onedark
|
||||
[cobalt_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=cobalt
|
||||
@@ -147,8 +173,22 @@ Use `?theme=THEME_NAME` parameter like so :-
|
||||
[slateorange_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=slateorange
|
||||
[kacho_ga_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=kacho_ga
|
||||
[outrun_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=outrun
|
||||
[ocean_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=ocean_dark
|
||||
[city_lights_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=city_lights
|
||||
[github_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=github_dark
|
||||
[discord_old_blurple_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=discord_old_blurple
|
||||
[aura_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=aura_dark
|
||||
[panda_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=panda
|
||||
[noctis_minimus_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=noctis_minimus
|
||||
[cobalt2_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=cobalt2
|
||||
[swift_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=swift
|
||||
[aura_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=aura
|
||||
[apprentice_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=apprentice
|
||||
[moltack_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=moltack
|
||||
[codeSTACKr_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=codeSTACKr
|
||||
[rose_pine_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=rose_pine
|
||||
|
||||
|
||||
[add-theme]: https://github.com/anuraghazra/github-readme-stats/edit/master/themes/index.js
|
||||
|
||||
Wanted to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
||||
Want to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
||||
|
||||
+69
-2
@@ -2,14 +2,14 @@ const themes = {
|
||||
default: {
|
||||
title_color: "2f80ed",
|
||||
icon_color: "4c71f2",
|
||||
text_color: "333",
|
||||
text_color: "434d58",
|
||||
bg_color: "fffefe",
|
||||
border_color: "e4e2e2",
|
||||
},
|
||||
default_repocard: {
|
||||
title_color: "2f80ed",
|
||||
icon_color: "586069", // icon color is different
|
||||
text_color: "333",
|
||||
text_color: "434d58",
|
||||
bg_color: "fffefe",
|
||||
},
|
||||
dark: {
|
||||
@@ -36,6 +36,12 @@ const themes = {
|
||||
text_color: "8ec07c",
|
||||
bg_color: "282828",
|
||||
},
|
||||
gruvbox_light: {
|
||||
title_color: "b57614",
|
||||
icon_color: "af3a03",
|
||||
text_color: "427b58",
|
||||
bg_color: "fbf1c7",
|
||||
},
|
||||
tokyonight: {
|
||||
title_color: "70a5fd",
|
||||
icon_color: "bf91f3",
|
||||
@@ -294,6 +300,67 @@ const themes = {
|
||||
text_color: "FFFFFF",
|
||||
bg_color: "2C2F33",
|
||||
},
|
||||
aura_dark: {
|
||||
title_color: "ff7372",
|
||||
icon_color: "6cffd0",
|
||||
text_color: "dbdbdb",
|
||||
bg_color: "252334",
|
||||
},
|
||||
panda: {
|
||||
title_color: "19f9d899",
|
||||
icon_color: "19f9d899",
|
||||
text_color: "FF75B5",
|
||||
bg_color: "31353a",
|
||||
},
|
||||
noctis_minimus: {
|
||||
title_color: "d3b692",
|
||||
icon_color: "72b7c0",
|
||||
text_color: "c5cdd3",
|
||||
bg_color: "1b2932",
|
||||
},
|
||||
cobalt2: {
|
||||
title_color: "ffc600",
|
||||
icon_color: "ffffff",
|
||||
text_color: "0088ff",
|
||||
bg_color: "193549",
|
||||
},
|
||||
swift: {
|
||||
title_color: "000000",
|
||||
icon_color: "f05237",
|
||||
text_color: "000000",
|
||||
bg_color: "f7f7f7",
|
||||
},
|
||||
aura: {
|
||||
title_color: "a277ff",
|
||||
icon_color: "ffca85",
|
||||
text_color: "61ffca",
|
||||
bg_color: "15141b",
|
||||
},
|
||||
apprentice: {
|
||||
title_color: "ffffff",
|
||||
icon_color: "ffffaf",
|
||||
text_color: "bcbcbc",
|
||||
bg_color: "262626",
|
||||
},
|
||||
moltack: {
|
||||
title_color: "86092C",
|
||||
icon_color: "86092C",
|
||||
text_color: "574038",
|
||||
bg_color: "F5E1C0",
|
||||
},
|
||||
codeSTACKr: {
|
||||
title_color: "ff652f",
|
||||
icon_color: "FFE400",
|
||||
text_color: "ffffff",
|
||||
bg_color: "09131B",
|
||||
border_color: "0c1a25",
|
||||
},
|
||||
rose_pine: {
|
||||
title_color: "9ccfd8",
|
||||
icon_color: "ebbcba",
|
||||
text_color: "e0def4",
|
||||
bg_color: "191724",
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = themes;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"functions": {
|
||||
"api/*.js": {
|
||||
"memory": 128,
|
||||
"maxDuration": 30
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/",
|
||||
|
||||
Reference in New Issue
Block a user