@stats-organization/github-readme-stats-core 2.1.5 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/build/api/gist.d.ts +2 -7
  2. package/build/api/gist.d.ts.map +1 -1
  3. package/build/api/gist.js +9 -41
  4. package/build/api/index.d.ts +3 -8
  5. package/build/api/index.d.ts.map +1 -1
  6. package/build/api/index.js +23 -45
  7. package/build/api/pin.d.ts +2 -7
  8. package/build/api/pin.d.ts.map +1 -1
  9. package/build/api/pin.js +9 -41
  10. package/build/api/top-langs.d.ts +2 -7
  11. package/build/api/top-langs.d.ts.map +1 -1
  12. package/build/api/top-langs.js +11 -55
  13. package/build/api/wakatime.d.ts +2 -7
  14. package/build/api/wakatime.d.ts.map +1 -1
  15. package/build/api/wakatime.js +9 -41
  16. package/build/cards/common-options.d.ts +13 -0
  17. package/build/cards/common-options.d.ts.map +1 -0
  18. package/build/cards/common-options.js +1 -0
  19. package/build/cards/gist.d.ts +11 -16
  20. package/build/cards/gist.d.ts.map +1 -1
  21. package/build/cards/gist.js +26 -31
  22. package/build/cards/repo.d.ts +19 -16
  23. package/build/cards/repo.d.ts.map +1 -1
  24. package/build/cards/repo.js +58 -60
  25. package/build/cards/stats.d.ts +29 -46
  26. package/build/cards/stats.d.ts.map +1 -1
  27. package/build/cards/stats.js +113 -181
  28. package/build/cards/top-languages.d.ts +81 -77
  29. package/build/cards/top-languages.d.ts.map +1 -1
  30. package/build/cards/top-languages.js +174 -200
  31. package/build/cards/wakatime.d.ts +21 -11
  32. package/build/cards/wakatime.d.ts.map +1 -1
  33. package/build/cards/wakatime.js +73 -111
  34. package/build/common/Card.d.ts +34 -13
  35. package/build/common/Card.d.ts.map +1 -1
  36. package/build/common/Card.js +73 -40
  37. package/build/common/I18n.d.ts +4 -2
  38. package/build/common/I18n.d.ts.map +1 -1
  39. package/build/common/color.d.ts +60 -18
  40. package/build/common/color.d.ts.map +1 -1
  41. package/build/common/color.js +102 -5
  42. package/build/common/config.d.ts +2 -1
  43. package/build/common/config.d.ts.map +1 -1
  44. package/build/common/config.js +16 -26
  45. package/build/common/constants.d.ts +2 -1
  46. package/build/common/constants.d.ts.map +1 -1
  47. package/build/common/date.d.ts +37 -0
  48. package/build/common/date.d.ts.map +1 -0
  49. package/build/common/date.js +31 -0
  50. package/build/common/http.d.ts +25 -2
  51. package/build/common/http.d.ts.map +1 -1
  52. package/build/common/http.js +26 -3
  53. package/build/common/icons.d.ts +1 -0
  54. package/build/common/icons.d.ts.map +1 -1
  55. package/build/common/icons.js +1 -0
  56. package/build/common/languageColors.d.ts +11 -0
  57. package/build/common/languageColors.d.ts.map +1 -0
  58. package/build/common/languageColors.js +15 -0
  59. package/build/common/languageColors.json +1 -0
  60. package/build/common/ops.d.ts +3 -10
  61. package/build/common/ops.d.ts.map +1 -1
  62. package/build/common/ops.js +3 -15
  63. package/build/common/render.d.ts +43 -6
  64. package/build/common/render.d.ts.map +1 -1
  65. package/build/common/render.js +77 -11
  66. package/build/common/retryer.d.ts +3 -2
  67. package/build/common/retryer.d.ts.map +1 -1
  68. package/build/common/retryer.js +1 -0
  69. package/build/fetchers/gist.d.ts.map +1 -1
  70. package/build/fetchers/gist.js +8 -39
  71. package/build/fetchers/repo.d.ts +12 -11
  72. package/build/fetchers/repo.d.ts.map +1 -1
  73. package/build/fetchers/repo.js +26 -67
  74. package/build/fetchers/stats.d.ts +24 -17
  75. package/build/fetchers/stats.d.ts.map +1 -1
  76. package/build/fetchers/stats.js +302 -183
  77. package/build/fetchers/top-languages.d.ts +10 -15
  78. package/build/fetchers/top-languages.d.ts.map +1 -1
  79. package/build/fetchers/top-languages.js +52 -103
  80. package/build/fetchers/types.d.ts +24 -20
  81. package/build/fetchers/types.d.ts.map +1 -1
  82. package/build/fetchers/wakatime.d.ts +9 -5
  83. package/build/fetchers/wakatime.d.ts.map +1 -1
  84. package/build/fetchers/wakatime.js +8 -4
  85. package/build/graphql/contributionsDocument.d.ts +18 -0
  86. package/build/graphql/contributionsDocument.d.ts.map +1 -0
  87. package/build/graphql/contributionsDocument.js +30 -0
  88. package/build/graphql/generated/common.d.ts +42 -0
  89. package/build/graphql/generated/common.d.ts.map +1 -0
  90. package/build/graphql/generated/common.js +2 -0
  91. package/build/graphql/generated/gist.d.ts +44 -0
  92. package/build/graphql/generated/gist.d.ts.map +1 -0
  93. package/build/graphql/generated/gist.js +27 -0
  94. package/build/graphql/generated/repo.d.ts +67 -0
  95. package/build/graphql/generated/repo.d.ts.map +1 -0
  96. package/build/graphql/generated/repo.js +30 -0
  97. package/build/graphql/generated/stats.d.ts +150 -0
  98. package/build/graphql/generated/stats.d.ts.map +1 -0
  99. package/build/graphql/generated/stats.js +95 -0
  100. package/build/graphql/generated/top-languages.d.ts +54 -0
  101. package/build/graphql/generated/top-languages.d.ts.map +1 -0
  102. package/build/graphql/generated/top-languages.js +27 -0
  103. package/build/graphql/graphqlDocument.d.ts +22 -0
  104. package/build/graphql/graphqlDocument.d.ts.map +1 -0
  105. package/build/graphql/graphqlDocument.js +8 -0
  106. package/build/graphql/reposContributedToDocument.d.ts +27 -0
  107. package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
  108. package/build/graphql/reposContributedToDocument.js +59 -0
  109. package/build/index.d.ts +3 -1
  110. package/build/index.d.ts.map +1 -1
  111. package/build/index.js +2 -1
  112. package/build/themes/index.d.ts +32 -0
  113. package/build/themes/index.d.ts.map +1 -1
  114. package/build/themes/index.js +28 -0
  115. package/build/translations.d.ts +17 -0
  116. package/build/translations.d.ts.map +1 -1
  117. package/build/translations.js +17 -0
  118. package/package.json +13 -7
  119. package/src/_github-username-regex.d.ts +4 -0
  120. package/src/api/gist.js +10 -46
  121. package/src/api/index.js +30 -51
  122. package/src/api/pin.js +10 -46
  123. package/src/api/top-langs.js +13 -60
  124. package/src/api/wakatime.js +10 -46
  125. package/src/cards/common-options.ts +13 -0
  126. package/src/cards/{gist.js → gist.ts} +37 -37
  127. package/src/cards/{repo.js → repo.ts} +86 -68
  128. package/src/cards/{stats.js → stats.ts} +168 -219
  129. package/src/cards/{top-languages.js → top-languages.ts} +309 -265
  130. package/src/cards/{wakatime.js → wakatime.ts} +136 -130
  131. package/src/common/Card.ts +94 -49
  132. package/src/common/I18n.ts +6 -2
  133. package/src/common/color.ts +163 -14
  134. package/src/common/config.ts +22 -29
  135. package/src/common/constants.ts +3 -1
  136. package/src/common/date.ts +45 -0
  137. package/src/common/http.ts +43 -3
  138. package/src/common/icons.ts +1 -0
  139. package/src/common/languageColors.json +1 -0
  140. package/src/common/languageColors.ts +19 -0
  141. package/src/common/ops.ts +8 -18
  142. package/src/common/render.ts +114 -14
  143. package/src/common/retryer.ts +6 -5
  144. package/src/fetchers/gist.ts +15 -72
  145. package/src/fetchers/repo.ts +114 -0
  146. package/src/fetchers/stats.ts +743 -0
  147. package/src/fetchers/top-languages.ts +135 -0
  148. package/src/fetchers/types.ts +28 -20
  149. package/src/fetchers/{wakatime.js → wakatime.ts} +19 -5
  150. package/src/graphql/contributionsDocument.ts +44 -0
  151. package/src/graphql/generated/common.ts +26 -0
  152. package/src/graphql/generated/gist.ts +59 -0
  153. package/src/graphql/generated/repo.ts +90 -0
  154. package/src/graphql/generated/stats.ts +194 -0
  155. package/src/graphql/generated/top-languages.ts +75 -0
  156. package/src/graphql/graphqlDocument.ts +25 -0
  157. package/src/graphql/queries/gist.graphql +25 -0
  158. package/src/graphql/queries/repo.graphql +28 -0
  159. package/src/graphql/queries/stats.graphql +120 -0
  160. package/src/graphql/queries/top-languages.graphql +34 -0
  161. package/src/graphql/reposContributedToDocument.ts +86 -0
  162. package/src/index.ts +3 -1
  163. package/src/themes/index.ts +33 -0
  164. package/src/translations.ts +17 -0
  165. package/src/cards/types.d.ts +0 -78
  166. package/src/fetchers/repo.js +0 -161
  167. package/src/fetchers/stats.js +0 -473
  168. package/src/fetchers/top-languages.js +0 -175
  169. package/src/themes/README.md +0 -229
@@ -1,5 +1,5 @@
1
1
  import { renderWakatimeCard } from "../cards/wakatime.js";
2
- import { findInvalidColor } from "../common/color.js";
2
+ import { findInvalidColorParam, pickColorParams } from "../common/color.js";
3
3
  import {
4
4
  MissingParamError,
5
5
  retrieveSecondaryMessage,
@@ -12,14 +12,9 @@ import { isLocaleAvailable } from "../translations.js";
12
12
  // @ts-ignore
13
13
  export default async ({
14
14
  username,
15
- title_color,
16
- icon_color,
17
15
  hide_border,
18
16
  card_width,
19
17
  line_height,
20
- text_color,
21
- bg_color,
22
- theme,
23
18
  hide_title,
24
19
  hide_progress,
25
20
  custom_title,
@@ -29,17 +24,13 @@ export default async ({
29
24
  hide,
30
25
  api_domain,
31
26
  border_radius,
32
- border_color,
33
27
  display_format,
34
28
  disable_animations,
29
+ ...remainingParams
35
30
  }) => {
36
- const invalidColorInput = findInvalidColor({
37
- title_color,
38
- icon_color,
39
- text_color,
40
- bg_color,
41
- border_color,
42
- });
31
+ const colorParams = pickColorParams(remainingParams);
32
+
33
+ const invalidColorInput = findInvalidColorParam(colorParams);
43
34
  if (invalidColorInput) {
44
35
  return {
45
36
  status: "error - permanent",
@@ -56,13 +47,7 @@ export default async ({
56
47
  content: renderError({
57
48
  message: "Something went wrong",
58
49
  secondaryMessage: "Language not found",
59
- renderOptions: {
60
- title_color,
61
- text_color,
62
- bg_color,
63
- border_color,
64
- theme,
65
- },
50
+ renderOptions: colorParams,
66
51
  }),
67
52
  };
68
53
  }
@@ -74,13 +59,7 @@ export default async ({
74
59
  content: renderError({
75
60
  message: "Something went wrong",
76
61
  secondaryMessage: "Username contains unsafe characters",
77
- renderOptions: {
78
- title_color,
79
- text_color,
80
- bg_color,
81
- border_color,
82
- theme,
83
- },
62
+ renderOptions: colorParams,
84
63
  }),
85
64
  };
86
65
  }
@@ -91,20 +70,15 @@ export default async ({
91
70
  return {
92
71
  status: "success",
93
72
  content: renderWakatimeCard(stats, {
73
+ ...colorParams,
94
74
  custom_title,
95
75
  hide_title: parseBoolean(hide_title),
96
76
  hide_border: parseBoolean(hide_border),
97
77
  card_width: parseInt(card_width, 10),
98
78
  hide: parseArray(hide),
99
79
  line_height,
100
- title_color,
101
- icon_color,
102
- text_color,
103
- bg_color,
104
- theme,
105
80
  hide_progress,
106
81
  border_radius,
107
- border_color,
108
82
  locale: locale ? locale.toLowerCase() : null,
109
83
  layout,
110
84
  langs_count,
@@ -120,11 +94,7 @@ export default async ({
120
94
  message: err.message,
121
95
  secondaryMessage: retrieveSecondaryMessage(err),
122
96
  renderOptions: {
123
- title_color,
124
- text_color,
125
- bg_color,
126
- border_color,
127
- theme,
97
+ ...colorParams,
128
98
  show_repo_link: !(err instanceof MissingParamError),
129
99
  },
130
100
  }),
@@ -134,13 +104,7 @@ export default async ({
134
104
  status: "error - temporary",
135
105
  content: renderError({
136
106
  message: "An unknown error occurred",
137
- renderOptions: {
138
- title_color,
139
- text_color,
140
- bg_color,
141
- border_color,
142
- theme,
143
- },
107
+ renderOptions: colorParams,
144
108
  }),
145
109
  };
146
110
  }
@@ -0,0 +1,13 @@
1
+ import type { ThemeName } from "../themes/index.js";
2
+
3
+ export interface CommonOptions {
4
+ title_color: string;
5
+ icon_color: string;
6
+ text_color: string;
7
+ bg_color: string;
8
+ theme: ThemeName;
9
+ border_radius: number;
10
+ border_color: string;
11
+ locale: string;
12
+ hide_border: boolean;
13
+ }
@@ -1,9 +1,9 @@
1
1
  import { default as Card } from "../common/Card.js";
2
- import { getCardColors } from "../common/color.js";
2
+ import { getLightDarkColors } from "../common/color.js";
3
3
  import { kFormatter, wrapTextMultiline } from "../common/fmt.js";
4
4
  import { encodeHTML } from "../common/html.js";
5
5
  import { icons } from "../common/icons.js";
6
- import languageColors from "../common/languageColors.json" with { type: "json" };
6
+ import { getLanguageColor } from "../common/languageColors.js";
7
7
  import { parseEmojis } from "../common/ops.js";
8
8
  import {
9
9
  countWrappedLines,
@@ -14,6 +14,9 @@ import {
14
14
  wrappedTextNode,
15
15
  wrappedTextStyles,
16
16
  } from "../common/render.js";
17
+ import type { GistData } from "../fetchers/types.js";
18
+
19
+ import type { CommonOptions } from "./common-options.js";
17
20
 
18
21
  const ICON_SIZE = 16;
19
22
  const CARD_DEFAULT_WIDTH = 400;
@@ -24,48 +27,39 @@ const DESCRIPTION_FONT_SIZE = 13;
24
27
  const DESCRIPTION_LINE_HEIGHT_PX = 16;
25
28
  const DESCRIPTION_MAX_LINES = 10;
26
29
 
27
- /**
28
- * @typedef {import('./types').GistCardOptions} GistCardOptions Gist card options.
29
- * @typedef {import('../fetchers/types').GistData} GistData Gist data.
30
- */
30
+ interface GistCardOptions extends CommonOptions {
31
+ show_owner: boolean;
32
+ browser_rendering: boolean;
33
+ }
31
34
 
32
35
  /**
33
36
  * Render gist card.
34
37
  *
35
- * @param {GistData} gistData Gist data.
36
- * @param {Partial<GistCardOptions>} options Gist card options.
37
- * @returns {string} Gist card.
38
+ * @param gistData Gist data.
39
+ * @param options Gist card options.
40
+ * @returns Gist card.
38
41
  */
39
- const renderGistCard = (gistData, options = {}) => {
42
+ const renderGistCard = (
43
+ gistData: GistData,
44
+ options: Partial<GistCardOptions> = {},
45
+ ): string => {
40
46
  const { name, nameWithOwner, description, language, starsCount, forksCount } =
41
47
  gistData;
42
48
  const {
43
- title_color,
44
- icon_color,
45
- text_color,
46
- bg_color,
47
49
  theme = "default_repocard",
48
50
  border_radius,
49
- border_color,
50
51
  show_owner = false,
51
52
  browser_rendering = false,
52
53
  hide_border = false,
53
54
  } = options;
54
55
 
55
- // returns theme based colors with proper overrides and defaults
56
- const { titleColor, textColor, iconColor, bgColor, borderColor } =
57
- getCardColors({
58
- title_color,
59
- icon_color,
60
- text_color,
61
- bg_color,
62
- border_color,
63
- theme,
64
- });
56
+ const { lightColors, darkColors } = getLightDarkColors({ ...options, theme });
57
+ const { textColor, iconColor } = lightColors;
65
58
 
66
59
  const desc = parseEmojis(description || "No description provided");
67
60
 
68
- let descriptionLines, descriptionSvg;
61
+ let descriptionLines: number;
62
+ let descriptionSvg: string;
69
63
  if (browser_rendering) {
70
64
  // The browser performs the actual text wrapping inside the foreignObject;
71
65
  // we only estimate the line count server-side so the SVG can reserve enough
@@ -128,8 +122,7 @@ const renderGistCard = (gistData, options = {}) => {
128
122
  );
129
123
 
130
124
  const languageName = language || "Unspecified";
131
- // @ts-ignore
132
- const languageColor = languageColors[languageName] || "#858585";
125
+ const languageColor = getLanguageColor(languageName);
133
126
 
134
127
  const svgLanguage = createLanguageNode(languageName, languageColor);
135
128
 
@@ -154,23 +147,30 @@ const renderGistCard = (gistData, options = {}) => {
154
147
  width: CARD_DEFAULT_WIDTH,
155
148
  height,
156
149
  border_radius,
157
- colors: {
158
- titleColor,
159
- textColor,
160
- iconColor,
161
- bgColor,
162
- borderColor,
163
- },
150
+ colors: { light: lightColors, dark: darkColors },
164
151
  });
165
152
 
166
- card.setCSS(`
153
+ card.setCSS({
154
+ light: `
167
155
  .description {
168
156
  font: 400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif;fill: ${textColor};
169
157
  ${browser_rendering ? wrappedTextStyles(textColor) : ""}
170
158
  }
171
159
  .gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
172
160
  .icon { fill: ${iconColor} }
173
- `);
161
+ `,
162
+ dark: darkColors
163
+ ? `
164
+ .description {
165
+ fill: ${darkColors.textColor};
166
+ ${browser_rendering ? wrappedTextStyles(darkColors.textColor) : ""}
167
+ }
168
+ .gray { fill: ${darkColors.textColor} }
169
+ .icon { fill: ${darkColors.iconColor} }
170
+ `
171
+ : null,
172
+ });
173
+
174
174
  card.setHideBorder(hide_border);
175
175
 
176
176
  return card.render(`
@@ -1,6 +1,6 @@
1
1
  import { Card } from "../common/Card.js";
2
2
  import { I18n } from "../common/I18n.js";
3
- import { getCardColors, isPrefixedHexColor } from "../common/color.js";
3
+ import { getLightDarkColors } from "../common/color.js";
4
4
  import { kFormatter, wrapTextMultiline } from "../common/fmt.js";
5
5
  import { encodeHTML } from "../common/html.js";
6
6
  import { icons } from "../common/icons.js";
@@ -8,15 +8,17 @@ import { buildSearchFilter, clampValue, parseEmojis } from "../common/ops.js";
8
8
  import {
9
9
  countWrappedLines,
10
10
  createLanguageNode,
11
+ createTextNode,
11
12
  flexLayout,
12
13
  iconWithLabel,
13
14
  measureText,
14
15
  wrappedTextNode,
15
16
  wrappedTextStyles,
16
17
  } from "../common/render.js";
18
+ import type { RepositoryData } from "../fetchers/types.js";
17
19
  import { repoCardLocales } from "../translations.js";
18
20
 
19
- import { createTextNode } from "./stats.js";
21
+ import type { CommonOptions } from "./common-options.js";
20
22
 
21
23
  const ICON_SIZE = 16;
22
24
  const CARD_DEFAULT_WIDTH = 400;
@@ -25,30 +27,48 @@ const DESCRIPTION_FONT_SIZE = 13;
25
27
  const DESCRIPTION_LINE_HEIGHT_PX = 16;
26
28
  const DESCRIPTION_MAX_LINES = 3;
27
29
 
30
+ interface RepoCardOptions extends CommonOptions {
31
+ show_owner: boolean;
32
+ browser_rendering: boolean;
33
+ description_lines_count: number;
34
+ card_width_input: number;
35
+ show: Array<string>;
36
+ show_icons: boolean;
37
+ number_format: string;
38
+ text_bold: boolean;
39
+ line_height: number | string;
40
+ username: string;
41
+ }
42
+
43
+ interface RepoStatItem {
44
+ icon: string;
45
+ label: string;
46
+ value: number | undefined;
47
+ id: string;
48
+ link: string;
49
+ unitSymbol?: string;
50
+ }
51
+
28
52
  /**
29
53
  * Retrieves the repository description and wraps it to fit the card width.
30
54
  *
31
- * @param {string} label The repository description.
32
- * @param {string} textColor The color of the text.
33
- * @returns {string} Wrapped repo description SVG object.
55
+ * @param label The repository description.
56
+ * @param xOffset Horizontal offset of the badge.
57
+ * @returns Wrapped repo description SVG object.
34
58
  */
35
- const getBadgeSVG = (label, textColor, xOffset = 0) => {
36
- if (!isPrefixedHexColor(textColor)) {
37
- throw new Error(`Invalid text color: "${textColor}"`);
38
- }
59
+ const getBadgeSVG = (label: string, xOffset = 0): string => {
39
60
  if (!Number.isFinite(xOffset)) {
40
61
  throw new Error(`Invalid xOffset: "${xOffset}"`);
41
62
  }
42
63
 
43
64
  return `
44
65
  <g data-testid="badge" class="badge" transform="translate(${320 + xOffset}, -18)">
45
- <rect stroke="${textColor}" stroke-width="1" width="70" height="20" x="-12" y="-14" ry="10" rx="10"></rect>
66
+ <rect stroke-width="1" width="70" height="20" x="-12" y="-14" ry="10" rx="10"></rect>
46
67
  <text
47
68
  x="23" y="-5"
48
69
  alignment-baseline="central"
49
70
  dominant-baseline="central"
50
71
  text-anchor="middle"
51
- fill="${textColor}"
52
72
  >
53
73
  ${encodeHTML(label)}
54
74
  </text>
@@ -56,19 +76,17 @@ const getBadgeSVG = (label, textColor, xOffset = 0) => {
56
76
  `;
57
77
  };
58
78
 
59
- /**
60
- * @typedef {import("../fetchers/types").RepositoryData} RepositoryData Repository data.
61
- * @typedef {import("./types").RepoCardOptions} RepoCardOptions Repo card options.
62
- */
63
-
64
79
  /**
65
80
  * Renders repository card details.
66
81
  *
67
- * @param {RepositoryData} repo Repository data.
68
- * @param {Partial<RepoCardOptions>} options Card options.
69
- * @returns {string} Repository card SVG object.
82
+ * @param repo Repository data.
83
+ * @param options Card options.
84
+ * @returns Repository card SVG object.
70
85
  */
71
- const renderRepoCard = (repo, options = {}) => {
86
+ const renderRepoCard = (
87
+ repo: RepositoryData,
88
+ options: Partial<RepoCardOptions> = {},
89
+ ): string => {
72
90
  const {
73
91
  name,
74
92
  nameWithOwner,
@@ -76,7 +94,7 @@ const renderRepoCard = (repo, options = {}) => {
76
94
  primaryLanguage,
77
95
  isArchived,
78
96
  isTemplate,
79
- starCount,
97
+ stargazerCount,
80
98
  forkCount,
81
99
  totalPRsAuthored,
82
100
  totalPRsCommented,
@@ -86,10 +104,6 @@ const renderRepoCard = (repo, options = {}) => {
86
104
  } = repo;
87
105
  const {
88
106
  hide_border = false,
89
- title_color,
90
- icon_color,
91
- text_color,
92
- bg_color,
93
107
  card_width_input,
94
108
  show_owner = false,
95
109
  browser_rendering = false,
@@ -101,7 +115,6 @@ const renderRepoCard = (repo, options = {}) => {
101
115
  username,
102
116
  theme = "default_repocard",
103
117
  border_radius,
104
- border_color,
105
118
  locale,
106
119
  description_lines_count,
107
120
  } = options;
@@ -118,11 +131,11 @@ const renderRepoCard = (repo, options = {}) => {
118
131
  translations: repoCardLocales,
119
132
  });
120
133
 
121
- let repoFilter = encodeURIComponent(buildSearchFilter([nameWithOwner], []));
122
- const encodedUsername = encodeURIComponent(username);
123
- const STATS = {};
134
+ const repoFilter = encodeURIComponent(buildSearchFilter([nameWithOwner], []));
135
+ const encodedUsername = encodeURIComponent(username ?? "");
136
+ const STATS: Record<string, RepoStatItem> = {};
124
137
  if (show.includes("prs_authored")) {
125
- STATS.prs_authored = {
138
+ STATS["prs_authored"] = {
126
139
  icon: icons.prs,
127
140
  label: i18n.t("repocard.prs-authored"),
128
141
  value: totalPRsAuthored,
@@ -131,7 +144,7 @@ const renderRepoCard = (repo, options = {}) => {
131
144
  };
132
145
  }
133
146
  if (show.includes("prs_commented")) {
134
- STATS.prs_commented = {
147
+ STATS["prs_commented"] = {
135
148
  icon: icons.comments,
136
149
  label: i18n.t("repocard.prs-commented"),
137
150
  value: totalPRsCommented,
@@ -140,7 +153,7 @@ const renderRepoCard = (repo, options = {}) => {
140
153
  };
141
154
  }
142
155
  if (show.includes("prs_reviewed")) {
143
- STATS.prs_reviewed = {
156
+ STATS["prs_reviewed"] = {
144
157
  icon: icons.reviews,
145
158
  label: i18n.t("repocard.prs-reviewed"),
146
159
  value: totalPRsReviewed,
@@ -149,7 +162,7 @@ const renderRepoCard = (repo, options = {}) => {
149
162
  };
150
163
  }
151
164
  if (show.includes("issues_authored")) {
152
- STATS.issues_authored = {
165
+ STATS["issues_authored"] = {
153
166
  icon: icons.issues,
154
167
  label: i18n.t("repocard.issues-authored"),
155
168
  value: totalIssuesAuthored,
@@ -158,7 +171,7 @@ const renderRepoCard = (repo, options = {}) => {
158
171
  };
159
172
  }
160
173
  if (show.includes("issues_commented")) {
161
- STATS.issues_commented = {
174
+ STATS["issues_commented"] = {
162
175
  icon: icons.discussions_started,
163
176
  label: i18n.t("repocard.issues-commented"),
164
177
  value: totalIssuesCommented,
@@ -167,20 +180,20 @@ const renderRepoCard = (repo, options = {}) => {
167
180
  };
168
181
  }
169
182
 
170
- const statItems = Object.keys(STATS).map((key, index) =>
183
+ const statItems = Object.values(STATS).map((stat, index) =>
171
184
  // create the text nodes, and pass index so that we can calculate the line spacing
172
185
  createTextNode({
173
- icon: STATS[key].icon,
174
- label: STATS[key].label,
175
- value: STATS[key].value,
176
- id: STATS[key].id,
177
- unitSymbol: STATS[key].unitSymbol,
186
+ icon: stat.icon,
187
+ label: stat.label,
188
+ value: stat.value ?? 0,
189
+ id: stat.id,
190
+ unitSymbol: stat.unitSymbol,
178
191
  index,
179
192
  showIcons: show_icons,
180
193
  shiftValuePos: 14.01,
181
194
  bold: text_bold,
182
195
  numberFormat: number_format,
183
- link: STATS[key].link,
196
+ link: stat.link,
184
197
  labelXOffset: 23,
185
198
  }),
186
199
  );
@@ -193,7 +206,8 @@ const renderRepoCard = (repo, options = {}) => {
193
206
  const desc = parseEmojis(description || "No description provided");
194
207
  const descriptionBoxWidth = card_width - 2 * X_OFFSET;
195
208
 
196
- let descriptionLinesCount, descriptionSvg;
209
+ let descriptionLinesCount: number;
210
+ let descriptionSvg: string;
197
211
  if (browser_rendering) {
198
212
  // The browser performs the actual text wrapping inside the foreignObject;
199
213
  // we only estimate the line count server-side so the SVG can reserve enough
@@ -249,21 +263,13 @@ const renderRepoCard = (repo, options = {}) => {
249
263
  descriptionLinesCount * lineHeight +
250
264
  extraHeight;
251
265
 
252
- // returns theme based colors with proper overrides and defaults
253
- const colors = getCardColors({
254
- title_color,
255
- icon_color,
256
- text_color,
257
- bg_color,
258
- border_color,
259
- theme,
260
- });
266
+ const { lightColors, darkColors } = getLightDarkColors({ ...options, theme });
261
267
 
262
268
  const svgLanguage = primaryLanguage
263
269
  ? createLanguageNode(langName, langColor)
264
270
  : "";
265
271
 
266
- const totalStars = kFormatter(starCount);
272
+ const totalStars = kFormatter(stargazerCount);
267
273
  const totalForks = kFormatter(forkCount);
268
274
  const svgStars = iconWithLabel(
269
275
  icons.star,
@@ -288,7 +294,7 @@ const renderRepoCard = (repo, options = {}) => {
288
294
  gap: 25,
289
295
  }).join("");
290
296
 
291
- let extraRows = [];
297
+ const extraRows: Array<string> = [];
292
298
  for (let i = 0; i < statItems.length; i += 2) {
293
299
  extraRows.push(
294
300
  flexLayout({
@@ -314,22 +320,24 @@ const renderRepoCard = (repo, options = {}) => {
314
320
  width: card_width,
315
321
  height,
316
322
  border_radius,
317
- colors,
323
+ colors: { light: lightColors, dark: darkColors },
318
324
  });
319
325
 
320
326
  card.disableAnimations();
321
327
  card.setHideBorder(hide_border);
322
328
  card.setHideTitle(false);
323
- card.setCSS(`
329
+ card.setCSS({
330
+ light: `
324
331
  .description {
325
- font: 400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif;fill: ${colors.textColor};
326
- ${browser_rendering ? wrappedTextStyles(colors.textColor) : ""}
332
+ font: 400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif;fill: ${lightColors.textColor};
333
+ ${browser_rendering ? wrappedTextStyles(lightColors.textColor) : ""}
327
334
  }
328
- .gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
335
+ .gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${lightColors.textColor} }
329
336
  .badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; }
330
- .badge rect { opacity: 0.2 }
337
+ .badge rect { opacity: 0.2; stroke: ${lightColors.textColor} }
338
+ .badge text { fill: ${lightColors.textColor} }
331
339
 
332
- .stat { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
340
+ .stat { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${lightColors.textColor} }
333
341
  .stagger {
334
342
  opacity: 0;
335
343
  animation: fadeInAnimation 0.3s ease-in-out forwards;
@@ -337,25 +345,35 @@ const renderRepoCard = (repo, options = {}) => {
337
345
  .not_bold { font-weight: 400 }
338
346
  .bold { font-weight: 700 }
339
347
  .icon {
340
- fill: ${colors.iconColor};
348
+ fill: ${lightColors.iconColor};
341
349
  display: block;
342
350
  }
343
- `);
351
+ `,
352
+ dark: darkColors
353
+ ? `
354
+ .description {
355
+ fill: ${darkColors.textColor};
356
+ ${browser_rendering ? wrappedTextStyles(darkColors.textColor) : ""}
357
+ }
358
+ .gray { fill: ${darkColors.textColor} }
359
+ .badge rect { stroke: ${darkColors.textColor} }
360
+ .badge text { fill: ${darkColors.textColor} }
361
+ .stat { fill: ${darkColors.textColor} }
362
+ .icon { fill: ${darkColors.iconColor}; }
363
+ `
364
+ : null,
365
+ });
344
366
 
345
367
  return card.render(`
346
368
  ${
347
369
  isTemplate
348
- ? // @ts-ignore
349
- getBadgeSVG(
370
+ ? getBadgeSVG(
350
371
  i18n.t("repocard.template"),
351
- colors.textColor,
352
372
  card_width - CARD_DEFAULT_WIDTH,
353
373
  )
354
374
  : isArchived
355
- ? // @ts-ignore
356
- getBadgeSVG(
375
+ ? getBadgeSVG(
357
376
  i18n.t("repocard.archived"),
358
- colors.textColor,
359
377
  card_width - CARD_DEFAULT_WIDTH,
360
378
  )
361
379
  : ""