From 7a4c452dbb841f05301d7a3f318f1d54bcf7006f Mon Sep 17 00:00:00 2001 From: Alexandr Garbuzov Date: Mon, 20 Nov 2023 20:08:48 +0200 Subject: [PATCH] feat(repo card): add description lines count query parameter (#3453) * feature(repo card): add description lines count query parameter * dev * dev * docs * test --- api/pin.js | 2 ++ readme.md | 1 + src/cards/repo-card.js | 21 ++++++++++++++++++--- src/cards/types.d.ts | 1 + tests/renderRepoCard.test.js | 30 ++++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/api/pin.js b/api/pin.js index c67df29abffe39..0bc029d7ffda3d 100644 --- a/api/pin.js +++ b/api/pin.js @@ -24,6 +24,7 @@ export default async (req, res) => { locale, border_radius, border_color, + description_lines_count, } = req.query; res.setHeader("Content-Type", "image/svg+xml"); @@ -96,6 +97,7 @@ export default async (req, res) => { border_color, show_owner: parseBoolean(show_owner), locale: locale ? locale.toLowerCase() : null, + description_lines_count, }), ); } catch (err) { diff --git a/readme.md b/readme.md index a176615907983b..0f1067166cd911 100644 --- a/readme.md +++ b/readme.md @@ -386,6 +386,7 @@ If we don't support your language, please consider contributing! You can find mo #### Repo Card Exclusive Options * `show_owner` - Shows the repo's owner name *(boolean)*. Default: `false`. +* `description_lines_count` - Manually set the number of lines for the description *(number)*. Specified value will be clamped between 1 and 3. If this parameter is not specified, the number of lines will be automatically adjusted according to the actual length of the description. Default: `undefined`. #### Gist Card Exclusive Options diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js index 0d32475ff5a381..bbfda52d477789 100644 --- a/src/cards/repo-card.js +++ b/src/cards/repo-card.js @@ -12,10 +12,13 @@ import { wrapTextMultiline, iconWithLabel, createLanguageNode, + clampValue, } from "../common/utils.js"; import { repoCardLocales } from "../translations.js"; const ICON_SIZE = 16; +const DESCRIPTION_LINE_WIDTH = 59; +const DESCRIPTION_MAX_LINES = 3; /** * Retrieves the repository description and wraps it to fit the card width. @@ -73,22 +76,34 @@ const renderRepoCard = (repo, options = {}) => { border_radius, border_color, locale, + description_lines_count, } = options; const lineHeight = 10; const header = show_owner ? nameWithOwner : name; const langName = (primaryLanguage && primaryLanguage.name) || "Unspecified"; const langColor = (primaryLanguage && primaryLanguage.color) || "#333"; + const descriptionMaxLines = description_lines_count + ? clampValue(description_lines_count, 1, DESCRIPTION_MAX_LINES) + : DESCRIPTION_MAX_LINES; const desc = parseEmojis(description || "No description provided"); - const multiLineDescription = wrapTextMultiline(desc); - const descriptionLines = multiLineDescription.length; + const multiLineDescription = wrapTextMultiline( + desc, + DESCRIPTION_LINE_WIDTH, + descriptionMaxLines, + ); + const descriptionLinesCount = description_lines_count + ? clampValue(description_lines_count, 1, DESCRIPTION_MAX_LINES) + : multiLineDescription.length; + const descriptionSvg = multiLineDescription .map((line) => `${encodeHTML(line)}`) .join(""); const height = - (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight; + (descriptionLinesCount > 1 ? 120 : 110) + + descriptionLinesCount * lineHeight; const i18n = new I18n({ locale, diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts index dce964d21af7e5..d55d1c6e552ffc 100644 --- a/src/cards/types.d.ts +++ b/src/cards/types.d.ts @@ -32,6 +32,7 @@ export type StatCardOptions = CommonOptions & { export type RepoCardOptions = CommonOptions & { show_owner: boolean; + description_lines_count: number; }; export type TopLangOptions = CommonOptions & { diff --git a/tests/renderRepoCard.test.js b/tests/renderRepoCard.test.js index 050e7109490bba..abbad4dbe2a3b7 100644 --- a/tests/renderRepoCard.test.js +++ b/tests/renderRepoCard.test.js @@ -339,4 +339,34 @@ describe("Test renderRepoCard", () => { "No description provided", ); }); + + it("should have correct height with specified `description_lines_count` parameter", () => { + // Testing short description + document.body.innerHTML = renderRepoCard(data_repo.repository, { + description_lines_count: 1, + }); + expect(document.querySelector("svg")).toHaveAttribute("height", "120"); + document.body.innerHTML = renderRepoCard(data_repo.repository, { + description_lines_count: 3, + }); + expect(document.querySelector("svg")).toHaveAttribute("height", "150"); + + // Testing long description + const longDescription = + "A tool that will make a lot of iPhone/iPad developers' life easier. It shares your app over-the-air in a WiFi network. Bonjour is used and no configuration is needed."; + document.body.innerHTML = renderRepoCard( + { ...data_repo.repository, description: longDescription }, + { + description_lines_count: 3, + }, + ); + expect(document.querySelector("svg")).toHaveAttribute("height", "150"); + document.body.innerHTML = renderRepoCard( + { ...data_repo.repository, description: longDescription }, + { + description_lines_count: 1, + }, + ); + expect(document.querySelector("svg")).toHaveAttribute("height", "120"); + }); });