Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d37c706f | ||
|
|
3a24ad62b1 | ||
|
|
989079e4fd | ||
|
|
20bddc3a0c | ||
|
|
19bacf780a | ||
|
|
89bb8fea42 | ||
|
|
0bade9be77 | ||
|
|
2658a8737d |
+60
-19
@@ -1,3 +1,21 @@
|
||||
// https://stackoverflow.com/a/5263759/10629172
|
||||
function normalcdf(mean, sigma, to) {
|
||||
var z = (to - mean) / Math.sqrt(2 * sigma * sigma);
|
||||
var t = 1 / (1 + 0.3275911 * Math.abs(z));
|
||||
var a1 = 0.254829592;
|
||||
var a2 = -0.284496736;
|
||||
var a3 = 1.421413741;
|
||||
var a4 = -1.453152027;
|
||||
var a5 = 1.061405429;
|
||||
var erf =
|
||||
1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-z * z);
|
||||
var sign = 1;
|
||||
if (z < 0) {
|
||||
sign = -1;
|
||||
}
|
||||
return (1 / 2) * (1 + sign * erf);
|
||||
}
|
||||
|
||||
function calculateRank({
|
||||
totalRepos,
|
||||
totalCommits,
|
||||
@@ -13,12 +31,24 @@ function calculateRank({
|
||||
const STARS_OFFSET = 0.75;
|
||||
const PRS_OFFSET = 0.5;
|
||||
const FOLLOWERS_OFFSET = 0.45;
|
||||
const REPO_OFFSET = 1;
|
||||
|
||||
const FIRST_STEP = 0;
|
||||
const SECOND_STEP = 5;
|
||||
const THIRD_STEP = 20;
|
||||
const FOURTH_STEP = 50;
|
||||
const FIFTH_STEP = 130;
|
||||
const ALL_OFFSETS =
|
||||
CONTRIBS_OFFSET +
|
||||
ISSUES_OFFSET +
|
||||
STARS_OFFSET +
|
||||
PRS_OFFSET +
|
||||
FOLLOWERS_OFFSET +
|
||||
REPO_OFFSET;
|
||||
|
||||
const RANK_S_VALUE = 1;
|
||||
const RANK_DOUBLE_A_VALUE = 25;
|
||||
const RANK_A2_VALUE = 45;
|
||||
const RANK_A3_VALUE = 60;
|
||||
const RANK_B_VALUE = 100;
|
||||
|
||||
const TOTAL_VALUES =
|
||||
RANK_S_VALUE + RANK_A2_VALUE + RANK_A3_VALUE + RANK_B_VALUE;
|
||||
|
||||
// prettier-ignore
|
||||
const score = (
|
||||
@@ -27,26 +57,37 @@ function calculateRank({
|
||||
issues * ISSUES_OFFSET +
|
||||
stargazers * STARS_OFFSET +
|
||||
prs * PRS_OFFSET +
|
||||
followers * FOLLOWERS_OFFSET
|
||||
) / totalRepos;
|
||||
followers * FOLLOWERS_OFFSET +
|
||||
totalRepos * REPO_OFFSET
|
||||
) / 100;
|
||||
|
||||
const normalizedScore = normalcdf(score, TOTAL_VALUES, ALL_OFFSETS) * 100;
|
||||
|
||||
let level = "";
|
||||
|
||||
if (score == FIRST_STEP) {
|
||||
level = "B";
|
||||
} else if (score > FIRST_STEP && score <= SECOND_STEP) {
|
||||
level = "B+";
|
||||
} else if (score > SECOND_STEP && score <= THIRD_STEP) {
|
||||
level = "A";
|
||||
} else if (score > THIRD_STEP && score <= FOURTH_STEP) {
|
||||
level = "A+";
|
||||
} else if (score > FOURTH_STEP && score <= FIFTH_STEP) {
|
||||
level = "A++";
|
||||
} else if (score > FIFTH_STEP) {
|
||||
if (normalizedScore < RANK_S_VALUE) {
|
||||
level = "S+";
|
||||
}
|
||||
if (
|
||||
normalizedScore >= RANK_S_VALUE &&
|
||||
normalizedScore < RANK_DOUBLE_A_VALUE
|
||||
) {
|
||||
level = "S";
|
||||
}
|
||||
if (
|
||||
normalizedScore >= RANK_DOUBLE_A_VALUE &&
|
||||
normalizedScore < RANK_A2_VALUE
|
||||
) {
|
||||
level = "A++";
|
||||
}
|
||||
if (normalizedScore >= RANK_A2_VALUE && normalizedScore < RANK_A3_VALUE) {
|
||||
level = "A+";
|
||||
}
|
||||
if (normalizedScore >= RANK_A3_VALUE && normalizedScore < RANK_B_VALUE) {
|
||||
level = "B+";
|
||||
}
|
||||
|
||||
return { level, score };
|
||||
return { level, score: normalizedScore };
|
||||
}
|
||||
|
||||
module.exports = calculateRank;
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ const fetcher = (variables, token) => {
|
||||
followers {
|
||||
totalCount
|
||||
}
|
||||
repositories(first: 100, orderBy: { direction: DESC, field: STARGAZERS }) {
|
||||
repositories(first: 100, ownerAffiliations: OWNER, isFork: false, orderBy: {direction: DESC, field: STARGAZERS}) {
|
||||
totalCount
|
||||
nodes {
|
||||
stargazers {
|
||||
|
||||
+11
-14
@@ -1,23 +1,24 @@
|
||||
const { kFormatter, encodeHTML, isValidHexColor } = require("../src/utils");
|
||||
const { kFormatter, encodeHTML, fallbackColor } = require("../src/utils");
|
||||
|
||||
const renderRepoCard = (repo, options = {}) => {
|
||||
const { name, description, primaryLanguage, stargazers, forkCount } = repo;
|
||||
const { title_color, icon_color, text_color, bg_color } = options;
|
||||
|
||||
const langName = primaryLanguage ? primaryLanguage.name : "Unspecified";
|
||||
const langColor = primaryLanguage ? primaryLanguage.color : "#333";
|
||||
|
||||
const height = 120;
|
||||
const shiftText = primaryLanguage.name.length > 15 ? 0 : 30;
|
||||
const shiftText = langName.length > 15 ? 0 : 30;
|
||||
|
||||
let desc = description || "No description provided";
|
||||
if (desc.length > 55) {
|
||||
desc = `${description.slice(0, 55)}..`;
|
||||
}
|
||||
|
||||
const titleColor =
|
||||
(isValidHexColor(title_color) && `#${title_color}`) || "#2f80ed";
|
||||
const iconColor =
|
||||
(isValidHexColor(icon_color) && `#${icon_color}`) || "#586069";
|
||||
const textColor = (isValidHexColor(text_color) && `#${text_color}`) || "#333";
|
||||
const bgColor = (isValidHexColor(bg_color) && `#${bg_color}`) || "#FFFEFE";
|
||||
const titleColor = fallbackColor(title_color, "#2f80ed");
|
||||
const iconColor = fallbackColor(icon_color, "#586069");
|
||||
const textColor = fallbackColor(text_color, "#333");
|
||||
const bgColor = fallbackColor(bg_color, "#FFFEFE");
|
||||
|
||||
const totalStars = kFormatter(stargazers.totalCount);
|
||||
const totalForks = kFormatter(forkCount);
|
||||
@@ -38,12 +39,8 @@ const renderRepoCard = (repo, options = {}) => {
|
||||
<text class="description" x="25" y="70">${encodeHTML(desc)}</text>
|
||||
|
||||
<g transform="translate(30, 100)">
|
||||
<circle data-testid="lang-color" cx="0" cy="-5" r="6" fill="${
|
||||
primaryLanguage.color
|
||||
}" />
|
||||
<text data-testid="lang" class="gray" x="15">${
|
||||
primaryLanguage.name
|
||||
}</text>
|
||||
<circle data-testid="lang-color" cx="0" cy="-5" r="6" fill="${langColor}" />
|
||||
<text data-testid="lang" class="gray" x="15">${langName}</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(${155 - shiftText}, 100)">
|
||||
|
||||
+9
-16
@@ -1,4 +1,4 @@
|
||||
const { kFormatter, isValidHexColor } = require("../src/utils");
|
||||
const { kFormatter, fallbackColor } = require("../src/utils");
|
||||
const getStyles = require("./getStyles");
|
||||
|
||||
const createTextNode = ({ icon, label, value, id, index, lineHeight }) => {
|
||||
@@ -43,12 +43,10 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
|
||||
const lheight = parseInt(line_height);
|
||||
|
||||
const titleColor =
|
||||
(isValidHexColor(title_color) && `#${title_color}`) || "#2f80ed";
|
||||
const iconColor =
|
||||
(isValidHexColor(icon_color) && `#${icon_color}`) || "#4c71f2";
|
||||
const textColor = (isValidHexColor(text_color) && `#${text_color}`) || "#333";
|
||||
const bgColor = (isValidHexColor(bg_color) && `#${bg_color}`) || "#FFFEFE";
|
||||
const titleColor = fallbackColor(title_color, "#2f80ed");
|
||||
const iconColor = fallbackColor(icon_color, "#4c71f2");
|
||||
const textColor = fallbackColor(text_color, "#333");
|
||||
const bgColor = fallbackColor(bg_color, "#FFFEFE");
|
||||
|
||||
const STATS = {
|
||||
stars: {
|
||||
@@ -118,7 +116,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
|
||||
<circle class="rank-circle" cx="-10" cy="8" r="40" />
|
||||
<text
|
||||
x="0"
|
||||
x="${rank.level.length === 1 ? "-4" : "0"}"
|
||||
y="0"
|
||||
alignment-baseline="central"
|
||||
dominant-baseline="central"
|
||||
@@ -129,14 +127,9 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
</text>
|
||||
</g>`;
|
||||
|
||||
// re-adjust circle progressbar's value until the ranking algo is improved
|
||||
let progress = rank.score;
|
||||
if (rank.score > 86) {
|
||||
progress = (40 + rank.score) * 0.6;
|
||||
}
|
||||
if (rank.score < 40) {
|
||||
progress = 40 + rank.score;
|
||||
}
|
||||
// the better user's score the the rank will be closer to zero so
|
||||
// subtracting 100 to get the progress in 100%
|
||||
let progress = 100 - rank.score;
|
||||
|
||||
const styles = getStyles({
|
||||
titleColor,
|
||||
|
||||
@@ -43,6 +43,10 @@ function parseBoolean(value) {
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackColor(color, fallbackColor) {
|
||||
return (isValidHexColor(color) && `#${color}`) || fallbackColor;
|
||||
}
|
||||
|
||||
function request(data, headers) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios({
|
||||
@@ -65,4 +69,5 @@ module.exports = {
|
||||
isValidHexColor,
|
||||
request,
|
||||
parseBoolean,
|
||||
fallbackColor,
|
||||
};
|
||||
|
||||
@@ -13,6 +13,6 @@ describe("Test calculateRank", () => {
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
})
|
||||
).toStrictEqual({ level: "S+", score: 192.13 });
|
||||
).toStrictEqual({ level: "A+", score: 49.16605417270399 });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user