perf: align icons and text vertical (#33)

* improve: improved rating algorithm wip

* Fixed typos, punctuation [...]

Corrected many instances of "Github" to "GitHub", fixed the punctuation on some sections, fixed the ~lack of~ uppercase chars in others, tweaked the grammar a bit, and added the Vercel guide to a spoiler-ish section so it's only visible if you click to expand.

<3

* fix: github rate limiter with multiple PATs

* perf: vertically align text left

* refactor: refactored retryer logic & handled invalid tokens

* chore: remove redundant codes

`axios` is Promise based, there is no need to wrap it into a Promise constructor again

* fix: query param booleans

* design: fixed rank alignment

* chore: rebase from master

* fix: fixed repo card breaking in absence of primaryLanguage

* fix: fixed stars count #39 & fixed progressbar percentage

* perf: replace emoji icons with GitHub SVG icons

* chore: added funding link

* refactor: refacted icons to another file

* test: added test for icons

Co-authored-by: anuraghazra <hazru.anurag@gmail.com>
Co-authored-by: Micael Jarniac <micael@jarniac.com>
Co-authored-by: JounQin <admin@1stg.me>
This commit is contained in:
Rico 2020-07-16 18:21:21 +08:00 committed by GitHub
parent 331295139d
commit 6d4fbfecfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 22 deletions

View File

@ -64,9 +64,6 @@ const getStyles = ({
} }
.bold { font-weight: 700 } .bold { font-weight: 700 }
.star-icon {
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
}
.icon { .icon {
fill: ${iconColor}; fill: ${iconColor};
display: ${!!show_icons ? "block" : "none"}; display: ${!!show_icons ? "block" : "none"};

11
src/icons.js Normal file
View File

@ -0,0 +1,11 @@
const icons = {
star: `<path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"/>`,
commits: `<path fill-rule="evenodd" d="M1.643 3.143L.427 1.927A.25.25 0 000 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 00.177-.427L2.715 4.215a6.5 6.5 0 11-1.18 4.458.75.75 0 10-1.493.154 8.001 8.001 0 101.6-5.684zM7.75 4a.75.75 0 01.75.75v2.992l2.028.812a.75.75 0 01-.557 1.392l-2.5-1A.75.75 0 017 8.25v-3.5A.75.75 0 017.75 4z"/>`,
prs: `<path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"/>`,
issues: `<path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"/>`,
icon: `<path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>`,
contribs: `<path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>`,
fork: `<path fill-rule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"></path>`,
};
module.exports = icons;

View File

@ -1,4 +1,5 @@
const { kFormatter, encodeHTML, fallbackColor } = require("../src/utils"); const { kFormatter, encodeHTML, fallbackColor } = require("../src/utils");
const icons = require("./icons");
const renderRepoCard = (repo, options = {}) => { const renderRepoCard = (repo, options = {}) => {
const { name, description, primaryLanguage, stargazers, forkCount } = repo; const { name, description, primaryLanguage, stargazers, forkCount } = repo;
@ -32,7 +33,7 @@ const renderRepoCard = (repo, options = {}) => {
</style> </style>
<rect data-testid="card-border" x="0.5" y="0.5" width="399" height="99%" rx="4.5" fill="${bgColor}" stroke="#E4E2E2"/> <rect data-testid="card-border" x="0.5" y="0.5" width="399" height="99%" rx="4.5" fill="${bgColor}" stroke="#E4E2E2"/>
<svg class="icon" x="25" y="25" viewBox="0 0 16 16" version="1.1" width="16" height="16"> <svg class="icon" x="25" y="25" viewBox="0 0 16 16" version="1.1" width="16" height="16">
<path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"></path> ${icons.contribs}
</svg> </svg>
<text x="50" y="38" class="header">${name}</text> <text x="50" y="38" class="header">${name}</text>
@ -45,14 +46,14 @@ const renderRepoCard = (repo, options = {}) => {
<g transform="translate(${155 - shiftText}, 100)"> <g transform="translate(${155 - shiftText}, 100)">
<svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16"> <svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16">
<path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path> ${icons.star}
</svg> </svg>
<text data-testid="stargazers" class="gray" x="25">${totalStars}</text> <text data-testid="stargazers" class="gray" x="25">${totalStars}</text>
</g> </g>
<g transform="translate(${220 - shiftText}, 100)"> <g transform="translate(${220 - shiftText}, 100)">
<svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16"> <svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16">
<path fill-rule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"></path> ${icons.fork}
</svg> </svg>
<text data-testid="forkcount" class="gray" x="25">${totalForks}</text> <text data-testid="forkcount" class="gray" x="25">${totalForks}</text>
</g> </g>

View File

@ -1,21 +1,36 @@
const { kFormatter, fallbackColor } = require("../src/utils"); const { kFormatter, fallbackColor } = require("../src/utils");
const getStyles = require("./getStyles"); const getStyles = require("./getStyles");
const icons = require("./icons");
const createTextNode = ({ icon, label, value, id, index, lineHeight }) => { const createTextNode = ({
const classname = icon === "★" && "star-icon"; icon,
label,
value,
id,
index,
lineHeight,
showIcons,
}) => {
const kValue = kFormatter(value); const kValue = kFormatter(value);
const staggerDelay = (index + 3) * 150; const staggerDelay = (index + 3) * 150;
// manually calculating lineHeight based on index instead of using <tspan dy="" /> // manually calculating lineHeight based on index instead of using <tspan dy="" />
// to fix firefox layout bug // to fix firefox layout bug
const lheight = lineHeight * (index + 1); const lheight = lineHeight * (index + 1);
const translateY = lheight - lineHeight / 2;
const labelOffset = showIcons ? `x="25"` : "";
const iconSvg = showIcons
? `
<svg data-testid="icon" class="icon" viewBox="0 0 16 16" version="1.1" width="16" height="16">
${icon}
</svg>
`
: "";
return ` return `
<text class="stagger" style="animation-delay: ${staggerDelay}ms" x="25" y="${lheight}"> <g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, ${translateY})">
<tspan dx="0" data-testid="icon" class="icon ${classname}">${icon}</tspan> ${iconSvg}
<tspan dx="0" class="stat bold"> <text class="stat bold" ${labelOffset} y="12.5">${label}:</text>
${label}: <text class="stat" x="135" y="12.5" data-testid="${id}">${kValue}</text>
</tspan> </g>
<tspan x="160" data-testid="${id}" class="stat">${kValue}</tspan>
</text>
`; `;
}; };
@ -50,31 +65,31 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
const STATS = { const STATS = {
stars: { stars: {
icon: "★", icon: icons.star,
label: "Total Stars", label: "Total Stars",
value: totalStars, value: totalStars,
id: "stars", id: "stars",
}, },
commits: { commits: {
icon: "🕗", icon: icons.commits,
label: "Total Commits", label: "Total Commits",
value: totalCommits, value: totalCommits,
id: "commits", id: "commits",
}, },
prs: { prs: {
icon: "🔀", icon: icons.prs,
label: "Total PRs", label: "Total PRs",
value: totalPRs, value: totalPRs,
id: "prs", id: "prs",
}, },
issues: { issues: {
icon: "ⓘ", icon: icons.issues,
label: "Total Issues", label: "Total Issues",
value: totalIssues, value: totalIssues,
id: "issues", id: "issues",
}, },
contribs: { contribs: {
icon: "📕", icon: icons.contribs,
label: "Contributed to", label: "Contributed to",
value: contributedTo, value: contributedTo,
id: "contribs", id: "contribs",
@ -85,7 +100,12 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
.filter((key) => !hide.includes(key)) .filter((key) => !hide.includes(key))
.map((key, index) => .map((key, index) =>
// create the text nodes, and pass index so that we can calculate the line spacing // create the text nodes, and pass index so that we can calculate the line spacing
createTextNode({ ...STATS[key], index, lineHeight: lheight }) createTextNode({
...STATS[key],
index,
lineHeight: lheight,
showIcons: show_icons,
})
); );
// Calculate the card height depending on how many items there are // Calculate the card height depending on how many items there are

View File

@ -2,7 +2,11 @@ require("@testing-library/jest-dom");
const cssToObject = require("css-to-object"); const cssToObject = require("css-to-object");
const renderStatsCard = require("../src/renderStatsCard"); const renderStatsCard = require("../src/renderStatsCard");
const { getByTestId, queryByTestId } = require("@testing-library/dom"); const {
getByTestId,
queryByTestId,
queryAllByTestId,
} = require("@testing-library/dom");
describe("Test renderStatsCard", () => { describe("Test renderStatsCard", () => {
const stats = { const stats = {
@ -107,4 +111,27 @@ describe("Test renderStatsCard", () => {
"#252525" "#252525"
); );
}); });
it("should render icons correctly", () => {
document.body.innerHTML = renderStatsCard(stats, {
show_icons: "true",
});
expect(queryAllByTestId(document.body, "icon")[0]).toBeDefined();
expect(queryByTestId(document.body, "stars")).toBeDefined();
expect(
queryByTestId(document.body, "stars").previousElementSibling // the label
).toHaveAttribute("x", "25");
});
it("should not have icons if show_icons is false", () => {
document.body.innerHTML = renderStatsCard(stats, { show_icons: false });
console.log(queryAllByTestId(document.body, "icon"));
expect(queryAllByTestId(document.body, "icon")[0]).not.toBeDefined();
expect(queryByTestId(document.body, "stars")).toBeDefined();
expect(
queryByTestId(document.body, "stars").previousElementSibling // the label
).not.toHaveAttribute("x");
});
}); });