diff --git a/api/pin.js b/api/pin.js
index 21ecf966b3ff4..4002e6c6ca5ce 100644
--- a/api/pin.js
+++ b/api/pin.js
@@ -24,6 +24,7 @@ export default async (req, res) => {
locale,
border_radius,
border_color,
+ card_width,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -80,6 +81,7 @@ export default async (req, res) => {
border_color,
show_owner: parseBoolean(show_owner),
locale: locale ? locale.toLowerCase() : null,
+ card_width: parseInt(card_width, 10),
}),
);
} catch (err) {
diff --git a/api/top-langs.js b/api/top-langs.js
index d9bf6b09da01a..a319666824c5f 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -33,9 +33,9 @@ export default async (req, res) => {
border_color,
disable_animations,
hide_progress,
+ progress_bar_bg_color,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
-
if (blacklist.includes(username)) {
return res.send(renderError("Something went wrong"));
}
@@ -96,6 +96,7 @@ export default async (req, res) => {
locale: locale ? locale.toLowerCase() : null,
disable_animations: parseBoolean(disable_animations),
hide_progress: parseBoolean(hide_progress),
+ progress_bar_bg_color,
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index ff826b3f6e863..7f9d93a763570 100644
--- a/readme.md
+++ b/readme.md
@@ -366,7 +366,8 @@ If we don't support your language, please consider contributing!
* `hide` - Hides the [specified items](#hiding-individual-stats) from stats *(Comma-separated values)*. Default: `[] (blank array)`.
* `hide_title` - *(boolean)*. Default: `false`.
-* `card_width` - Sets the card's width manually *(number)*. Default: `500px (approx.)`.
+* `card_width` - Sets the card's width manually *(number)*. Default: `287px`.
+* `card_min_width` - Sets the minimum card's width *(number)*. Default: `287px`.
* `hide_rank` - *(boolean)* hides the rank and automatically resizes the card width. Default: `false`.
* `rank_icon` - Shows alternative rank icon (i.e. `github`, `percentile` or `default`). Default: `default`.
* `show_icons` - *(boolean)*. Default: `false`.
@@ -386,6 +387,24 @@ If we don't support your language, please consider contributing!
#### Repo Card Exclusive Options
* `show_owner` - Shows the repo's owner name *(boolean)*. Default: `false`.
+* `icon_size` - Sets the icon size manually *(number)*. Default: `16px`.
+* `getBadgeSVG` - Retrieves the repository description and wraps it to fit the card width.
+* `renderRepoCard` * Renders repository card details (i.e. `name`,`nameWithOwner`,`description`,`primaryLanguage`,`isArchived`,`isTemplate`,`starCount`). Default: `default`.
+* `lineheight` - Sets line height manually *(number)*.Default:16.
+* `header` - Shows header with `showOwner` and `namewithOwner` .
+* `langName` - Stores the name of the primary programming language used in the repository.
+* `langColor` - Stores the color associated with the primary programming language used in the repository.
+* `desc` - Stores the description of the GitHub repository. Emojis are parsed within this description.
+* `multiLineDescription` - Stores the description text broken into multiple lines to fit within the card's layout.
+* `descriptionLines` - Represents the number of lines in the description.
+* `descriptionSvg.Number` - Contains SVG text for rendering the repository description on the card.
+* `height` - Represents the height of the GitHub repository card. It is calculated based on the number of lines in the description.
+* `i18n` - Provides internationalization support and translations for the card.
+* `colors` - Contains theme-based colors used for rendering the card, including title color, icon color, text color, background color, and border color.
+* `svgLanguage` - Contains SVG representation of the primary programming language label.
+* `totalStars` - Stores the total number of stars (GitHub repository stargazers) in a human-readable format.
+* `totalForks` - Stores the total number of forks (GitHub repository forks) in a human-readable format.
+* `starAndForkCount` - Contains SVG representation of stars and forks count along with the primary language label.
#### Gist Card Exclusive Options
@@ -396,7 +415,8 @@ If we don't support your language, please consider contributing!
* `hide` - Hides the languages specified from the card *(Comma-separated values)*. Default: `[] (blank array)`.
* `hide_title` - *(boolean)*. Default: `false`.
* `layout` - Switches between five available layouts `normal` & `compact` & `donut` & `donut-vertical` & `pie`. Default: `normal`.
-* `card_width` - Sets the card's width manually *(number)*. Default `300`.
+* `card_width` - Sets the card's width manually *(number)*. Default `300px`.
+* `card_min_width` - Sets the card's minimum width *(number)*.Default `280px`.
* `langs_count` - Shows more languages on the card, between 1-20 *(number)*. Default: `5` for `normal` and `donut`, `6` for other layouts.
* `exclude_repo` - Excludes specified repositories *(Comma-separated values)*. Default: `[] (blank array)`.
* `custom_title` - Sets a custom title for the card *(string)*. Default `Most Used Languages`.
diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js
index 09b5841880a97..a24cc0a36155e 100644
--- a/src/cards/repo-card.js
+++ b/src/cards/repo-card.js
@@ -2,6 +2,7 @@
import { Card } from "../common/Card.js";
import { I18n } from "../common/I18n.js";
import { icons } from "../common/icons.js";
+
import {
encodeHTML,
flexLayout,
@@ -15,7 +16,10 @@ import {
} from "../common/utils.js";
import { repoCardLocales } from "../translations.js";
+const DEFAULT_CARD_WIDTH = 300;
+const MIN_CARD_WIDTH = 400;
const ICON_SIZE = 16;
+const card_height = undefined ;
/**
* Retrieves the repository description and wraps it to fit the card width.
@@ -73,6 +77,8 @@ const renderRepoCard = (repo, options = {}) => {
border_radius,
border_color,
locale,
+ card_width,
+ card_height,
} = options;
const lineHeight = 10;
@@ -87,14 +93,24 @@ const renderRepoCard = (repo, options = {}) => {
.map((line) => `${encodeHTML(line)}`)
.join("");
- const height =
- (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight;
-
const i18n = new I18n({
locale,
translations: repoCardLocales,
});
+ let width = card_width
+ ? isNaN(card_width)
+ ? DEFAULT_CARD_WIDTH
+ : card_width < MIN_CARD_WIDTH
+ ? MIN_CARD_WIDTH
+ : card_width
+ : DEFAULT_CARD_WIDTH;
+ const height =
+ (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight;
+ const height = card_height ?? (
+ (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight
+);
+
// returns theme based colors with proper overrides and defaults
const colors = getCardColors({
title_color,
@@ -137,7 +153,7 @@ const renderRepoCard = (repo, options = {}) => {
const card = new Card({
defaultTitle: header.length > 35 ? `${header.slice(0, 35)}...` : header,
titlePrefixIcon: icons.contribs,
- width: 400,
+ width,
height,
border_radius,
colors,
@@ -175,5 +191,5 @@ const renderRepoCard = (repo, options = {}) => {
`);
};
-export { renderRepoCard };
+export { renderRepoCard, DEFAULT_CARD_WIDTH, MIN_CARD_WIDTH };
export default renderRepoCard;
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index 5f57205602016..a84baaee15ef7 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -541,5 +541,5 @@ const renderStatsCard = (stats, options = {}) => {
`);
};
-export { renderStatsCard };
+export { renderStatsCard, RANK_CARD_DEFAULT_WIDTH, RANK_CARD_MIN_WIDTH };
export default renderStatsCard;
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 758bd34baff5d..65d632de8e99e 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -203,11 +203,19 @@ const trimTopLanguages = (topLangs, langs_count, hide) => {
* @param {number} props.width The card width
* @param {string} props.color Color of the programming language.
* @param {string} props.name Name of the programming language.
+ * @param {string} props.progBgColor Color of the background of progress bar
* @param {number} 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, index }) => {
+const createProgressTextNode = ({
+ width,
+ color,
+ name,
+ progress,
+ index,
+ progBgColor,
+}) => {
const staggerDelay = (index + 3) * 150;
const paddingRight = 95;
const progressTextX = width - paddingRight + 10;
@@ -223,7 +231,9 @@ const createProgressTextNode = ({ width, color, name, progress, index }) => {
color,
width: progressWidth,
progress,
- progressBarBackgroundColor: "#ddd",
+ progressBarBackgroundColor: progBgColor
+ ? `#${progBgColor}`
+ : "#ddd",
delay: staggerDelay + 300,
})}
@@ -322,9 +332,10 @@ const createDonutLanguagesNode = ({ langs, totalSize }) => {
* @param {Lang[]} langs Array of programming languages.
* @param {number} width Card width.
* @param {number} totalLanguageSize Total size of all languages.
+ * @param {string} progBgColor Sets progress bar background color.
* @returns {string} Normal layout card SVG object.
*/
-const renderNormalLayout = (langs, width, totalLanguageSize) => {
+const renderNormalLayout = (langs, width, totalLanguageSize, progBgColor) => {
return flexLayout({
items: langs.map((lang, index) => {
return createProgressTextNode({
@@ -335,6 +346,7 @@ const renderNormalLayout = (langs, width, totalLanguageSize) => {
((lang.size / totalLanguageSize) * 100).toFixed(2),
),
index,
+ progBgColor,
});
}),
gap: 40,
@@ -383,14 +395,14 @@ const renderCompactLayout = (langs, width, totalLanguageSize, hideProgress) => {
return `
${
- hideProgress
- ? ""
- : `
-
-
-
- ${compactProgressBar}
- `
+ !hideProgress
+ ? `
+
+
+
+ ${compactProgressBar}
+ `
+ : ""
}
${createLanguageTextNode({
@@ -738,8 +750,8 @@ const renderTopLanguages = (topLangs, options = {}) => {
border_radius,
border_color,
disable_animations,
+ progBgColor,
} = options;
-
const i18n = new I18n({
locale,
translations: langCardLocales,
@@ -798,7 +810,12 @@ const renderTopLanguages = (topLangs, options = {}) => {
width = width + 50; // padding
finalLayout = renderDonutLayout(langs, width, totalLanguageSize);
} else {
- finalLayout = renderNormalLayout(langs, width, totalLanguageSize);
+ finalLayout = renderNormalLayout(
+ langs,
+ width,
+ totalLanguageSize,
+ progBgColor,
+ );
}
const card = new Card({
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index dce964d21af7e..d2ff21177d02e 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -6,6 +6,7 @@ export type CommonOptions = {
icon_color: string;
text_color: string;
bg_color: string;
+ progress_bar_bg_color:string;
theme: ThemeNames;
border_radius: number;
border_color: string;
@@ -32,6 +33,7 @@ export type StatCardOptions = CommonOptions & {
export type RepoCardOptions = CommonOptions & {
show_owner: boolean;
+ card_width: number;
};
export type TopLangOptions = CommonOptions & {
diff --git a/tests/pin.test.js b/tests/pin.test.js
index 0dcb5aa9768fd..8f09b20dd9593 100644
--- a/tests/pin.test.js
+++ b/tests/pin.test.js
@@ -73,6 +73,7 @@ describe("Test /api/pin", () => {
text_color: "fff",
bg_color: "fff",
full_name: "1",
+ card_width: 100,
},
};
const res = {
diff --git a/tests/renderRepoCard.test.js b/tests/renderRepoCard.test.js
index 61c9bc6da9ac5..e04c3d4d47c20 100644
--- a/tests/renderRepoCard.test.js
+++ b/tests/renderRepoCard.test.js
@@ -1,7 +1,11 @@
import { queryByTestId } from "@testing-library/dom";
import "@testing-library/jest-dom";
import { cssToObject } from "@uppercod/css-to-object";
-import { renderRepoCard } from "../src/cards/repo-card.js";
+import {
+ renderRepoCard,
+ DEFAULT_CARD_WIDTH,
+ MIN_CARD_WIDTH,
+} from "../src/cards/repo-card.js";
import { expect, it, describe } from "@jest/globals";
import { themes } from "../themes/index.js";
@@ -338,4 +342,56 @@ describe("Test renderRepoCard", () => {
"No description provided",
);
});
+
+ it("should render with custom width set", () => {
+ document.body.innerHTML = renderRepoCard({
+ ...data_repo.repository,
+ description: undefined,
+ isArchived: true,
+ });
+
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ DEFAULT_CARD_WIDTH.toString(),
+ );
+
+ document.body.innerHTML = renderRepoCard(
+ {
+ ...data_repo.repository,
+ description: undefined,
+ isArchived: true,
+ },
+ { card_width: 400 },
+ );
+ expect(document.querySelector("svg")).toHaveAttribute("width", "400");
+ });
+
+ it("should render with min width", () => {
+ document.body.innerHTML = renderRepoCard(
+ {
+ ...data_repo.repository,
+ description: undefined,
+ isArchived: true,
+ },
+ { card_width: 190 },
+ );
+
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ MIN_CARD_WIDTH.toString(),
+ );
+
+ document.body.innerHTML = renderRepoCard(
+ {
+ ...data_repo.repository,
+ description: undefined,
+ isArchived: true,
+ },
+ { card_width: 100 },
+ );
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ MIN_CARD_WIDTH.toString(),
+ );
+ });
});
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index abbf2100306d7..2c89a1542fccf 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -4,7 +4,11 @@ import {
queryByTestId,
} from "@testing-library/dom";
import { cssToObject } from "@uppercod/css-to-object";
-import { renderStatsCard } from "../src/cards/stats-card.js";
+import {
+ renderStatsCard,
+ RANK_CARD_DEFAULT_WIDTH,
+ RANK_CARD_MIN_WIDTH,
+} from "../src/cards/stats-card.js";
import { expect, it, describe } from "@jest/globals";
import { CustomError } from "../src/common/utils.js";
@@ -131,7 +135,10 @@ describe("Test renderStatsCard", () => {
it("should render with custom width set", () => {
document.body.innerHTML = renderStatsCard(stats);
- expect(document.querySelector("svg")).toHaveAttribute("width", "450");
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ RANK_CARD_DEFAULT_WIDTH.toString(),
+ );
document.body.innerHTML = renderStatsCard(stats, { card_width: 500 });
expect(document.querySelector("svg")).toHaveAttribute("width", "500");
@@ -139,7 +146,10 @@ describe("Test renderStatsCard", () => {
it("should render with custom width set and limit minimum width", () => {
document.body.innerHTML = renderStatsCard(stats, { card_width: 1 });
- expect(document.querySelector("svg")).toHaveAttribute("width", "420");
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ RANK_CARD_MIN_WIDTH.toString(),
+ );
// Test default minimum card width without rank circle.
document.body.innerHTML = renderStatsCard(stats, {
diff --git a/tests/renderTopLanguagesCard.test.js b/tests/renderTopLanguagesCard.test.js
index 6b7ef62aa30dd..da152c22d1dce 100644
--- a/tests/renderTopLanguagesCard.test.js
+++ b/tests/renderTopLanguagesCard.test.js
@@ -15,6 +15,7 @@ import {
donutCenterTranslation,
trimTopLanguages,
renderTopLanguages,
+ DEFAULT_CARD_WIDTH,
MIN_CARD_WIDTH,
getDefaultLanguagesCountByLayout,
} from "../src/cards/top-languages-card.js";
@@ -428,7 +429,10 @@ describe("Test renderTopLanguages", () => {
it("should render with custom width set", () => {
document.body.innerHTML = renderTopLanguages(langs, {});
- expect(document.querySelector("svg")).toHaveAttribute("width", "300");
+ expect(document.querySelector("svg")).toHaveAttribute(
+ "width",
+ DEFAULT_CARD_WIDTH.toString(),
+ );
document.body.innerHTML = renderTopLanguages(langs, { card_width: 400 });
expect(document.querySelector("svg")).toHaveAttribute("width", "400");