Commit 6059cb16 authored by anuraghazra's avatar anuraghazra
Browse files

feat: added animations!

parent cbd0e583
Loading
Loading
Loading
Loading

src/getStyles.js

0 → 100644
+97 −0
Original line number Diff line number Diff line
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;
+23 −29
Original line number Diff line number Diff line
const { kFormatter, isValidHexColor } = require("../src/utils");
const getStyles = require("./getStyles");

const createTextNode = ({ icon, label, value, id, index, lineHeight }) => {
  const classname = icon === "" && "star-icon";
  const kValue = kFormatter(value);
  const staggerDelay = (index + 3) * 150;
  // manually calculating lineHeight based on index instead of using <tspan dy="" />
  // to fix firefox layout bug
  const lheight = lineHeight * (index + 1);
  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" class="stat bold">
       ${label}:
@@ -107,7 +110,6 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
    />
  `;

  const rankProgress = 180 + rank.score * 0.8;
  const rankCircle = hide_rank
    ? ""
    : `<g data-testid="rank-circle" transform="translate(400, ${
@@ -122,42 +124,34 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
          dominant-baseline="central"
          text-anchor="middle"
          class="rank-text"
          transform="translate(-5, 5)"
        >
          ${rank.level}
        </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;
  }

  const styles = getStyles({
    titleColor,
    textColor,
    iconColor,
    show_icons,
    progress,
  });

  return `
    <svg width="495" height="${height}" viewBox="0 0 495 ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
      <style>
      .header { font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${titleColor}; }
      .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);
      }
        ${styles}
      </style>
      
      ${hide_border ? "" : border}

      ${rankCircle}
+3 −2
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ describe("Test renderStatsCard", () => {
    totalIssues: 300,
    totalPRs: 400,
    contributedTo: 500,
    rank: { level: "A+", score: 100 },
    rank: { level: "A+", score: 40 },
  };

  it("should render correctly", () => {
@@ -66,7 +66,8 @@ describe("Test renderStatsCard", () => {
    document.body.innerHTML = renderStatsCard(stats);

    const styleTag = document.querySelector("style");
    const stylesObject = cssToObject(styleTag.innerHTML);
    console.log(styleTag.textContent);
    const stylesObject = cssToObject(styleTag.textContent);

    const headerClassStyles = stylesObject[".header"];
    const statClassStyles = stylesObject[".stat"];