mirror of
https://github.com/anuraghazra/github-readme-stats.git
synced 2025-03-07 15:08:07 +08:00
Merge pull request #50 from anuraghazra/animations
feat: added animations!
This commit is contained in:
commit
c297798889
97
src/getStyles.js
Normal file
97
src/getStyles.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
const calculateCircleProgress = (value) => {
|
||||||
|
let radius = 40;
|
||||||
|
let c = Math.PI * (radius * 2);
|
||||||
|
|
||||||
|
if (value < 0) value = 0;
|
||||||
|
if (value > 100) value = 100;
|
||||||
|
|
||||||
|
let percentage = ((100 - value) / 100) * c;
|
||||||
|
return percentage;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAnimations = ({ progress }) => {
|
||||||
|
return `
|
||||||
|
/* Animations */
|
||||||
|
@keyframes scaleIn {
|
||||||
|
from {
|
||||||
|
transform: translate(-5px, 5px) scale(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translate(-5px, 5px) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes rankAnimation {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: ${calculateCircleProgress(0)};
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: ${calculateCircleProgress(progress)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = ({
|
||||||
|
titleColor,
|
||||||
|
textColor,
|
||||||
|
iconColor,
|
||||||
|
show_icons,
|
||||||
|
progress,
|
||||||
|
}) => {
|
||||||
|
return `
|
||||||
|
.header {
|
||||||
|
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${titleColor};
|
||||||
|
animation: fadeIn 0.8s ease-in-out forwards;
|
||||||
|
}
|
||||||
|
.stat {
|
||||||
|
font: 600 14px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
|
||||||
|
}
|
||||||
|
.stagger {
|
||||||
|
opacity: 0;
|
||||||
|
animation: fadeIn 0.3s ease-in-out forwards;
|
||||||
|
}
|
||||||
|
.rank-text {
|
||||||
|
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
|
||||||
|
animation: scaleIn 0.3s ease-in-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bold { font-weight: 700 }
|
||||||
|
.star-icon {
|
||||||
|
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
fill: ${iconColor};
|
||||||
|
display: ${!!show_icons ? "block" : "none"};
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-circle-rim {
|
||||||
|
stroke: ${titleColor};
|
||||||
|
fill: none;
|
||||||
|
stroke-width: 6;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
.rank-circle {
|
||||||
|
stroke: ${titleColor};
|
||||||
|
stroke-dasharray: 250;
|
||||||
|
fill: none;
|
||||||
|
stroke-width: 6;
|
||||||
|
stroke-linecap: round;
|
||||||
|
opacity: 0.8;
|
||||||
|
transform-origin: -10px 8px;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
animation: rankAnimation 1s forwards ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
${process.env.NODE_ENV === "test" ? "" : getAnimations({ progress })}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = getStyles;
|
@ -1,12 +1,15 @@
|
|||||||
const { kFormatter, isValidHexColor } = require("../src/utils");
|
const { kFormatter, isValidHexColor } = require("../src/utils");
|
||||||
|
const getStyles = require("./getStyles");
|
||||||
|
|
||||||
const createTextNode = ({ icon, label, value, id, index, lineHeight }) => {
|
const createTextNode = ({ icon, label, value, id, index, lineHeight }) => {
|
||||||
const classname = icon === "★" && "star-icon";
|
const classname = icon === "★" && "star-icon";
|
||||||
const kValue = kFormatter(value);
|
const kValue = kFormatter(value);
|
||||||
|
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);
|
||||||
return `
|
return `
|
||||||
<text x="25" y="${lineHeight * (index + 1)}">
|
<text class="stagger" style="animation-delay: ${staggerDelay}ms" x="25" y="${lheight}">
|
||||||
<tspan dx="0" data-testid="icon" class="icon ${classname}">${icon}</tspan>
|
<tspan dx="0" data-testid="icon" class="icon ${classname}">${icon}</tspan>
|
||||||
<tspan dx="0" class="stat bold">
|
<tspan dx="0" class="stat bold">
|
||||||
${label}:
|
${label}:
|
||||||
@ -107,7 +110,6 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
|||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const rankProgress = 180 + rank.score * 0.8;
|
|
||||||
const rankCircle = hide_rank
|
const rankCircle = hide_rank
|
||||||
? ""
|
? ""
|
||||||
: `<g data-testid="rank-circle" transform="translate(400, ${
|
: `<g data-testid="rank-circle" transform="translate(400, ${
|
||||||
@ -122,42 +124,34 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
|||||||
dominant-baseline="central"
|
dominant-baseline="central"
|
||||||
text-anchor="middle"
|
text-anchor="middle"
|
||||||
class="rank-text"
|
class="rank-text"
|
||||||
transform="translate(-5, 5)"
|
|
||||||
>
|
>
|
||||||
${rank.level}
|
${rank.level}
|
||||||
</text>
|
</text>
|
||||||
</g>`;
|
</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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = getStyles({
|
||||||
|
titleColor,
|
||||||
|
textColor,
|
||||||
|
iconColor,
|
||||||
|
show_icons,
|
||||||
|
progress,
|
||||||
|
});
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<svg width="495" height="${height}" viewBox="0 0 495 ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="495" height="${height}" viewBox="0 0 495 ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<style>
|
<style>
|
||||||
.header { font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${titleColor}; }
|
${styles}
|
||||||
.stat { font: 600 14px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor}; }
|
|
||||||
.rank-text { font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor}; }
|
|
||||||
.star-icon { font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; }
|
|
||||||
.bold { font-weight: 700 }
|
|
||||||
.icon {
|
|
||||||
fill: ${iconColor};
|
|
||||||
display: ${!!show_icons ? "block" : "none"};
|
|
||||||
}
|
|
||||||
.rank-circle-rim {
|
|
||||||
stroke: ${titleColor};
|
|
||||||
fill: none;
|
|
||||||
stroke-width: 6;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
.rank-circle {
|
|
||||||
stroke-dashoffset: 30;
|
|
||||||
stroke-dasharray: ${rankProgress};
|
|
||||||
stroke: ${titleColor};
|
|
||||||
fill: none;
|
|
||||||
stroke-width: 6;
|
|
||||||
stroke-linecap: round;
|
|
||||||
opacity: 0.8;
|
|
||||||
transform-origin: -10px 8px;
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
${hide_border ? "" : border}
|
${hide_border ? "" : border}
|
||||||
|
|
||||||
${rankCircle}
|
${rankCircle}
|
||||||
|
@ -12,7 +12,7 @@ describe("Test renderStatsCard", () => {
|
|||||||
totalIssues: 300,
|
totalIssues: 300,
|
||||||
totalPRs: 400,
|
totalPRs: 400,
|
||||||
contributedTo: 500,
|
contributedTo: 500,
|
||||||
rank: { level: "A+", score: 100 },
|
rank: { level: "A+", score: 40 },
|
||||||
};
|
};
|
||||||
|
|
||||||
it("should render correctly", () => {
|
it("should render correctly", () => {
|
||||||
@ -66,7 +66,8 @@ describe("Test renderStatsCard", () => {
|
|||||||
document.body.innerHTML = renderStatsCard(stats);
|
document.body.innerHTML = renderStatsCard(stats);
|
||||||
|
|
||||||
const styleTag = document.querySelector("style");
|
const styleTag = document.querySelector("style");
|
||||||
const stylesObject = cssToObject(styleTag.innerHTML);
|
console.log(styleTag.textContent);
|
||||||
|
const stylesObject = cssToObject(styleTag.textContent);
|
||||||
|
|
||||||
const headerClassStyles = stylesObject[".header"];
|
const headerClassStyles = stylesObject[".header"];
|
||||||
const statClassStyles = stylesObject[".stat"];
|
const statClassStyles = stylesObject[".stat"];
|
||||||
|
Loading…
Reference in New Issue
Block a user