forked from mirrored/github-readme-stats
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2abbdf940 |
@@ -1,30 +0,0 @@
|
||||
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.
|
||||
@@ -25,9 +25,5 @@ jobs:
|
||||
npm install
|
||||
npm run test
|
||||
|
||||
- name: Run Prettier
|
||||
run: |
|
||||
npm run format:check
|
||||
|
||||
- name: Code Coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
|
||||
@@ -15,7 +15,6 @@ jobs:
|
||||
with:
|
||||
label: false
|
||||
dashboard: true
|
||||
dashboard_show_total_reactions: true
|
||||
top_issues: true
|
||||
top_bugs: true
|
||||
top_features: true
|
||||
|
||||
@@ -17,7 +17,6 @@ module.exports = async (req, res) => {
|
||||
hide,
|
||||
hide_title,
|
||||
hide_border,
|
||||
card_width,
|
||||
hide_rank,
|
||||
show_icons,
|
||||
count_private,
|
||||
@@ -66,7 +65,6 @@ 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,
|
||||
|
||||
+1
-3
@@ -8,9 +8,7 @@
|
||||
"test:watch": "jest --watch",
|
||||
"theme-readme-gen": "node scripts/generate-theme-doc",
|
||||
"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 ."
|
||||
"generate-langs-json": "node scripts/generate-langs-json"
|
||||
},
|
||||
"author": "Anurag Hazra",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -169,7 +169,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
|
||||
- `theme` - name of the theme, choose from [all available themes](./themes/README.md)
|
||||
- `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.
|
||||
|
||||
@@ -187,7 +187,6 @@ You can provide multiple comma-separated values in the bg_color option to render
|
||||
|
||||
- `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)_
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
const fs = require("fs");
|
||||
const jsYaml = require("js-yaml");
|
||||
const axios = require("axios");
|
||||
const fs = require('fs');
|
||||
const jsYaml = require('js-yaml');
|
||||
const axios = require('axios');
|
||||
|
||||
const LANGS_FILEPATH = "./src/common/languageColors.json";
|
||||
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);
|
||||
axios.get("https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml")
|
||||
.then((response) => {
|
||||
|
||||
const languageColors = {};
|
||||
//and convert them to a JS Object
|
||||
const languages = jsYaml.load(response.data);
|
||||
|
||||
//Filter only language colors from the whole file
|
||||
Object.keys(languages).forEach((lang) => {
|
||||
languageColors[lang] = languages[lang].color;
|
||||
});
|
||||
const languageColors = {};
|
||||
|
||||
//Debug Print
|
||||
//console.dir(languageColors);
|
||||
fs.writeFileSync(
|
||||
LANGS_FILEPATH,
|
||||
JSON.stringify(languageColors, null, " "),
|
||||
);
|
||||
//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, ' '));
|
||||
|
||||
});
|
||||
|
||||
@@ -65,11 +65,11 @@ function calculateRank({
|
||||
|
||||
const level = (() => {
|
||||
if (normalizedScore < RANK_S_VALUE) return "S+";
|
||||
if (normalizedScore < RANK_DOUBLE_A_VALUE) return "S";
|
||||
if (normalizedScore < RANK_A2_VALUE) return "A++";
|
||||
if (normalizedScore < RANK_A3_VALUE) return "A+";
|
||||
return "B+";
|
||||
})();
|
||||
if (normalizedScore >= RANK_S_VALUE && normalizedScore < RANK_DOUBLE_A_VALUE) return "S";
|
||||
if (normalizedScore >= RANK_DOUBLE_A_VALUE && normalizedScore < RANK_A2_VALUE) return "A++";
|
||||
if (normalizedScore >= RANK_A2_VALUE && normalizedScore < RANK_A3_VALUE) return "A+"
|
||||
if (normalizedScore >= RANK_A3_VALUE && normalizedScore < RANK_B_VALUE) return "B+"
|
||||
})()
|
||||
|
||||
return { level, score: normalizedScore };
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ const iconWithLabel = (icon, label, testid) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('../fetchers/types').RepositoryData} repo
|
||||
* @param {Partial<import("./types").RepoCardOptions>} options
|
||||
* @param {import('../fetchers/types').RepositoryData} repo
|
||||
* @param {Partial<import("./types").RepoCardOptions>} options
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderRepoCard = (repo, options = {}) => {
|
||||
@@ -167,11 +167,11 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
return card.render(`
|
||||
${
|
||||
isTemplate
|
||||
? // @ts-ignore
|
||||
getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
|
||||
// @ts-ignore
|
||||
? getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
|
||||
: isArchived
|
||||
? // @ts-ignore
|
||||
getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
|
||||
// @ts-ignore
|
||||
? getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
|
||||
: ""
|
||||
}
|
||||
|
||||
|
||||
+32
-59
@@ -36,10 +36,10 @@ const createTextNode = ({
|
||||
<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"
|
||||
x="${(showIcons ? 140 : 120) + shiftValuePos}"
|
||||
y="12.5"
|
||||
data-testid="${id}"
|
||||
>${kValue}</text>
|
||||
</g>
|
||||
@@ -66,7 +66,6 @@ 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,
|
||||
@@ -175,6 +174,26 @@ 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="-5"
|
||||
y="3"
|
||||
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;
|
||||
@@ -190,20 +209,13 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
return measureText(custom_title ? custom_title : i18n.t("statcard.title"));
|
||||
};
|
||||
|
||||
/*
|
||||
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 width = hide_rank
|
||||
? clampValue(
|
||||
50 /* padding */ + calculateTextWidth() * 2,
|
||||
270 /* min */,
|
||||
Infinity,
|
||||
)
|
||||
: 495;
|
||||
|
||||
const card = new Card({
|
||||
customTitle: custom_title,
|
||||
@@ -226,45 +238,6 @@ 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))
|
||||
@@ -291,7 +264,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
gap: lheight,
|
||||
direction: "column",
|
||||
}).join("")}
|
||||
</svg>
|
||||
</svg>
|
||||
`);
|
||||
};
|
||||
|
||||
|
||||
@@ -86,16 +86,15 @@ const totalCommitsFetcher = async (username) => {
|
||||
|
||||
try {
|
||||
let res = await retryer(fetchTotalCommits, { login: username });
|
||||
let total_count = res.data.total_count;
|
||||
if (!!total_count && !isNaN(total_count)) {
|
||||
if (res.data.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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ const { MissingParamError } = require("../common/utils");
|
||||
*/
|
||||
const fetchWakatimeStats = async ({ username, api_domain, range }) => {
|
||||
if (!username) throw new MissingParamError(["username"]);
|
||||
|
||||
|
||||
try {
|
||||
const { data } = await axios.get(
|
||||
`https://${
|
||||
|
||||
@@ -81,10 +81,7 @@ 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"]),
|
||||
);
|
||||
let repo = await fetchTopLanguages("anuraghazra", exclude_repo=["test-repo-1"]);
|
||||
expect(repo).toStrictEqual({
|
||||
HTML: {
|
||||
color: "#0f0",
|
||||
|
||||
@@ -207,7 +207,7 @@ describe("Wakatime fetcher", () => {
|
||||
mock.onGet(/\/https:\/\/wakatime\.com\/api/).reply(404, wakaTimeData);
|
||||
|
||||
await expect(fetchWakatimeStats("noone")).rejects.toThrow(
|
||||
'Missing params "username" make sure you pass the parameters in URL',
|
||||
"Missing params \"username\" make sure you pass the parameters in URL",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,52 +75,6 @@ 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);
|
||||
|
||||
|
||||
@@ -48,15 +48,10 @@ describe("Test Render Wakatime Card", () => {
|
||||
});
|
||||
|
||||
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",
|
||||
);
|
||||
});
|
||||
document.body.innerHTML = renderWakatimeCard({
|
||||
...wakaTimeData.data,
|
||||
languages: undefined
|
||||
}, {});
|
||||
expect(document.querySelector(".stat").textContent).toBe("No coding activity this week")
|
||||
})
|
||||
});
|
||||
|
||||
+2
-2
@@ -355,12 +355,12 @@ const themes = {
|
||||
bg_color: "09131B",
|
||||
border_color: "0c1a25",
|
||||
},
|
||||
rose_pine: {
|
||||
"rose_pine":{
|
||||
title_color: "9ccfd8",
|
||||
icon_color: "ebbcba",
|
||||
text_color: "e0def4",
|
||||
bg_color: "191724",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = themes;
|
||||
|
||||
Reference in New Issue
Block a user