Skip to content

Commit

Permalink
refactor: added reusable Card class to reduce code & test duplication (
Browse files Browse the repository at this point in the history
…#260)

* refactor: added reusable Card class to reduce code & test duplication

* fix: top-langs card width & documented card_width option
  • Loading branch information
anuraghazra authored Jul 30, 2020
1 parent 34b5dcb commit 3b0f1b1
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 229 deletions.
7 changes: 4 additions & 3 deletions api/top-langs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ module.exports = async (req, res) => {
username,
hide,
hide_title,
hide_border,
card_width,
title_color,
text_color,
bg_color,
theme,
cache_seconds,
layout
layout,
} = req.query;
let topLangs;

Expand All @@ -42,15 +43,15 @@ module.exports = async (req, res) => {

res.send(
renderTopLanguages(topLangs, {
theme,
hide_title: parseBoolean(hide_title),
hide_border: parseBoolean(hide_border),
card_width: parseInt(card_width, 10),
hide: parseArray(hide),
title_color,
text_color,
bg_color,
theme,
layout
layout,
})
);
};
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ Customization Options:
| cache_seconds | number | manually set custom cache control | 1800 | 1800 | 1800 |
| count_private | boolean | counts private contributions too if enabled | false | N/A | N/A |
| layout | string | choose a layout option | N/A | N/A | 'default' |
| card_width | number | set the card width | N/A | N/A | 300 |

> Note on cache: Repo cards have default cache of 30mins (1800 seconds) if the fork count & star count is less than 1k otherwise it's 2hours (7200). Also note that cache is clamped to minimum of 30min and maximum of 24hours
Expand Down
139 changes: 139 additions & 0 deletions src/Card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const { FlexLayout } = require("./utils");
const { getAnimations } = require("./getStyles");

class Card {
constructor({
width = 100,
height = 100,
colors = {},
title = "",
titlePrefixIcon,
}) {
this.width = width;
this.height = height;

this.hideBorder = false;
this.hideTitle = false;

// returns theme based colors with proper overrides and defaults
this.colors = colors;
this.title = title;
this.css = "";

this.paddingX = 25;
this.paddingY = 35;
this.titlePrefixIcon = titlePrefixIcon;
this.animations = true;
}

disableAnimations() {
this.animations = false;
}

setCSS(value) {
this.css = value;
}

setHideBorder(value) {
this.hideBorder = value;
}

setHideTitle(value) {
this.hideTitle = value;
if (value) {
this.height -= 30;
}
}

setTitle(text) {
this.title = text;
}

renderTitle() {
const titleText = `
<text
x="0"
y="0"
class="header"
data-testid="header"
>${this.title}</text>
`;

const prefixIcon = `
<svg
class="icon"
x="0"
y="-13"
viewBox="0 0 16 16"
version="1.1"
width="16"
height="16"
>
${this.titlePrefixIcon}
</svg>
`;
return `
<g
data-testid="card-title"
transform="translate(${this.paddingX}, ${this.paddingY})"
>
${FlexLayout({
items: [this.titlePrefixIcon && prefixIcon, titleText],
gap: 25,
}).join("")}
</g>
`;
}

render(body) {
return `
<svg
width="${this.width}"
height="${this.height}"
viewBox="0 0 ${this.width} ${this.height}"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<style>
.header {
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
fill: ${this.colors.titleColor};
animation: fadeInAnimation 0.8s ease-in-out forwards;
}
${this.css}
${
process.env.NODE_ENV === "test" || !this.animations
? ""
: getAnimations()
}
</style>
<rect
data-testid="card-bg"
x="0.5"
y="0.5"
rx="4.5"
height="99%"
stroke="#E4E2E2"
width="${this.width - 1}"
fill="${this.colors.bgColor}"
stroke-opacity="${this.hideBorder ? 0 : 1}"
/>
${this.hideTitle ? "" : this.renderTitle()}
<g
data-testid="main-card-body"
transform="translate(0, ${
this.hideTitle ? this.paddingX : this.paddingY + 20
})"
>
${body}
</g>
</svg>
`;
}
}

module.exports = Card;
46 changes: 23 additions & 23 deletions src/getStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,36 @@ const calculateCircleProgress = (value) => {
return percentage;
};

const getAnimations = ({ progress }) => {
const getProgressAnimation = ({ progress }) => {
return `
/* Animations */
@keyframes scaleIn {
@keyframes rankAnimation {
from {
transform: translate(-5px, 5px) scale(0);
stroke-dashoffset: ${calculateCircleProgress(0)};
}
to {
transform: translate(-5px, 5px) scale(1);
stroke-dashoffset: ${calculateCircleProgress(progress)};
}
}
@keyframes fadeIn {
`;
};

const getAnimations = () => {
return `
/* Animations */
@keyframes scaleInAnimation {
from {
opacity: 0;
transform: translate(-5px, 5px) scale(0);
}
to {
opacity: 1;
transform: translate(-5px, 5px) scale(1);
}
}
@keyframes rankAnimation {
@keyframes fadeInAnimation {
from {
stroke-dashoffset: ${calculateCircleProgress(0)};
opacity: 0;
}
to {
stroke-dashoffset: ${calculateCircleProgress(progress)};
opacity: 1;
}
}
`;
Expand All @@ -47,20 +52,16 @@ const getStyles = ({
progress,
}) => {
return `
.header {
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${titleColor};
animation: fadeIn 0.8s ease-in-out forwards;
}
.stat {
.stat {
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
}
.stagger {
.stagger {
opacity: 0;
animation: fadeIn 0.3s ease-in-out forwards;
animation: fadeInAnimation 0.3s ease-in-out forwards;
}
.rank-text {
.rank-text {
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
animation: scaleIn 0.3s ease-in-out forwards;
animation: scaleInAnimation 0.3s ease-in-out forwards;
}
.bold { font-weight: 700 }
Expand All @@ -86,9 +87,8 @@ const getStyles = ({
transform: rotate(-90deg);
animation: rankAnimation 1s forwards ease-in-out;
}
${process.env.NODE_ENV === "test" ? "" : getAnimations({ progress })}
${process.env.NODE_ENV === "test" ? "" : getProgressAnimation({ progress })}
`;
};

module.exports = getStyles;
module.exports = { getStyles, getAnimations };
Loading

0 comments on commit 3b0f1b1

Please sign in to comment.