diff --git a/api/index.js b/api/index.js index 34824ba658a1ff..88bd3c2e3e7ead 100644 --- a/api/index.js +++ b/api/index.js @@ -26,6 +26,7 @@ export default async (req, res) => { include_all_commits, line_height, title_color, + ring_color, icon_color, text_color, text_bold, @@ -76,6 +77,7 @@ export default async (req, res) => { include_all_commits: parseBoolean(include_all_commits), line_height, title_color, + ring_color, icon_color, text_color, text_bold: parseBoolean(text_bold), diff --git a/readme.md b/readme.md index e18efc80f73b96..bfe042fcc20323 100644 --- a/readme.md +++ b/readme.md @@ -286,6 +286,7 @@ You can provide multiple comma-separated values in the bg_color option to render - `custom_title` - Sets a custom title for the card. Default: ` GitHub Stats`. - `text_bold` - Use bold text _(boolean)_. Default: `true`. - `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`. +- `ring_color` - Color of the rank circle _(hex color)_. Defaults to the theme ring color if it exists and otherwise the title color. > **Note** > When hide_rank=`true`, the minimum card width is 270 px + the title length and padding. diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index 782ff069674bbb..b078728ea54c33 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -89,6 +89,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => { include_all_commits = false, line_height = 25, title_color, + ring_color, icon_color, text_color, text_bold = true, @@ -104,13 +105,14 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => { const lheight = parseInt(String(line_height), 10); // returns theme based colors with proper overrides and defaults - const { titleColor, textColor, iconColor, bgColor, borderColor } = + const { titleColor, iconColor, textColor, bgColor, borderColor, ringColor } = getCardColors({ title_color, - icon_color, text_color, + icon_color, bg_color, border_color, + ring_color, theme, }); @@ -201,6 +203,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => { const progress = 100 - rank.score; const cssStyles = getStyles({ titleColor, + ringColor, textColor, iconColor, show_icons, diff --git a/src/common/utils.js b/src/common/utils.js index 43c7587fc29322..a0fbf3dabade76 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -133,9 +133,9 @@ function isValidGradient(colors) { * @returns {string | string[]} The gradient or color. */ function fallbackColor(color, fallbackColor) { - let colors = color.split(","); let gradient = null; + let colors = color ? color.split(",") : []; if (colors.length > 1 && isValidGradient(colors)) { gradient = colors; } @@ -207,6 +207,7 @@ function getCardColors({ icon_color, bg_color, border_color, + ring_color, theme, fallbackTheme = "default", }) { @@ -221,6 +222,13 @@ function getCardColors({ title_color || selectedTheme.title_color, "#" + defaultTheme.title_color, ); + + // get the color provided by the user else the theme color + // finally if both colors are invalid we use the titleColor + const ringColor = fallbackColor( + ring_color || selectedTheme.ring_color, + titleColor, + ); const iconColor = fallbackColor( icon_color || selectedTheme.icon_color, "#" + defaultTheme.icon_color, @@ -239,7 +247,7 @@ function getCardColors({ "#" + defaultBorderColor, ); - return { titleColor, iconColor, textColor, bgColor, borderColor }; + return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor }; } /** diff --git a/src/getStyles.js b/src/getStyles.js index 79692e8579035a..f7b90f4adc7b4c 100644 --- a/src/getStyles.js +++ b/src/getStyles.js @@ -77,6 +77,7 @@ const getStyles = ({ titleColor, textColor, iconColor, + ringColor, show_icons, progress, }) => { @@ -105,13 +106,13 @@ const getStyles = ({ } .rank-circle-rim { - stroke: ${titleColor}; + stroke: ${ringColor}; fill: none; stroke-width: 6; opacity: 0.2; } .rank-circle { - stroke: ${titleColor}; + stroke: ${ringColor}; stroke-dasharray: 250; fill: none; stroke-width: 6; diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap index 416ead953e4596..cc6129272f51e6 100644 --- a/tests/__snapshots__/renderWakatimeCard.test.js.snap +++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap @@ -51,13 +51,13 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1 } .rank-circle-rim { - stroke: #2f80ed; + stroke: undefined; fill: none; stroke-width: 6; opacity: 0.2; } .rank-circle { - stroke: #2f80ed; + stroke: undefined; stroke-dasharray: 250; fill: none; stroke-width: 6; diff --git a/tests/api.test.js b/tests/api.test.js index f77a7175b43d7d..e1830858be0636 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -248,4 +248,39 @@ describe("Test /api/", () => { ), ); }); + + it("should allow changing ring_color", async () => { + const { req, res } = faker( + { + username: "anuraghazra", + hide: "issues,prs,contribs", + show_icons: true, + hide_border: true, + line_height: 100, + title_color: "fff", + ring_color: "0000ff", + icon_color: "fff", + text_color: "fff", + bg_color: "fff", + }, + data, + ); + + await api(req, res); + + expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); + expect(res.send).toBeCalledWith( + renderStatsCard(stats, { + hide: ["issues", "prs", "contribs"], + show_icons: true, + hide_border: true, + line_height: 100, + title_color: "fff", + ring_color: "0000ff", + icon_color: "fff", + text_color: "fff", + bg_color: "fff", + }), + ); + }); }); diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js index 69708137b334cf..288048670f20b7 100644 --- a/tests/renderStatsCard.test.js +++ b/tests/renderStatsCard.test.js @@ -239,6 +239,39 @@ describe("Test renderStatsCard", () => { ); }); + it("should render custom ring_color properly", () => { + const customColors = { + title_color: "5a0", + ring_color: "0000ff", + icon_color: "1b998b", + text_color: "9991", + bg_color: "252525", + }; + + document.body.innerHTML = renderStatsCard(stats, { ...customColors }); + + const styleTag = document.querySelector("style"); + const stylesObject = cssToObject(styleTag.innerHTML); + + const headerClassStyles = stylesObject[":host"][".header "]; + const statClassStyles = stylesObject[":host"][".stat "]; + const iconClassStyles = stylesObject[":host"][".icon "]; + const rankCircleStyles = stylesObject[":host"][".rank-circle "]; + const rankCircleRimStyles = stylesObject[":host"][".rank-circle-rim "]; + + expect(headerClassStyles.fill.trim()).toBe(`#${customColors.title_color}`); + expect(statClassStyles.fill.trim()).toBe(`#${customColors.text_color}`); + expect(iconClassStyles.fill.trim()).toBe(`#${customColors.icon_color}`); + expect(rankCircleStyles.stroke.trim()).toBe(`#${customColors.ring_color}`); + expect(rankCircleRimStyles.stroke.trim()).toBe( + `#${customColors.ring_color}`, + ); + expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( + "fill", + "#252525", + ); + }); + it("should render icons correctly", () => { document.body.innerHTML = renderStatsCard(stats, { show_icons: true, diff --git a/tests/utils.test.js b/tests/utils.test.js index b6e4a3be3f9f97..5f6231cceff2d7 100644 --- a/tests/utils.test.js +++ b/tests/utils.test.js @@ -48,6 +48,7 @@ describe("Test utils.js", () => { let colors = getCardColors({ title_color: "f00", text_color: "0f0", + ring_color: "0000ff", icon_color: "00f", bg_color: "fff", border_color: "fff", @@ -57,6 +58,7 @@ describe("Test utils.js", () => { titleColor: "#f00", textColor: "#0f0", iconColor: "#00f", + ringColor: "#0000ff", bgColor: "#fff", borderColor: "#fff", }); @@ -75,6 +77,7 @@ describe("Test utils.js", () => { titleColor: "#2f80ed", textColor: "#0f0", iconColor: "#00f", + ringColor: "#2f80ed", bgColor: "#fff", borderColor: "#e4e2e2", }); @@ -87,11 +90,31 @@ describe("Test utils.js", () => { expect(colors).toStrictEqual({ titleColor: "#fff", textColor: "#9f9f9f", + ringColor: "#fff", iconColor: "#79ff97", bgColor: "#151515", borderColor: "#e4e2e2", }); }); + + it("getCardColors: should return ring color equal to title color if not ring color is defined", () => { + let colors = getCardColors({ + title_color: "f00", + text_color: "0f0", + icon_color: "00f", + bg_color: "fff", + border_color: "fff", + theme: "dark", + }); + expect(colors).toStrictEqual({ + titleColor: "#f00", + textColor: "#0f0", + iconColor: "#00f", + ringColor: "#f00", + bgColor: "#fff", + borderColor: "#fff", + }); + }); }); describe("wrapTextMultiline", () => {