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..90fb94f1cae00 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -104,7 +104,7 @@ export default async (req, res) => { `max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${ CONSTANTS.ERROR_CACHE_SECONDS }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`, - ); // Use lower cache period for errors. + ); // Use a lower cache period for errors. return res.send(renderError(err.message, err.secondaryMessage)); } }; 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..a3fa5c79356d4 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -431,7 +431,7 @@ const renderDonutVerticalLayout = (langs, totalLanguageSize) => { circles.push(` - { 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");