@stats-organization/github-readme-stats-core 2.1.4 → 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 (182) 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 +28 -26
  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 +32 -36
  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 +18 -33
  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 +32 -44
  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 +28 -26
  16. package/build/calculateRank.d.ts +12 -11
  17. package/build/calculateRank.d.ts.map +1 -1
  18. package/build/calculateRank.js +18 -18
  19. package/build/cards/common-options.d.ts +13 -0
  20. package/build/cards/common-options.d.ts.map +1 -0
  21. package/build/cards/common-options.js +1 -0
  22. package/build/cards/gist.d.ts +11 -16
  23. package/build/cards/gist.d.ts.map +1 -1
  24. package/build/cards/gist.js +26 -31
  25. package/build/cards/repo.d.ts +19 -16
  26. package/build/cards/repo.d.ts.map +1 -1
  27. package/build/cards/repo.js +79 -72
  28. package/build/cards/stats.d.ts +29 -44
  29. package/build/cards/stats.d.ts.map +1 -1
  30. package/build/cards/stats.js +118 -173
  31. package/build/cards/top-languages.d.ts +81 -77
  32. package/build/cards/top-languages.d.ts.map +1 -1
  33. package/build/cards/top-languages.js +186 -184
  34. package/build/cards/wakatime.d.ts +21 -11
  35. package/build/cards/wakatime.d.ts.map +1 -1
  36. package/build/cards/wakatime.js +92 -109
  37. package/build/common/Card.d.ts +41 -14
  38. package/build/common/Card.d.ts.map +1 -1
  39. package/build/common/Card.js +92 -31
  40. package/build/common/I18n.d.ts +4 -2
  41. package/build/common/I18n.d.ts.map +1 -1
  42. package/build/common/color.d.ts +91 -15
  43. package/build/common/color.d.ts.map +1 -1
  44. package/build/common/color.js +163 -17
  45. package/build/common/config.d.ts +2 -1
  46. package/build/common/config.d.ts.map +1 -1
  47. package/build/common/config.js +16 -26
  48. package/build/common/constants.d.ts +2 -1
  49. package/build/common/constants.d.ts.map +1 -1
  50. package/build/common/date.d.ts +37 -0
  51. package/build/common/date.d.ts.map +1 -0
  52. package/build/common/date.js +31 -0
  53. package/build/common/html.js +1 -1
  54. package/build/common/http.d.ts +37 -5
  55. package/build/common/http.d.ts.map +1 -1
  56. package/build/common/http.js +29 -6
  57. package/build/common/icons.d.ts +1 -0
  58. package/build/common/icons.d.ts.map +1 -1
  59. package/build/common/icons.js +1 -0
  60. package/build/common/languageColors.d.ts +11 -0
  61. package/build/common/languageColors.d.ts.map +1 -0
  62. package/build/common/languageColors.js +15 -0
  63. package/build/common/languageColors.json +10 -1
  64. package/build/common/ops.d.ts +27 -33
  65. package/build/common/ops.d.ts.map +1 -1
  66. package/build/common/ops.js +31 -48
  67. package/build/common/render.d.ts +154 -113
  68. package/build/common/render.d.ts.map +1 -1
  69. package/build/common/render.js +209 -92
  70. package/build/common/retryer.d.ts +15 -6
  71. package/build/common/retryer.d.ts.map +1 -1
  72. package/build/common/retryer.js +2 -0
  73. package/build/fetchers/gist.d.ts +6 -21
  74. package/build/fetchers/gist.d.ts.map +1 -1
  75. package/build/fetchers/gist.js +28 -64
  76. package/build/fetchers/repo.d.ts +12 -11
  77. package/build/fetchers/repo.d.ts.map +1 -1
  78. package/build/fetchers/repo.js +27 -68
  79. package/build/fetchers/stats.d.ts +24 -17
  80. package/build/fetchers/stats.d.ts.map +1 -1
  81. package/build/fetchers/stats.js +302 -184
  82. package/build/fetchers/top-languages.d.ts +10 -15
  83. package/build/fetchers/top-languages.d.ts.map +1 -1
  84. package/build/fetchers/top-languages.js +52 -103
  85. package/build/fetchers/types.d.ts +130 -0
  86. package/build/fetchers/types.d.ts.map +1 -0
  87. package/build/fetchers/types.js +1 -0
  88. package/build/fetchers/wakatime.d.ts +9 -5
  89. package/build/fetchers/wakatime.d.ts.map +1 -1
  90. package/build/fetchers/wakatime.js +8 -4
  91. package/build/graphql/contributionsDocument.d.ts +18 -0
  92. package/build/graphql/contributionsDocument.d.ts.map +1 -0
  93. package/build/graphql/contributionsDocument.js +30 -0
  94. package/build/graphql/generated/common.d.ts +42 -0
  95. package/build/graphql/generated/common.d.ts.map +1 -0
  96. package/build/graphql/generated/common.js +2 -0
  97. package/build/graphql/generated/gist.d.ts +44 -0
  98. package/build/graphql/generated/gist.d.ts.map +1 -0
  99. package/build/graphql/generated/gist.js +27 -0
  100. package/build/graphql/generated/repo.d.ts +67 -0
  101. package/build/graphql/generated/repo.d.ts.map +1 -0
  102. package/build/graphql/generated/repo.js +30 -0
  103. package/build/graphql/generated/stats.d.ts +150 -0
  104. package/build/graphql/generated/stats.d.ts.map +1 -0
  105. package/build/graphql/generated/stats.js +95 -0
  106. package/build/graphql/generated/top-languages.d.ts +54 -0
  107. package/build/graphql/generated/top-languages.d.ts.map +1 -0
  108. package/build/graphql/generated/top-languages.js +27 -0
  109. package/build/graphql/graphqlDocument.d.ts +22 -0
  110. package/build/graphql/graphqlDocument.d.ts.map +1 -0
  111. package/build/graphql/graphqlDocument.js +8 -0
  112. package/build/graphql/reposContributedToDocument.d.ts +27 -0
  113. package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
  114. package/build/graphql/reposContributedToDocument.js +59 -0
  115. package/build/index.d.ts +3 -1
  116. package/build/index.d.ts.map +1 -1
  117. package/build/index.js +2 -1
  118. package/build/themes/index.d.ts +32 -0
  119. package/build/themes/index.d.ts.map +1 -1
  120. package/build/themes/index.js +28 -0
  121. package/build/translations.d.ts +17 -0
  122. package/build/translations.d.ts.map +1 -1
  123. package/build/translations.js +17 -0
  124. package/package.json +14 -8
  125. package/src/_emoji-name-map.d.ts +10 -0
  126. package/src/_github-username-regex.d.ts +4 -0
  127. package/src/api/gist.js +31 -31
  128. package/src/api/index.js +40 -42
  129. package/src/api/pin.js +20 -38
  130. package/src/api/top-langs.js +36 -49
  131. package/src/api/wakatime.js +31 -31
  132. package/src/{calculateRank.js → calculateRank.ts} +29 -19
  133. package/src/cards/common-options.ts +13 -0
  134. package/src/cards/{gist.js → gist.ts} +37 -37
  135. package/src/cards/{repo.js → repo.ts} +107 -79
  136. package/src/cards/{stats.js → stats.ts} +173 -210
  137. package/src/cards/{top-languages.js → top-languages.ts} +325 -243
  138. package/src/cards/{wakatime.js → wakatime.ts} +158 -127
  139. package/src/common/Card.ts +123 -43
  140. package/src/common/I18n.ts +6 -2
  141. package/src/common/color.ts +240 -28
  142. package/src/common/config.ts +22 -29
  143. package/src/common/constants.ts +3 -1
  144. package/src/common/date.ts +45 -0
  145. package/src/common/html.ts +1 -1
  146. package/src/common/http.ts +71 -0
  147. package/src/common/icons.ts +1 -0
  148. package/src/common/languageColors.json +10 -1
  149. package/src/common/languageColors.ts +19 -0
  150. package/src/common/ops.ts +158 -0
  151. package/src/common/render.ts +652 -0
  152. package/src/common/retryer.ts +21 -12
  153. package/src/fetchers/gist.ts +79 -0
  154. package/src/fetchers/repo.ts +114 -0
  155. package/src/fetchers/stats.ts +743 -0
  156. package/src/fetchers/top-languages.ts +135 -0
  157. package/src/fetchers/{types.d.ts → types.ts} +28 -20
  158. package/src/fetchers/{wakatime.js → wakatime.ts} +19 -5
  159. package/src/graphql/contributionsDocument.ts +44 -0
  160. package/src/graphql/generated/common.ts +26 -0
  161. package/src/graphql/generated/gist.ts +59 -0
  162. package/src/graphql/generated/repo.ts +90 -0
  163. package/src/graphql/generated/stats.ts +194 -0
  164. package/src/graphql/generated/top-languages.ts +75 -0
  165. package/src/graphql/graphqlDocument.ts +25 -0
  166. package/src/graphql/queries/gist.graphql +25 -0
  167. package/src/graphql/queries/repo.graphql +28 -0
  168. package/src/graphql/queries/stats.graphql +120 -0
  169. package/src/graphql/queries/top-languages.graphql +34 -0
  170. package/src/graphql/reposContributedToDocument.ts +86 -0
  171. package/src/index.ts +3 -1
  172. package/src/themes/index.ts +33 -0
  173. package/src/translations.ts +17 -0
  174. package/src/cards/types.d.ts +0 -78
  175. package/src/common/http.js +0 -19
  176. package/src/common/ops.js +0 -170
  177. package/src/common/render.js +0 -440
  178. package/src/fetchers/gist.js +0 -112
  179. package/src/fetchers/repo.js +0 -161
  180. package/src/fetchers/stats.js +0 -474
  181. package/src/fetchers/top-languages.js +0 -175
  182. package/src/themes/README.md +0 -229
@@ -1,13 +1,15 @@
1
1
  import { Card } from "../common/Card.js";
2
2
  import { I18n } from "../common/I18n.js";
3
- import { getCardColors } from "../common/color.js";
3
+ import { getLightDarkColors } from "../common/color.js";
4
4
  import { CustomError } from "../common/error.js";
5
- import { kFormatter } from "../common/fmt.js";
6
5
  import { icons, rankIcon } from "../common/icons.js";
7
6
  import { buildSearchFilter, clampValue } from "../common/ops.js";
8
- import { flexLayout, measureText } from "../common/render.js";
7
+ import { createTextNode, flexLayout, measureText } from "../common/render.js";
8
+ import type { StatsData } from "../fetchers/types.js";
9
9
  import { statCardLocales, wakatimeCardLocales } from "../translations.js";
10
10
 
11
+ import type { CommonOptions } from "./common-options.js";
12
+
11
13
  const CARD_MIN_WIDTH = 287;
12
14
  const CARD_DEFAULT_WIDTH = 287;
13
15
  const RANK_CARD_MIN_WIDTH = 420;
@@ -15,12 +17,39 @@ const RANK_CARD_DEFAULT_WIDTH = 450;
15
17
  const RANK_ONLY_CARD_MIN_WIDTH = 290;
16
18
  const RANK_ONLY_CARD_DEFAULT_WIDTH = 290;
17
19
 
18
- /**
19
- * Long locales that need more space for text. Keep sorted alphabetically.
20
- *
21
- * @type {(keyof typeof wakatimeCardLocales["wakatimecard.title"])[]}
22
- */
23
- const LONG_LOCALES = [
20
+ type RankIcon = "default" | "github" | "percentile";
21
+
22
+ interface StatCardOptions extends CommonOptions {
23
+ hide: Array<string>;
24
+ show_icons: boolean;
25
+ hide_title: boolean;
26
+ card_width: number;
27
+ hide_rank: boolean;
28
+ include_all_commits: boolean;
29
+ commits_year: number;
30
+ line_height: number | string;
31
+ custom_title: string;
32
+ disable_animations: boolean;
33
+ number_format: string;
34
+ number_precision: number;
35
+ ring_color: string;
36
+ text_bold: boolean;
37
+ rank_icon: RankIcon;
38
+ show: Array<string>;
39
+ }
40
+
41
+ /** Meta data for a stat, used to build its text node and accessibility label. */
42
+ interface StatItem {
43
+ icon: string;
44
+ label: string;
45
+ value: number | string;
46
+ id: string;
47
+ unitSymbol?: string;
48
+ link?: string;
49
+ }
50
+
51
+ /** Long locales that need more space for text. Keep sorted alphabetically. */
52
+ const LONG_LOCALES: Array<string> = [
24
53
  "az",
25
54
  "bg",
26
55
  "cs",
@@ -49,87 +78,13 @@ const LONG_LOCALES = [
49
78
  "zh-tw",
50
79
  ];
51
80
 
52
- /**
53
- * Create a stats card text item.
54
- *
55
- * @param {object} params Object that contains the createTextNode parameters.
56
- * @param {string} params.icon The icon to display.
57
- * @param {string} params.label The label to display.
58
- * @param {number} params.value The value to display.
59
- * @param {string} params.id The id of the stat.
60
- * @param {string=} params.unitSymbol The unit symbol of the stat.
61
- * @param {number} params.index The index of the stat.
62
- * @param {boolean} params.showIcons Whether to show icons.
63
- * @param {number} params.shiftValuePos Number of pixels the value has to be shifted to the right.
64
- * @param {boolean} params.bold Whether to bold the label.
65
- * @param {string} params.numberFormat The format of numbers on card.
66
- * @param {number=} params.numberPrecision The precision of numbers on card.
67
- * @param {string} params.link Url to link to.
68
- * @param {number} params.labelXOffset horizontal offset for label.
69
- * @returns {string} The stats card text item SVG object.
70
- */
71
- const createTextNode = ({
72
- icon,
73
- label,
74
- value,
75
- id,
76
- unitSymbol,
77
- index,
78
- showIcons,
79
- shiftValuePos,
80
- bold,
81
- numberFormat,
82
- numberPrecision,
83
- link,
84
- labelXOffset = 25,
85
- }) => {
86
- const precision =
87
- typeof numberPrecision === "number" && !isNaN(numberPrecision)
88
- ? clampValue(numberPrecision, 0, 2)
89
- : undefined;
90
- const kValue =
91
- numberFormat.toLowerCase() === "long" || id === "prs_merged_percentage"
92
- ? value
93
- : kFormatter(value, precision);
94
- const staggerDelay = (index + 3) * 150;
95
-
96
- const labelOffset = showIcons ? `x="${labelXOffset}"` : "";
97
- const iconSvg = showIcons
98
- ? `
99
- <svg data-testid="icon" class="icon" viewBox="0 0 16 16" version="1.1" width="16" height="16">
100
- ${icon}
101
- </svg>
102
- `
103
- : "";
104
- return (
105
- `
106
- <g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">` +
107
- (link ? `<a href="${link}">` : "") +
108
- `
109
- ${iconSvg}
110
- <text class="stat ${
111
- bold ? " bold" : "not_bold"
112
- }" ${labelOffset} y="12.5">${label}:</text>
113
- <text
114
- class="stat ${bold ? " bold" : "not_bold"}"
115
- x="${(showIcons ? 140 : 120) + (bold ? 5 : 0) + shiftValuePos}"
116
- y="12.5"
117
- data-testid="${id}"
118
- >${kValue}${unitSymbol ? ` ${unitSymbol}` : ""}</text>` +
119
- (link ? "</a>" : "") +
120
- `
121
- </g>
122
- `
123
- );
124
- };
125
-
126
81
  /**
127
82
  * Calculates progress along the boundary of the circle, i.e. its circumference.
128
83
  *
129
- * @param {number} value The rank value to calculate progress for.
130
- * @returns {number} Progress value.
84
+ * @param value The rank value to calculate progress for.
85
+ * @returns Progress value.
131
86
  */
132
- const calculateCircleProgress = (value) => {
87
+ const calculateCircleProgress = (value: number): number => {
133
88
  const radius = 40;
134
89
  const c = Math.PI * (radius * 2);
135
90
 
@@ -147,10 +102,11 @@ const calculateCircleProgress = (value) => {
147
102
  * Retrieves the animation to display progress along the circumference of circle
148
103
  * from the beginning to the given value in a clockwise direction.
149
104
  *
150
- * @param {{progress: number}} progress The progress value to animate to.
151
- * @returns {string} Progress animation css.
105
+ * @param props The props object.
106
+ * @param props.progress The progress value to animate to.
107
+ * @returns Progress animation css.
152
108
  */
153
- const getProgressAnimation = ({ progress }) => {
109
+ const getProgressAnimation = ({ progress }: { progress: number }): string => {
154
110
  return `
155
111
  @keyframes rankAnimation {
156
112
  from {
@@ -166,24 +122,27 @@ const getProgressAnimation = ({ progress }) => {
166
122
  /**
167
123
  * Retrieves CSS styles for a card.
168
124
  *
169
- * @param {Object} colors The colors to use for the card.
170
- * @param {string} colors.titleColor The title color.
171
- * @param {string} colors.textColor The text color.
172
- * @param {string} colors.iconColor The icon color.
173
- * @param {string} colors.ringColor The ring color.
174
- * @param {boolean} colors.show_icons Whether to show icons.
175
- * @param {number} colors.progress The progress value to animate to.
176
- * @returns {string} Card CSS styles.
125
+ * @param colors The colors to use for the card.
126
+ * @param colors.textColor The text color.
127
+ * @param colors.iconColor The icon color.
128
+ * @param colors.ringColor The ring color.
129
+ * @param colors.show_icons Whether to show icons.
130
+ * @param colors.progress The progress value to animate to.
131
+ * @returns Card CSS styles.
177
132
  */
178
133
  const getStyles = ({
179
- // eslint-disable-next-line no-unused-vars
180
- titleColor,
181
134
  textColor,
182
135
  iconColor,
183
136
  ringColor,
184
137
  show_icons,
185
138
  progress,
186
- }) => {
139
+ }: {
140
+ textColor: string;
141
+ iconColor: string;
142
+ ringColor: string;
143
+ show_icons: boolean;
144
+ progress: number;
145
+ }): string => {
187
146
  return `
188
147
  .stat {
189
148
  font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
@@ -238,37 +197,39 @@ const getStyles = ({
238
197
  /**
239
198
  * Return the label for commits according to the selected options
240
199
  *
241
- * @param {boolean} include_all_commits Option to include all years
242
- * @param {number|undefined} commits_year Option to include only selected year
243
- * @param {I18n} i18n The I18n instance.
244
- * @returns {string} The label corresponding to the options.
200
+ * @param include_all_commits Option to include all years
201
+ * @param commits_year Option to include only selected year
202
+ * @param i18n The I18n instance.
203
+ * @returns The label corresponding to the options.
245
204
  */
246
- const getTotalCommitsYearLabel = (include_all_commits, commits_year, i18n) =>
205
+ const getTotalCommitsYearLabel = (
206
+ include_all_commits: boolean,
207
+ commits_year: number | undefined,
208
+ i18n: I18n,
209
+ ): string =>
247
210
  include_all_commits
248
211
  ? ""
249
212
  : commits_year
250
213
  ? ` (${commits_year})`
251
214
  : ` (${i18n.t("wakatimecard.lastyear")})`;
252
215
 
253
- /**
254
- * @typedef {import('../fetchers/types').StatsData} StatsData
255
- * @typedef {import('./types').StatCardOptions} StatCardOptions
256
- */
257
-
258
216
  /**
259
217
  * Renders the stats card.
260
218
  *
261
- * @param {StatsData} stats The stats data.
262
- * @param {Partial<StatCardOptions>} options The card options.
263
- * @returns {string} The stats card SVG object.
219
+ * @param stats The stats data.
220
+ * @param options The card options.
221
+ * @param username GitHub username, used to build stat search links.
222
+ * @param repo Repositories to scope the search links to.
223
+ * @param owner Owners to scope the search links to.
224
+ * @returns The stats card SVG object.
264
225
  */
265
226
  const renderStatsCard = (
266
- stats,
267
- options = {},
268
- username,
269
- repo = [],
270
- owner = [],
271
- ) => {
227
+ stats: StatsData,
228
+ options: Partial<StatCardOptions> = {},
229
+ username?: string,
230
+ repo: Array<string> = [],
231
+ owner: Array<string> = [],
232
+ ): string => {
272
233
  const {
273
234
  name,
274
235
  totalStars,
@@ -281,11 +242,13 @@ const renderStatsCard = (
281
242
  totalDiscussionsStarted,
282
243
  totalDiscussionsAnswered,
283
244
  contributedTo,
245
+ allTimeContributedTo,
284
246
  totalPRsAuthored,
285
247
  totalPRsCommented,
286
248
  totalPRsReviewed,
287
249
  totalIssuesAuthored,
288
250
  totalIssuesCommented,
251
+ totalContributions,
289
252
  rank,
290
253
  } = stats;
291
254
  const {
@@ -298,16 +261,9 @@ const renderStatsCard = (
298
261
  include_all_commits = false,
299
262
  commits_year,
300
263
  line_height = 25,
301
- title_color,
302
- ring_color,
303
- icon_color,
304
- text_color,
305
264
  text_bold = true,
306
- bg_color,
307
- theme = "default",
308
265
  custom_title,
309
266
  border_radius,
310
- border_color,
311
267
  number_format = "short",
312
268
  number_precision,
313
269
  locale,
@@ -318,17 +274,8 @@ const renderStatsCard = (
318
274
 
319
275
  const lheight = parseInt(String(line_height), 10);
320
276
 
321
- // returns theme based colors with proper overrides and defaults
322
- const { titleColor, iconColor, textColor, bgColor, borderColor, ringColor } =
323
- getCardColors({
324
- title_color,
325
- text_color,
326
- icon_color,
327
- bg_color,
328
- border_color,
329
- ring_color,
330
- theme,
331
- });
277
+ const { lightColors, darkColors } = getLightDarkColors(options);
278
+ const { iconColor, textColor, ringColor } = lightColors;
332
279
 
333
280
  const apostrophe = /s$/i.test(name.trim()) ? "" : "s";
334
281
  const i18n = new I18n({
@@ -340,15 +287,25 @@ const renderStatsCard = (
340
287
  });
341
288
 
342
289
  // Meta data for creating text nodes with createTextNode function
343
- const STATS = {};
290
+ const STATS: Record<string, StatItem> = {};
344
291
 
345
- STATS.stars = {
292
+ STATS["stars"] = {
346
293
  icon: icons.star,
347
294
  label: i18n.t("statcard.totalstars"),
348
295
  value: totalStars,
349
296
  id: "stars",
350
297
  };
351
- STATS.commits = {
298
+
299
+ if (show.includes("contributions")) {
300
+ STATS["contributions"] = {
301
+ icon: icons.contributions,
302
+ label: i18n.t("statcard.contributions"),
303
+ value: totalContributions,
304
+ id: "contributions",
305
+ };
306
+ }
307
+
308
+ STATS["commits"] = {
352
309
  icon: icons.commits,
353
310
  label: `${i18n.t("statcard.commits")}${getTotalCommitsYearLabel(
354
311
  include_all_commits,
@@ -358,7 +315,7 @@ const renderStatsCard = (
358
315
  value: totalCommits,
359
316
  id: "commits",
360
317
  };
361
- STATS.prs = {
318
+ STATS["prs"] = {
362
319
  icon: icons.prs,
363
320
  label: i18n.t("statcard.prs"),
364
321
  value: totalPRs,
@@ -366,7 +323,7 @@ const renderStatsCard = (
366
323
  };
367
324
 
368
325
  if (show.includes("prs_merged")) {
369
- STATS.prs_merged = {
326
+ STATS["prs_merged"] = {
370
327
  icon: icons.prs_merged,
371
328
  label: i18n.t("statcard.prs-merged"),
372
329
  value: totalPRsMerged,
@@ -375,11 +332,11 @@ const renderStatsCard = (
375
332
  }
376
333
 
377
334
  if (show.includes("prs_merged_percentage")) {
378
- STATS.prs_merged_percentage = {
335
+ STATS["prs_merged_percentage"] = {
379
336
  icon: icons.prs_merged_percentage,
380
337
  label: i18n.t("statcard.prs-merged-percentage"),
381
338
  value: mergedPRsPercentage.toFixed(
382
- typeof number_precision === "number" && !isNaN(number_precision)
339
+ number_precision !== undefined && Number.isFinite(number_precision)
383
340
  ? clampValue(number_precision, 0, 2)
384
341
  : 2,
385
342
  ),
@@ -389,7 +346,7 @@ const renderStatsCard = (
389
346
  }
390
347
 
391
348
  if (show.includes("reviews")) {
392
- STATS.reviews = {
349
+ STATS["reviews"] = {
393
350
  icon: icons.reviews,
394
351
  label: i18n.t("statcard.reviews"),
395
352
  value: totalReviews,
@@ -397,7 +354,7 @@ const renderStatsCard = (
397
354
  };
398
355
  }
399
356
 
400
- STATS.issues = {
357
+ STATS["issues"] = {
401
358
  icon: icons.issues,
402
359
  label: i18n.t("statcard.issues"),
403
360
  value: totalIssues,
@@ -405,7 +362,7 @@ const renderStatsCard = (
405
362
  };
406
363
 
407
364
  if (show.includes("discussions_started")) {
408
- STATS.discussions_started = {
365
+ STATS["discussions_started"] = {
409
366
  icon: icons.discussions_started,
410
367
  label: i18n.t("statcard.discussions-started"),
411
368
  value: totalDiscussionsStarted,
@@ -413,7 +370,7 @@ const renderStatsCard = (
413
370
  };
414
371
  }
415
372
  if (show.includes("discussions_answered")) {
416
- STATS.discussions_answered = {
373
+ STATS["discussions_answered"] = {
417
374
  icon: icons.discussions_answered,
418
375
  label: i18n.t("statcard.discussions-answered"),
419
376
  value: totalDiscussionsAnswered,
@@ -421,92 +378,97 @@ const renderStatsCard = (
421
378
  };
422
379
  }
423
380
 
424
- let repoFilter = encodeURIComponent(buildSearchFilter(repo, owner));
381
+ const repoFilter = encodeURIComponent(buildSearchFilter(repo, owner));
382
+ const encodedUsername = encodeURIComponent(username ?? "");
425
383
  if (show.includes("prs_authored")) {
426
- STATS.prs_authored = {
384
+ STATS["prs_authored"] = {
427
385
  icon: icons.prs,
428
386
  label: i18n.t("statcard.prs-authored"),
429
387
  value: totalPRsAuthored,
430
388
  id: "prs_authored",
431
- link: `https://github.com/search?q=${repoFilter}author%3A${username}&amp;type=pullrequests`,
389
+ link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&amp;type=pullrequests`,
432
390
  };
433
391
  }
434
392
  if (show.includes("prs_commented")) {
435
- STATS.prs_commented = {
393
+ STATS["prs_commented"] = {
436
394
  icon: icons.comments,
437
395
  label: i18n.t("statcard.prs-commented"),
438
396
  value: totalPRsCommented,
439
397
  id: "prs_commented",
440
- link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&amp;type=pullrequests`,
398
+ link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=pullrequests`,
441
399
  };
442
400
  }
443
401
  if (show.includes("prs_reviewed")) {
444
- STATS.prs_reviewed = {
402
+ STATS["prs_reviewed"] = {
445
403
  icon: icons.reviews,
446
404
  label: i18n.t("statcard.prs-reviewed"),
447
405
  value: totalPRsReviewed,
448
406
  id: "prs_reviewed",
449
- link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${username}+-author%3A${username}&amp;type=pullrequests`,
407
+ link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=pullrequests`,
450
408
  };
451
409
  }
452
410
  if (show.includes("issues_authored")) {
453
- STATS.issues_authored = {
411
+ STATS["issues_authored"] = {
454
412
  icon: icons.issues,
455
413
  label: i18n.t("statcard.issues-authored"),
456
414
  value: totalIssuesAuthored,
457
415
  id: "issues_authored",
458
- link: `https://github.com/search?q=${repoFilter}author%3A${username}&amp;type=issues`,
416
+ link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&amp;type=issues`,
459
417
  };
460
418
  }
461
419
  if (show.includes("issues_commented")) {
462
- STATS.issues_commented = {
420
+ STATS["issues_commented"] = {
463
421
  icon: icons.discussions_started,
464
422
  label: i18n.t("statcard.issues-commented"),
465
423
  value: totalIssuesCommented,
466
424
  id: "issues_commented",
467
- link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&amp;type=issues`,
425
+ link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=issues`,
468
426
  };
469
427
  }
470
428
 
471
- STATS.contribs = {
429
+ STATS["contribs"] = {
472
430
  icon: icons.contribs,
473
431
  label: i18n.t("statcard.contribs"),
474
432
  value: contributedTo,
475
433
  id: "contribs",
476
434
  };
477
435
 
478
- // @ts-ignore
436
+ if (show.includes("all_time_contribs")) {
437
+ STATS["all_time_contribs"] = {
438
+ icon: icons.contribs,
439
+ label: i18n.t("statcard.all-time-contribs"),
440
+ value: allTimeContributedTo,
441
+ id: "all_time_contribs",
442
+ };
443
+ }
444
+
479
445
  const isLongLocale = locale ? LONG_LOCALES.includes(locale) : false;
480
446
 
481
447
  // check if all used labels are short
482
- const longLabels =
483
- Object.keys(STATS)
484
- .filter((key) => !hide.includes(key))
485
- .filter((key) => STATS[key].label.length > 18).length > 0;
448
+ const longLabels = Object.entries(STATS)
449
+ .filter(([key]) => !hide.includes(key))
450
+ .some(([, stat]) => stat.label.length > 18);
486
451
 
487
452
  // filter out hidden stats defined by user & create the text nodes
488
- const statItems = Object.keys(STATS)
489
- .filter((key) => !hide.includes(key))
490
- .map((key, index) => {
491
- // @ts-ignore
492
- const stats = STATS[key];
493
-
494
- // create the text nodes, and pass index so that we can calculate the line spacing
495
- return createTextNode({
496
- icon: stats.icon,
497
- label: stats.label,
498
- value: stats.value,
499
- id: stats.id,
500
- unitSymbol: stats.unitSymbol,
453
+ const statItems = Object.entries(STATS)
454
+ .filter(([key]) => !hide.includes(key))
455
+ // pass index so that we can calculate the line spacing
456
+ .map(([, stat], index) =>
457
+ createTextNode({
458
+ icon: stat.icon,
459
+ label: stat.label,
460
+ value: stat.value,
461
+ id: stat.id,
462
+ unitSymbol: stat.unitSymbol,
501
463
  index,
502
464
  showIcons: show_icons,
503
465
  shiftValuePos: 29.01 + (longLabels ? 50 : 0) + (isLongLocale ? 50 : 0),
504
466
  bold: text_bold,
505
467
  numberFormat: number_format,
506
468
  numberPrecision: number_precision,
507
- link: STATS[key].link,
508
- });
509
- });
469
+ link: stat.link,
470
+ }),
471
+ );
510
472
 
511
473
  if (statItems.length === 0 && hide_rank) {
512
474
  throw new CustomError(
@@ -517,21 +479,13 @@ const renderStatsCard = (
517
479
 
518
480
  // Calculate the card height depending on how many items there are
519
481
  // but if rank circle is visible clamp the minimum height to `150`
520
- let height = Math.max(
482
+ const height = Math.max(
521
483
  45 + (statItems.length + 1) * lheight,
522
484
  hide_rank ? 0 : statItems.length ? 150 : 180,
523
485
  );
524
486
 
525
487
  // the lower the user's percentile the better
526
488
  const progress = 100 - rank.percentile;
527
- const cssStyles = getStyles({
528
- titleColor,
529
- ringColor,
530
- textColor,
531
- iconColor,
532
- show_icons,
533
- progress,
534
- });
535
489
 
536
490
  const calculateTextWidth = () => {
537
491
  return measureText(
@@ -565,7 +519,7 @@ const renderStatsCard = (
565
519
  : statItems.length
566
520
  ? RANK_CARD_DEFAULT_WIDTH
567
521
  : RANK_ONLY_CARD_DEFAULT_WIDTH) + iconWidth;
568
- let width = card_width
522
+ const width = card_width
569
523
  ? isNaN(card_width)
570
524
  ? Math.max(defaultCardWidth, minCardWidth)
571
525
  : card_width
@@ -579,18 +533,29 @@ const renderStatsCard = (
579
533
  width,
580
534
  height,
581
535
  border_radius,
582
- colors: {
583
- titleColor,
584
- textColor,
585
- iconColor,
586
- bgColor,
587
- borderColor,
588
- },
536
+ colors: { light: lightColors, dark: darkColors },
589
537
  });
590
538
 
591
539
  card.setHideBorder(hide_border);
592
540
  card.setHideTitle(hide_title);
593
- card.setCSS(cssStyles);
541
+ card.setCSS({
542
+ light: getStyles({
543
+ ringColor,
544
+ textColor,
545
+ iconColor,
546
+ show_icons,
547
+ progress,
548
+ }),
549
+ dark: darkColors
550
+ ? getStyles({
551
+ ringColor: darkColors.ringColor,
552
+ textColor: darkColors.textColor,
553
+ iconColor: darkColors.iconColor,
554
+ show_icons,
555
+ progress,
556
+ })
557
+ : null,
558
+ });
594
559
 
595
560
  if (disable_animations) {
596
561
  card.disableAnimations();
@@ -604,9 +569,9 @@ const renderStatsCard = (
604
569
  * width < RANK_CARD_DEFAULT_WIDTH: The left and right padding will be enlarged
605
570
  * equally from a certain minimum at RANK_CARD_MIN_WIDTH.
606
571
  *
607
- * @returns {number} - Rank circle translation value.
572
+ * @returns Rank circle translation value.
608
573
  */
609
- const calculateRankXTranslation = () => {
574
+ const calculateRankXTranslation = (): number => {
610
575
  if (statItems.length) {
611
576
  const minXTranslation = RANK_CARD_MIN_WIDTH + iconWidth - 70;
612
577
  if (width > RANK_CARD_DEFAULT_WIDTH) {
@@ -630,24 +595,22 @@ const renderStatsCard = (
630
595
  <circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
631
596
  <circle class="rank-circle" cx="-10" cy="8" r="40" />
632
597
  <g class="rank-text">
633
- ${rankIcon(rank_icon, rank?.level, rank?.percentile)}
598
+ ${rankIcon(rank_icon, rank.level, rank.percentile)}
634
599
  </g>
635
600
  </g>`;
636
601
 
637
602
  // Accessibility Labels
638
- const labels = Object.keys(STATS)
639
- .filter((key) => !hide.includes(key))
640
- .map((key) => {
641
- // @ts-ignore
642
- const stats = STATS[key];
603
+ const labels = Object.entries(STATS)
604
+ .filter(([key]) => !hide.includes(key))
605
+ .map(([key, stat]) => {
643
606
  if (key === "commits") {
644
607
  return `${i18n.t("statcard.commits")} ${getTotalCommitsYearLabel(
645
608
  include_all_commits,
646
609
  commits_year,
647
610
  i18n,
648
- )} : ${stats.value}`;
611
+ )} : ${stat.value}`;
649
612
  }
650
- return `${stats.label}: ${stats.value}`;
613
+ return `${stat.label}: ${stat.value}`;
651
614
  })
652
615
  .join(", ");
653
616
 
@@ -668,4 +631,4 @@ const renderStatsCard = (
668
631
  `);
669
632
  };
670
633
 
671
- export { renderStatsCard, createTextNode };
634
+ export { renderStatsCard };