Skip to content

Commit 77dcdab

Browse files
Add loading Animation to Most used Language card (anuraghazra#2197)
* add: text animation * compact progress done * cleaned code * non compact animation done * tests fixed + prettier * revert: vercel.json * remove: unnecessary import * added parameter in docs * style: improve syntax Co-authored-by: rickstaa <[email protected]>
1 parent 227711c commit 77dcdab

File tree

5 files changed

+76
-29
lines changed

5 files changed

+76
-29
lines changed

api/top-langs.js

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default async (req, res) => {
2929
locale,
3030
border_radius,
3131
border_color,
32+
disable_animations,
3233
} = req.query;
3334
res.setHeader("Content-Type", "image/svg+xml");
3435

@@ -75,6 +76,7 @@ export default async (req, res) => {
7576
border_radius,
7677
border_color,
7778
locale: locale ? locale.toLowerCase() : null,
79+
disable_animations: parseBoolean(disable_animations),
7880
}),
7981
);
8082
} catch (err) {

readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ You can provide multiple comma-separated values in the bg_color option to render
304304
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
305305
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
306306
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
307+
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
307308

308309
> **Warning**
309310
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)

src/cards/top-languages-card.js

+61-21
Original file line numberDiff line numberDiff line change
@@ -39,46 +39,53 @@ const getLongestLang = (arr) =>
3939
* Creates a node to display usage of a programming language in percentage
4040
* using text and a horizontal progress bar.
4141
*
42-
* @param {object[]} props Function properties.
42+
* @param {object} props Function properties.
4343
* @param {number} props.width The card width
4444
* @param {string} props.name Name of the programming language.
4545
* @param {string} props.color Color of the programming language.
4646
* @param {string} props.progress Usage of the programming language in percentage.
47+
* @param {number} props.index Index of the programming language.
4748
* @returns {string} Programming language SVG node.
4849
*/
49-
const createProgressTextNode = ({ width, color, name, progress }) => {
50+
const createProgressTextNode = ({ width, color, name, progress, index }) => {
51+
const staggerDelay = (index + 3) * 150;
5052
const paddingRight = 95;
5153
const progressTextX = width - paddingRight + 10;
5254
const progressWidth = width - paddingRight;
5355

5456
return `
55-
<text data-testid="lang-name" x="2" y="15" class="lang-name">${name}</text>
56-
<text x="${progressTextX}" y="34" class="lang-name">${progress}%</text>
57-
${createProgressNode({
58-
x: 0,
59-
y: 25,
60-
color,
61-
width: progressWidth,
62-
progress,
63-
progressBarBackgroundColor: "#ddd",
64-
})}
57+
<g class="stagger" style="animation-delay: ${staggerDelay}ms">
58+
<text data-testid="lang-name" x="2" y="15" class="lang-name">${name}</text>
59+
<text x="${progressTextX}" y="34" class="lang-name">${progress}%</text>
60+
${createProgressNode({
61+
x: 0,
62+
y: 25,
63+
color,
64+
width: progressWidth,
65+
progress,
66+
progressBarBackgroundColor: "#ddd",
67+
delay: staggerDelay + 300,
68+
})}
69+
</g>
6570
`;
6671
};
6772

6873
/**
6974
* Creates a text only node to display usage of a programming language in percentage.
7075
*
71-
* @param {object[]} props Function properties.
76+
* @param {object} props Function properties.
7277
* @param {Lang} props.lang Programming language object.
7378
* @param {number} props.totalSize Total size of all languages.
79+
* @param {number} props.index Index of the programming language.
7480
* @returns {string} Compact layout programming language SVG node.
7581
*/
76-
const createCompactLangNode = ({ lang, totalSize }) => {
82+
const createCompactLangNode = ({ lang, totalSize, index }) => {
7783
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
84+
const staggerDelay = (index + 3) * 150;
7885
const color = lang.color || "#858585";
7986

8087
return `
81-
<g>
88+
<g class="stagger" style="animation-delay: ${staggerDelay}ms">
8289
<circle cx="5" cy="6" r="5" fill="${color}" />
8390
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
8491
${lang.name} ${percentage}%
@@ -104,7 +111,6 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
104111
createCompactLangNode({
105112
lang,
106113
totalSize,
107-
// @ts-ignore
108114
index,
109115
}),
110116
);
@@ -134,12 +140,13 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
134140
*/
135141
const renderNormalLayout = (langs, width, totalLanguageSize) => {
136142
return flexLayout({
137-
items: langs.map((lang) => {
143+
items: langs.map((lang, index) => {
138144
return createProgressTextNode({
139-
width: width,
145+
width,
140146
name: lang.name,
141147
color: lang.color || DEFAULT_LANG_COLOR,
142148
progress: ((lang.size / totalLanguageSize) * 100).toFixed(2),
149+
index,
143150
});
144151
}),
145152
gap: 40,
@@ -187,7 +194,7 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
187194

188195
return `
189196
<mask id="rect-mask">
190-
<rect x="0" y="0" width="${offsetWidth}" height="8" fill="white" rx="5" />
197+
<rect x="0" y="0" width="${offsetWidth}" height="8" fill="white" rx="5"/>
191198
</mask>
192199
${compactProgressBar}
193200
@@ -276,6 +283,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
276283
langs_count = DEFAULT_LANGS_COUNT,
277284
border_radius,
278285
border_color,
286+
disable_animations,
279287
} = options;
280288

281289
const i18n = new I18n({
@@ -324,11 +332,43 @@ const renderTopLanguages = (topLangs, options = {}) => {
324332
colors,
325333
});
326334

327-
card.disableAnimations();
335+
if (disable_animations) card.disableAnimations();
336+
328337
card.setHideBorder(hide_border);
329338
card.setHideTitle(hide_title);
330339
card.setCSS(
331-
`.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`,
340+
`
341+
@keyframes slideInAnimation {
342+
from {
343+
width: 0;
344+
}
345+
to {
346+
width: calc(100%-100px);
347+
}
348+
}
349+
@keyframes growWidthAnimation {
350+
from {
351+
width: 0;
352+
}
353+
to {
354+
width: 100%;
355+
}
356+
}
357+
.lang-name {
358+
font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
359+
fill: ${colors.textColor};
360+
}
361+
.stagger {
362+
opacity: 0;
363+
animation: fadeInAnimation 0.3s ease-in-out forwards;
364+
}
365+
#rect-mask rect{
366+
animation: slideInAnimation 1s ease-in-out forwards;
367+
}
368+
.lang-progress{
369+
animation: growWidthAnimation 0.6s ease-in-out forwards;
370+
}
371+
`,
332372
);
333373

334374
return card.render(`

src/cards/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export type TopLangOptions = CommonOptions & {
3737
layout: "compact" | "normal";
3838
custom_title: string;
3939
langs_count: number;
40+
disable_animations: boolean;
4041
};
4142

4243
type WakaTimeOptions = CommonOptions & {

src/common/createProgressNode.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { clampValue } from "./utils.js";
1010
* @param {string} createProgressNodeParams.color Progress color.
1111
* @param {string} createProgressNodeParams.progress Progress value.
1212
* @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color.
13+
* @param {number} createProgressNodeParams.delay Delay before animation starts.
1314
* @returns {string} Progress node.
1415
*/
1516
const createProgressNode = ({
@@ -19,20 +20,22 @@ const createProgressNode = ({
1920
color,
2021
progress,
2122
progressBarBackgroundColor,
23+
delay,
2224
}) => {
2325
const progressPercentage = clampValue(progress, 2, 100);
2426

2527
return `
2628
<svg width="${width}" x="${x}" y="${y}">
2729
<rect rx="5" ry="5" x="0" y="0" width="${width}" height="8" fill="${progressBarBackgroundColor}"></rect>
28-
<rect
29-
height="8"
30-
fill="${color}"
31-
rx="5" ry="5" x="0" y="0"
32-
data-testid="lang-progress"
33-
width="${progressPercentage}%"
34-
>
35-
</rect>
30+
<svg data-testid="lang-progress" width="${progressPercentage}%">
31+
<rect
32+
height="8"
33+
fill="${color}"
34+
rx="5" ry="5" x="0" y="0"
35+
class="lang-progress"
36+
style="animation-delay: ${delay}ms;"
37+
/>
38+
</svg>
3639
</svg>
3740
`;
3841
};

0 commit comments

Comments
 (0)