diff --git a/api/top-langs.js b/api/top-langs.js index d183d3b455ca0..19cccb894e33a 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -29,6 +29,7 @@ export default async (req, res) => { locale, border_radius, border_color, + disable_animations, } = req.query; res.setHeader("Content-Type", "image/svg+xml"); @@ -75,6 +76,7 @@ export default async (req, res) => { border_radius, border_color, locale: locale ? locale.toLowerCase() : null, + disable_animations: parseBoolean(disable_animations), }), ); } catch (err) { diff --git a/readme.md b/readme.md index bfe042fcc2032..716bda22758c6 100644 --- a/readme.md +++ b/readme.md @@ -304,6 +304,7 @@ You can provide multiple comma-separated values in the bg_color option to render - `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`. - `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`. - `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`. +- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`. > **Warning** > Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh index 4a035db3041a0..1ab5de474ea5a 100755 --- a/scripts/push-theme-readme.sh +++ b/scripts/push-theme-readme.sh @@ -9,6 +9,6 @@ git config --global user.name "GitHub Readme Stats Bot" git branch -d $BRANCH_NAME || true git checkout -b $BRANCH_NAME git add --all -git commit --message "docs(theme): Auto update theme readme" || exit 0 +git commit --no-verify --message "docs(theme): Auto update theme readme" git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js index 602d1b811b5df..9396ff8e73d5e 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -39,46 +39,53 @@ const getLongestLang = (arr) => * Creates a node to display usage of a programming language in percentage * using text and a horizontal progress bar. * - * @param {object[]} props Function properties. + * @param {object} props Function properties. * @param {number} props.width The card width * @param {string} props.name Name of the programming language. * @param {string} props.color Color of the programming language. * @param {string} props.progress Usage of the programming language in percentage. + * @param {number} props.index Index of the programming language. * @returns {string} Programming language SVG node. */ -const createProgressTextNode = ({ width, color, name, progress }) => { +const createProgressTextNode = ({ width, color, name, progress, index }) => { + const staggerDelay = (index + 3) * 150; const paddingRight = 95; const progressTextX = width - paddingRight + 10; const progressWidth = width - paddingRight; return ` - ${name} - ${progress}% - ${createProgressNode({ - x: 0, - y: 25, - color, - width: progressWidth, - progress, - progressBarBackgroundColor: "#ddd", - })} + + ${name} + ${progress}% + ${createProgressNode({ + x: 0, + y: 25, + color, + width: progressWidth, + progress, + progressBarBackgroundColor: "#ddd", + delay: staggerDelay + 300, + })} + `; }; /** * Creates a text only node to display usage of a programming language in percentage. * - * @param {object[]} props Function properties. + * @param {object} props Function properties. * @param {Lang} props.lang Programming language object. * @param {number} props.totalSize Total size of all languages. + * @param {number} props.index Index of the programming language. * @returns {string} Compact layout programming language SVG node. */ -const createCompactLangNode = ({ lang, totalSize }) => { +const createCompactLangNode = ({ lang, totalSize, index }) => { const percentage = ((lang.size / totalSize) * 100).toFixed(2); + const staggerDelay = (index + 3) * 150; const color = lang.color || "#858585"; return ` - + ${lang.name} ${percentage}% @@ -104,7 +111,6 @@ const createLanguageTextNode = ({ langs, totalSize }) => { createCompactLangNode({ lang, totalSize, - // @ts-ignore index, }), ); @@ -134,12 +140,13 @@ const createLanguageTextNode = ({ langs, totalSize }) => { */ const renderNormalLayout = (langs, width, totalLanguageSize) => { return flexLayout({ - items: langs.map((lang) => { + items: langs.map((lang, index) => { return createProgressTextNode({ - width: width, + width, name: lang.name, color: lang.color || DEFAULT_LANG_COLOR, progress: ((lang.size / totalLanguageSize) * 100).toFixed(2), + index, }); }), gap: 40, @@ -187,7 +194,7 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => { return ` - + ${compactProgressBar} @@ -276,6 +283,7 @@ const renderTopLanguages = (topLangs, options = {}) => { langs_count = DEFAULT_LANGS_COUNT, border_radius, border_color, + disable_animations, } = options; const i18n = new I18n({ @@ -324,11 +332,43 @@ const renderTopLanguages = (topLangs, options = {}) => { colors, }); - card.disableAnimations(); + if (disable_animations) card.disableAnimations(); + card.setHideBorder(hide_border); card.setHideTitle(hide_title); card.setCSS( - `.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`, + ` + @keyframes slideInAnimation { + from { + width: 0; + } + to { + width: calc(100%-100px); + } + } + @keyframes growWidthAnimation { + from { + width: 0; + } + to { + width: 100%; + } + } + .lang-name { + font: 400 11px "Segoe UI", Ubuntu, Sans-Serif; + fill: ${colors.textColor}; + } + .stagger { + opacity: 0; + animation: fadeInAnimation 0.3s ease-in-out forwards; + } + #rect-mask rect{ + animation: slideInAnimation 1s ease-in-out forwards; + } + .lang-progress{ + animation: growWidthAnimation 0.6s ease-in-out forwards; + } + `, ); return card.render(` diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts index 502314c41fa92..c5945d48be71e 100644 --- a/src/cards/types.d.ts +++ b/src/cards/types.d.ts @@ -37,6 +37,7 @@ export type TopLangOptions = CommonOptions & { layout: "compact" | "normal"; custom_title: string; langs_count: number; + disable_animations: boolean; }; type WakaTimeOptions = CommonOptions & { diff --git a/src/common/createProgressNode.js b/src/common/createProgressNode.js index c36818b193b2f..2825583c7406a 100644 --- a/src/common/createProgressNode.js +++ b/src/common/createProgressNode.js @@ -10,6 +10,7 @@ import { clampValue } from "./utils.js"; * @param {string} createProgressNodeParams.color Progress color. * @param {string} createProgressNodeParams.progress Progress value. * @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color. + * @param {number} createProgressNodeParams.delay Delay before animation starts. * @returns {string} Progress node. */ const createProgressNode = ({ @@ -19,20 +20,22 @@ const createProgressNode = ({ color, progress, progressBarBackgroundColor, + delay, }) => { const progressPercentage = clampValue(progress, 2, 100); return ` - - + + + `; }; diff --git a/src/common/retryer.js b/src/common/retryer.js index 73833ef85b3a4..5351cbe8cf99a 100644 --- a/src/common/retryer.js +++ b/src/common/retryer.js @@ -45,7 +45,9 @@ const retryer = async (fetcher, variables, retries = 0) => { // prettier-ignore // also checking for bad credentials if any tokens gets invalidated const isBadCredential = err.response.data && err.response.data.message === "Bad credentials"; - const isAccountSuspended = err.response.data && err.response.data.message === "Sorry. Your account was suspended."; + const isAccountSuspended = + err.response.data && + err.response.data.message === "Sorry. Your account was suspended."; if (isBadCredential || isAccountSuspended) { logger.log(`PAT_${retries + 1} Failed`);