From e088a16151c28083974e2940283a8a34be3e9c88 Mon Sep 17 00:00:00 2001 From: Maruf Khan Date: Thu, 24 Jun 2021 23:03:12 +0600 Subject: [PATCH 1/4] chore(translation): added Bengali language (bn) to the stat card. (#1157) --- src/translations.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/translations.js b/src/translations.js index 490dc5603cb2d..7f3a0f1f7dff5 100644 --- a/src/translations.js +++ b/src/translations.js @@ -9,6 +9,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: `GitHub statistiky uživatele ${encodedName}`, de: `${encodedName + apostrophe} GitHub-Statistiken`, en: `${encodedName}'${apostrophe} GitHub Stats`, + bn: `${encodedName} এর GitHub পরিসংখ্যান`, es: `Estadísticas de GitHub de ${encodedName}`, fr: `Statistiques GitHub de ${encodedName}`, hu: `${encodedName} GitHub statisztika`, @@ -34,6 +35,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: "Celkem hvězd", de: "Sterne Insgesamt", en: "Total Stars", + bn: "সর্বমোট Stars", es: "Estrellas totales", fr: "Total d'étoiles", hu: "Csillagok", @@ -59,6 +61,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: "Celkem commitů", de: "Anzahl Commits", en: "Total Commits", + bn: "সর্বমোট Commits", es: "Commits totales", fr: "Total des validations", hu: "Összes commit", @@ -84,6 +87,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: "Celkem PRs", de: "PRs Insgesamt", en: "Total PRs", + bn: "সর্বমোট PRs", es: "PRs totales", fr: "Total des PR", hu: "Összes PR", @@ -109,6 +113,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: "Celkem problémů", de: "Anzahl Issues", en: "Total Issues", + bn: "সর্বমোট Issues", es: "Issues totales", fr: "Nombre total d'incidents", hu: "Összes hibajegy", @@ -134,6 +139,7 @@ const statCardLocales = ({ name, apostrophe }) => { cs: "Přispěl k", de: "Beigetragen zu", en: "Contributed to", + bn: "অবদান রেখেছেন", es: "Contribuciones en", fr: "Contribué à", hu: "Hozzájárulások", From dfecef5c34adc188c45d7e298939309121955987 Mon Sep 17 00:00:00 2001 From: JacobLinCool Date: Fri, 25 Jun 2021 01:04:13 +0800 Subject: [PATCH 2/4] fix: return "" instead of return undefined (#1133) the function renderGradient may return undefined if colors.bgColor !== "object" which may render "undefined" into svg --- src/common/Card.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Card.js b/src/common/Card.js index 3b5686e668805..520560f94d24d 100644 --- a/src/common/Card.js +++ b/src/common/Card.js @@ -94,7 +94,7 @@ class Card { } renderGradient() { - if (typeof this.colors.bgColor !== "object") return; + if (typeof this.colors.bgColor !== "object") return ""; const gradients = this.colors.bgColor.slice(1); return typeof this.colors.bgColor === "object" From 99aea7f8034abba5dd2817fc863458fbbed8ae1a Mon Sep 17 00:00:00 2001 From: Anurag Date: Thu, 24 Jun 2021 22:43:24 +0530 Subject: [PATCH 3/4] test: fixed snapshot tests --- tests/__snapshots__/renderWakatimeCard.test.js.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap index 4c478d5881cd2..c46f950c40dfe 100644 --- a/tests/__snapshots__/renderWakatimeCard.test.js.snap +++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap @@ -61,7 +61,7 @@ exports[`Test Render Wakatime Card should render correctly 1`] = ` - undefined + - undefined + Date: Sun, 11 Jul 2021 19:28:06 +0530 Subject: [PATCH 4/4] refactor: language card renderer refactor (#1184) * refactor: language card render refactor * chore: change error msg --- api/top-langs.js | 2 +- src/cards/top-languages-card.js | 245 ++++++++++++++++++------------- tests/renderTopLanguages.test.js | 25 ++-- 3 files changed, 158 insertions(+), 114 deletions(-) diff --git a/api/top-langs.js b/api/top-langs.js index f529e311f4ab8..89306fa257f5e 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -40,7 +40,7 @@ module.exports = async (req, res) => { } if (locale && !isLocaleAvailable(locale)) { - return res.send(renderError("Something went wrong", "Language not found")); + return res.send(renderError("Something went wrong", "Locale not found")); } try { diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js index 36b4b0cfe9014..f281b12567239 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -4,6 +4,13 @@ const { langCardLocales } = require("../translations"); const { createProgressNode } = require("../common/createProgressNode"); const { clampValue, getCardColors, flexLayout } = require("../common/utils"); +const DEFAULT_CARD_WIDTH = 300; +const DEFAULT_LANGS_COUNT = 5; +const DEFAULT_LANG_COLOR = "#858585"; +const CARD_PADDING = 25; + +const lowercaseTrim = (name) => name.toLowerCase().trim(); + const createProgressTextNode = ({ width, color, name, progress }) => { const paddingRight = 95; const progressTextX = width - paddingRight + 10; @@ -58,35 +65,99 @@ const createLanguageTextNode = ({ langs, totalSize, x, y }) => { }); }; -const lowercaseTrim = (name) => name.toLowerCase().trim(); +/** + * + * @param {any[]} langs + * @param {number} width + * @param {number} totalLanguageSize + * @returns {string} + */ +const renderNormalLayout = (langs, width, totalLanguageSize) => { + return flexLayout({ + items: langs.map((lang) => { + return createProgressTextNode({ + width: width, + name: lang.name, + color: lang.color || DEFAULT_LANG_COLOR, + progress: ((lang.size / totalLanguageSize) * 100).toFixed(2), + }); + }), + gap: 40, + direction: "column", + }).join(""); +}; -const renderTopLanguages = (topLangs, options = {}) => { - const { - hide_title, - hide_border, - card_width, - title_color, - text_color, - bg_color, - hide, - theme, - layout, - custom_title, - locale, - langs_count = 5, - border_radius, - border_color, - } = options; +/** + * + * @param {any[]} langs + * @param {number} width + * @param {number} totalLanguageSize + * @returns {string} + */ +const renderCompactLayout = (langs, width, totalLanguageSize) => { + const paddingRight = 50; + const offsetWidth = width - paddingRight; + // progressOffset holds the previous language's width and used to offset the next language + // so that we can stack them one after another, like this: [--][----][---] + let progressOffset = 0; + const compactProgressBar = langs + .map((lang) => { + const percentage = parseFloat( + ((lang.size / totalLanguageSize) * offsetWidth).toFixed(2), + ); - const i18n = new I18n({ - locale, - translations: langCardLocales, - }); + const progress = percentage < 10 ? percentage + 10 : percentage; + + const output = ` + + `; + progressOffset += percentage; + return output; + }) + .join(""); + + return ` + + + + ${compactProgressBar} + ${createLanguageTextNode({ + x: 0, + y: 25, + langs, + totalSize: totalLanguageSize, + }).join("")} + `; +}; + +/** + * @param {number} totalLangs + * @returns {number} + */ +const calculateCompactLayoutHeight = (totalLangs) => { + return 90 + Math.round(totalLangs / 2) * 25; +}; +/** + * @param {number} totalLangs + * @returns {number} + */ +const calculateNormalLayoutHeight = (totalLangs) => { + return 45 + (totalLangs + 1) * 40; +}; + +const useLanguages = (topLangs, hide, langs_count) => { let langs = Object.values(topLangs); let langsToHide = {}; - - langsCount = clampValue(parseInt(langs_count), 1, 10); + let langsCount = clampValue(parseInt(langs_count), 1, 10); // populate langsToHide map for quick lookup // while filtering out @@ -104,110 +175,80 @@ const renderTopLanguages = (topLangs, options = {}) => { }) .slice(0, langsCount); - const totalLanguageSize = langs.reduce((acc, curr) => { - return acc + curr.size; - }, 0); + const totalLanguageSize = langs.reduce((acc, curr) => acc + curr.size, 0); - // returns theme based colors with proper overrides and defaults - const { titleColor, textColor, bgColor, borderColor } = getCardColors({ + return { langs, totalLanguageSize }; +}; + +const renderTopLanguages = (topLangs, options = {}) => { + const { + hide_title, + hide_border, + card_width, title_color, text_color, bg_color, - border_color, + hide, theme, + layout, + custom_title, + locale, + langs_count = DEFAULT_LANGS_COUNT, + border_radius, + border_color, + } = options; + + const i18n = new I18n({ + locale, + translations: langCardLocales, }); - let width = isNaN(card_width) ? 300 : card_width; - let height = 45 + (langs.length + 1) * 40; + const { langs, totalLanguageSize } = useLanguages( + topLangs, + hide, + langs_count, + ); - let finalLayout = ""; + let width = isNaN(card_width) ? DEFAULT_CARD_WIDTH : card_width; + let height = calculateNormalLayoutHeight(langs.length); - // RENDER COMPACT LAYOUT + let finalLayout = ""; if (layout === "compact") { - width = width + 50; - height = 90 + Math.round(langs.length / 2) * 25; - - // progressOffset holds the previous language's width and used to offset the next language - // so that we can stack them one after another, like this: [--][----][---] - let progressOffset = 0; - const compactProgressBar = langs - .map((lang) => { - const percentage = ( - (lang.size / totalLanguageSize) * - (width - 50) - ).toFixed(2); - - const progress = - percentage < 10 ? parseFloat(percentage) + 10 : percentage; - - const output = ` - - `; - progressOffset += parseFloat(percentage); - return output; - }) - .join(""); - - finalLayout = ` - - - - ${compactProgressBar} - ${createLanguageTextNode({ - x: 0, - y: 25, - langs, - totalSize: totalLanguageSize, - }).join("")} - `; + width = width + 50; // padding + height = calculateCompactLayoutHeight(langs.length); + + finalLayout = renderCompactLayout(langs, width, totalLanguageSize); } else { - finalLayout = flexLayout({ - items: langs.map((lang) => { - return createProgressTextNode({ - width: width, - name: lang.name, - color: lang.color || "#858585", - progress: ((lang.size / totalLanguageSize) * 100).toFixed(2), - }); - }), - gap: 40, - direction: "column", - }).join(""); + finalLayout = renderNormalLayout(langs, width, totalLanguageSize); } + // returns theme based colors with proper overrides and defaults + const colors = getCardColors({ + title_color, + text_color, + bg_color, + border_color, + theme, + }); + const card = new Card({ customTitle: custom_title, defaultTitle: i18n.t("langcard.title"), width, height, border_radius, - colors: { - titleColor, - textColor, - bgColor, - borderColor, - }, + colors, }); card.disableAnimations(); card.setHideBorder(hide_border); card.setHideTitle(hide_title); - card.setCSS(` - .lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} } - `); + card.setCSS( + `.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`, + ); return card.render(` - + ${finalLayout} `); diff --git a/tests/renderTopLanguages.test.js b/tests/renderTopLanguages.test.js index 7934215c0a3e1..66946ce56e1c8 100644 --- a/tests/renderTopLanguages.test.js +++ b/tests/renderTopLanguages.test.js @@ -198,7 +198,7 @@ describe("Test renderTopLanguages", () => { ); expect(queryAllByTestId(document.body, "lang-progress")[0]).toHaveAttribute( "width", - "120.00", + "120", ); expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent( @@ -206,7 +206,7 @@ describe("Test renderTopLanguages", () => { ); expect(queryAllByTestId(document.body, "lang-progress")[1]).toHaveAttribute( "width", - "120.00", + "120", ); expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent( @@ -214,7 +214,7 @@ describe("Test renderTopLanguages", () => { ); expect(queryAllByTestId(document.body, "lang-progress")[2]).toHaveAttribute( "width", - "60.00", + "60", ); }); @@ -228,25 +228,28 @@ describe("Test renderTopLanguages", () => { it("should render without rounding", () => { document.body.innerHTML = renderTopLanguages(langs, { border_radius: "0" }); expect(document.querySelector("rect")).toHaveAttribute("rx", "0"); - document.body.innerHTML = renderTopLanguages(langs, { }); + document.body.innerHTML = renderTopLanguages(langs, {}); expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5"); }); it("should render langs with specified langs_count", async () => { options = { - langs_count: 1 - } + langs_count: 1, + }; document.body.innerHTML = renderTopLanguages(langs, { ...options }); - expect(queryAllByTestId(document.body, "lang-name").length).toBe(options.langs_count) + expect(queryAllByTestId(document.body, "lang-name").length).toBe( + options.langs_count, + ); }); it("should render langs with specified langs_count even when hide is set", async () => { options = { hide: ["HTML"], - langs_count: 2 - } + langs_count: 2, + }; document.body.innerHTML = renderTopLanguages(langs, { ...options }); - expect(queryAllByTestId(document.body, "lang-name").length).toBe(options.langs_count) + expect(queryAllByTestId(document.body, "lang-name").length).toBe( + options.langs_count, + ); }); - });