@stats-forge/github-stats-forge-core 0.0.1

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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/build/api/api-result.d.ts +44 -0
  4. package/build/api/api-result.d.ts.map +1 -0
  5. package/build/api/api-result.js +33 -0
  6. package/build/api/gist.d.ts +29 -0
  7. package/build/api/gist.d.ts.map +1 -0
  8. package/build/api/gist.js +52 -0
  9. package/build/api/index.d.ts +13 -0
  10. package/build/api/index.d.ts.map +1 -0
  11. package/build/api/index.js +8 -0
  12. package/build/api/params.d.ts +93 -0
  13. package/build/api/params.d.ts.map +1 -0
  14. package/build/api/params.js +145 -0
  15. package/build/api/pin.d.ts +47 -0
  16. package/build/api/pin.d.ts.map +1 -0
  17. package/build/api/pin.js +87 -0
  18. package/build/api/stats.d.ts +42 -0
  19. package/build/api/stats.d.ts.map +1 -0
  20. package/build/api/stats.js +132 -0
  21. package/build/api/top-langs.d.ts +37 -0
  22. package/build/api/top-langs.d.ts.map +1 -0
  23. package/build/api/top-langs.js +101 -0
  24. package/build/api/wakatime.d.ts +34 -0
  25. package/build/api/wakatime.d.ts.map +1 -0
  26. package/build/api/wakatime.js +91 -0
  27. package/build/calculateRank.d.ts +29 -0
  28. package/build/calculateRank.d.ts.map +1 -0
  29. package/build/calculateRank.js +58 -0
  30. package/build/cards/gist.d.ts +16 -0
  31. package/build/cards/gist.d.ts.map +1 -0
  32. package/build/cards/gist.js +119 -0
  33. package/build/cards/index.d.ts +11 -0
  34. package/build/cards/index.d.ts.map +1 -0
  35. package/build/cards/index.js +7 -0
  36. package/build/cards/options.d.ts +19 -0
  37. package/build/cards/options.d.ts.map +1 -0
  38. package/build/cards/options.js +1 -0
  39. package/build/cards/repo.d.ts +25 -0
  40. package/build/cards/repo.d.ts.map +1 -0
  41. package/build/cards/repo.js +276 -0
  42. package/build/cards/stats.d.ts +37 -0
  43. package/build/cards/stats.d.ts.map +1 -0
  44. package/build/cards/stats.js +457 -0
  45. package/build/cards/top-languages.d.ts +153 -0
  46. package/build/cards/top-languages.d.ts.map +1 -0
  47. package/build/cards/top-languages.js +805 -0
  48. package/build/cards/wakatime.d.ts +31 -0
  49. package/build/cards/wakatime.d.ts.map +1 -0
  50. package/build/cards/wakatime.js +376 -0
  51. package/build/common/Card.d.ts +121 -0
  52. package/build/common/Card.d.ts.map +1 -0
  53. package/build/common/Card.js +305 -0
  54. package/build/common/I18n.d.ts +27 -0
  55. package/build/common/I18n.d.ts.map +1 -0
  56. package/build/common/I18n.js +35 -0
  57. package/build/common/color.d.ts +112 -0
  58. package/build/common/color.d.ts.map +1 -0
  59. package/build/common/color.js +188 -0
  60. package/build/common/config.d.ts +53 -0
  61. package/build/common/config.d.ts.map +1 -0
  62. package/build/common/config.js +87 -0
  63. package/build/common/constants.d.ts +7 -0
  64. package/build/common/constants.d.ts.map +1 -0
  65. package/build/common/constants.js +9 -0
  66. package/build/common/date.d.ts +29 -0
  67. package/build/common/date.d.ts.map +1 -0
  68. package/build/common/date.js +23 -0
  69. package/build/common/error.d.ts +87 -0
  70. package/build/common/error.d.ts.map +1 -0
  71. package/build/common/error.js +108 -0
  72. package/build/common/fmt.d.ts +28 -0
  73. package/build/common/fmt.d.ts.map +1 -0
  74. package/build/common/fmt.js +68 -0
  75. package/build/common/html.d.ts +8 -0
  76. package/build/common/html.d.ts.map +1 -0
  77. package/build/common/html.js +14 -0
  78. package/build/common/http.d.ts +53 -0
  79. package/build/common/http.d.ts.map +1 -0
  80. package/build/common/http.js +47 -0
  81. package/build/common/icons.d.ts +28 -0
  82. package/build/common/icons.d.ts.map +1 -0
  83. package/build/common/icons.js +77 -0
  84. package/build/common/languageColors.d.ts +11 -0
  85. package/build/common/languageColors.d.ts.map +1 -0
  86. package/build/common/languageColors.js +15 -0
  87. package/build/common/languageColors.json +678 -0
  88. package/build/common/log.d.ts +9 -0
  89. package/build/common/log.d.ts.map +1 -0
  90. package/build/common/log.js +8 -0
  91. package/build/common/ops.d.ts +59 -0
  92. package/build/common/ops.d.ts.map +1 -0
  93. package/build/common/ops.js +115 -0
  94. package/build/common/render.d.ts +196 -0
  95. package/build/common/render.d.ts.map +1 -0
  96. package/build/common/render.js +474 -0
  97. package/build/common/retryer.d.ts +36 -0
  98. package/build/common/retryer.d.ts.map +1 -0
  99. package/build/common/retryer.js +67 -0
  100. package/build/fetchers/gist.d.ts +15 -0
  101. package/build/fetchers/gist.d.ts.map +1 -0
  102. package/build/fetchers/gist.js +68 -0
  103. package/build/fetchers/index.d.ts +13 -0
  104. package/build/fetchers/index.d.ts.map +1 -0
  105. package/build/fetchers/index.js +10 -0
  106. package/build/fetchers/repo.d.ts +27 -0
  107. package/build/fetchers/repo.d.ts.map +1 -0
  108. package/build/fetchers/repo.js +100 -0
  109. package/build/fetchers/stats.d.ts +74 -0
  110. package/build/fetchers/stats.d.ts.map +1 -0
  111. package/build/fetchers/stats.js +498 -0
  112. package/build/fetchers/top-languages.d.ts +23 -0
  113. package/build/fetchers/top-languages.d.ts.map +1 -0
  114. package/build/fetchers/top-languages.js +89 -0
  115. package/build/fetchers/types.d.ts +130 -0
  116. package/build/fetchers/types.d.ts.map +1 -0
  117. package/build/fetchers/types.js +1 -0
  118. package/build/fetchers/wakatime.d.ts +19 -0
  119. package/build/fetchers/wakatime.d.ts.map +1 -0
  120. package/build/fetchers/wakatime.js +36 -0
  121. package/build/graphql/contributionsDocument.d.ts +18 -0
  122. package/build/graphql/contributionsDocument.d.ts.map +1 -0
  123. package/build/graphql/contributionsDocument.js +30 -0
  124. package/build/graphql/generated/common.d.ts +42 -0
  125. package/build/graphql/generated/common.d.ts.map +1 -0
  126. package/build/graphql/generated/common.js +2 -0
  127. package/build/graphql/generated/gist.d.ts +44 -0
  128. package/build/graphql/generated/gist.d.ts.map +1 -0
  129. package/build/graphql/generated/gist.js +27 -0
  130. package/build/graphql/generated/repo.d.ts +67 -0
  131. package/build/graphql/generated/repo.d.ts.map +1 -0
  132. package/build/graphql/generated/repo.js +30 -0
  133. package/build/graphql/generated/stats.d.ts +150 -0
  134. package/build/graphql/generated/stats.d.ts.map +1 -0
  135. package/build/graphql/generated/stats.js +95 -0
  136. package/build/graphql/generated/top-languages.d.ts +54 -0
  137. package/build/graphql/generated/top-languages.d.ts.map +1 -0
  138. package/build/graphql/generated/top-languages.js +27 -0
  139. package/build/graphql/graphqlDocument.d.ts +22 -0
  140. package/build/graphql/graphqlDocument.d.ts.map +1 -0
  141. package/build/graphql/graphqlDocument.js +8 -0
  142. package/build/graphql/reposContributedToDocument.d.ts +27 -0
  143. package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
  144. package/build/graphql/reposContributedToDocument.js +59 -0
  145. package/build/index.d.ts +15 -0
  146. package/build/index.d.ts.map +1 -0
  147. package/build/index.js +10 -0
  148. package/build/themes/index.d.ts +505 -0
  149. package/build/themes/index.d.ts.map +1 -0
  150. package/build/themes/index.js +505 -0
  151. package/build/translations.d.ts +1153 -0
  152. package/build/translations.d.ts.map +1 -0
  153. package/build/translations.js +1156 -0
  154. package/package.json +114 -0
  155. package/src/_emoji-name-map.d.ts +10 -0
  156. package/src/_github-username-regex.d.ts +4 -0
  157. package/src/api/api-result.ts +69 -0
  158. package/src/api/gist.ts +66 -0
  159. package/src/api/index.ts +16 -0
  160. package/src/api/params.ts +221 -0
  161. package/src/api/pin.ts +126 -0
  162. package/src/api/stats.ts +195 -0
  163. package/src/api/top-langs.ts +150 -0
  164. package/src/api/wakatime.ts +130 -0
  165. package/src/calculateRank.ts +91 -0
  166. package/src/cards/gist.ts +169 -0
  167. package/src/cards/index.ts +21 -0
  168. package/src/cards/options.ts +18 -0
  169. package/src/cards/repo.ts +376 -0
  170. package/src/cards/stats.ts +615 -0
  171. package/src/cards/top-languages.ts +1077 -0
  172. package/src/cards/wakatime.ts +501 -0
  173. package/src/common/Card.ts +364 -0
  174. package/src/common/I18n.ts +51 -0
  175. package/src/common/color.ts +296 -0
  176. package/src/common/config.ts +118 -0
  177. package/src/common/constants.ts +12 -0
  178. package/src/common/date.ts +34 -0
  179. package/src/common/error.ts +163 -0
  180. package/src/common/fmt.ts +86 -0
  181. package/src/common/html.ts +17 -0
  182. package/src/common/http.ts +98 -0
  183. package/src/common/icons.ts +80 -0
  184. package/src/common/languageColors.json +678 -0
  185. package/src/common/languageColors.ts +19 -0
  186. package/src/common/log.ts +12 -0
  187. package/src/common/ops.ts +145 -0
  188. package/src/common/render.ts +641 -0
  189. package/src/common/retryer.ts +111 -0
  190. package/src/fetchers/gist.ts +82 -0
  191. package/src/fetchers/index.ts +25 -0
  192. package/src/fetchers/repo.ts +140 -0
  193. package/src/fetchers/stats.ts +742 -0
  194. package/src/fetchers/top-languages.ts +134 -0
  195. package/src/fetchers/types.ts +136 -0
  196. package/src/fetchers/wakatime.ts +56 -0
  197. package/src/graphql/contributionsDocument.ts +44 -0
  198. package/src/graphql/generated/common.ts +26 -0
  199. package/src/graphql/generated/gist.ts +56 -0
  200. package/src/graphql/generated/repo.ts +79 -0
  201. package/src/graphql/generated/stats.ts +180 -0
  202. package/src/graphql/generated/top-languages.ts +66 -0
  203. package/src/graphql/graphqlDocument.ts +25 -0
  204. package/src/graphql/queries/gist.graphql +25 -0
  205. package/src/graphql/queries/repo.graphql +28 -0
  206. package/src/graphql/queries/stats.graphql +113 -0
  207. package/src/graphql/queries/top-languages.graphql +27 -0
  208. package/src/graphql/reposContributedToDocument.ts +83 -0
  209. package/src/index.ts +18 -0
  210. package/src/themes/index.ts +519 -0
  211. package/src/translations.ts +1169 -0
@@ -0,0 +1,457 @@
1
+ import { Card } from '../common/Card.js';
2
+ import { getLightDarkColors } from '../common/color.js';
3
+ import { CardError } from '../common/error.js';
4
+ import { I18n } from '../common/I18n.js';
5
+ import { icons, rankIcon } from '../common/icons.js';
6
+ import { buildSearchFilter, clampValue } from '../common/ops.js';
7
+ import { createTextNode, flexLayout, measureText } from '../common/render.js';
8
+ import { statCardLocales, wakatimeCardLocales } from '../translations.js';
9
+ const CARD_MIN_WIDTH = 287;
10
+ const CARD_DEFAULT_WIDTH = 287;
11
+ const RANK_CARD_MIN_WIDTH = 420;
12
+ const RANK_CARD_DEFAULT_WIDTH = 450;
13
+ const RANK_ONLY_CARD_MIN_WIDTH = 290;
14
+ const RANK_ONLY_CARD_DEFAULT_WIDTH = 290;
15
+ /** Rank indicators the card can draw; the api validates `rank_icon` against this. */
16
+ const RANK_ICONS = ['default', 'github', 'percentile'];
17
+ /** Long locales that need more space for text. Keep sorted alphabetically. */
18
+ const LONG_LOCALES = [
19
+ 'az',
20
+ 'bg',
21
+ 'cs',
22
+ 'de',
23
+ 'el',
24
+ 'es',
25
+ 'fil',
26
+ 'fi',
27
+ 'fr',
28
+ 'hu',
29
+ 'id',
30
+ 'ja',
31
+ 'ml',
32
+ 'my',
33
+ 'nl',
34
+ 'pl',
35
+ 'pt-br',
36
+ 'pt-pt',
37
+ 'ru',
38
+ 'sr',
39
+ 'sr-latn',
40
+ 'sw',
41
+ 'ta',
42
+ 'uk-ua',
43
+ 'uz',
44
+ 'zh-tw',
45
+ ];
46
+ /**
47
+ * Calculates progress along the boundary of the circle, i.e. its circumference.
48
+ *
49
+ * @param value The rank value to calculate progress for.
50
+ * @returns Progress value.
51
+ */
52
+ const calculateCircleProgress = (value) => {
53
+ const radius = 40;
54
+ const c = Math.PI * (radius * 2);
55
+ if (value < 0) {
56
+ value = 0;
57
+ }
58
+ if (value > 100) {
59
+ value = 100;
60
+ }
61
+ return ((100 - value) / 100) * c;
62
+ };
63
+ /**
64
+ * Retrieves the animation to display progress along the circumference of circle
65
+ * from the beginning to the given value in a clockwise direction.
66
+ *
67
+ * @param props The props object.
68
+ * @param props.progress The progress value to animate to.
69
+ * @returns Progress animation css.
70
+ */
71
+ const getProgressAnimation = ({ progress }) => {
72
+ return `
73
+ @keyframes rankAnimation {
74
+ from {
75
+ stroke-dashoffset: ${calculateCircleProgress(0)};
76
+ }
77
+ to {
78
+ stroke-dashoffset: ${calculateCircleProgress(progress)};
79
+ }
80
+ }
81
+ `;
82
+ };
83
+ /**
84
+ * Retrieves CSS styles for a card.
85
+ *
86
+ * @param colors The colors to use for the card.
87
+ * @param colors.textColor The text color.
88
+ * @param colors.iconColor The icon color.
89
+ * @param colors.ringColor The ring color.
90
+ * @param colors.show_icons Whether to show icons.
91
+ * @param colors.progress The progress value to animate to.
92
+ * @returns Card CSS styles.
93
+ */
94
+ const getStyles = ({ textColor, iconColor, ringColor, show_icons, progress, }) => {
95
+ return `
96
+ .stat {
97
+ font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
98
+ }
99
+ @supports(-moz-appearance: auto) {
100
+ /* Selector detects Firefox */
101
+ .stat { font-size:12px; }
102
+ }
103
+ .stagger {
104
+ opacity: 0;
105
+ animation: fadeInAnimation 0.3s ease-in-out forwards;
106
+ }
107
+ .rank-text {
108
+ font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
109
+ animation: scaleInAnimation 0.3s ease-in-out forwards;
110
+ }
111
+ .rank-percentile-header {
112
+ font-size: 14px;
113
+ }
114
+ .rank-percentile-text {
115
+ font-size: 16px;
116
+ }
117
+
118
+ .not_bold { font-weight: 400 }
119
+ .bold { font-weight: 700 }
120
+ .icon {
121
+ fill: ${iconColor};
122
+ display: ${show_icons ? 'block' : 'none'};
123
+ }
124
+
125
+ .rank-circle-rim {
126
+ stroke: ${ringColor};
127
+ fill: none;
128
+ stroke-width: 6;
129
+ opacity: 0.2;
130
+ }
131
+ .rank-circle {
132
+ stroke: ${ringColor};
133
+ stroke-dasharray: 250;
134
+ fill: none;
135
+ stroke-width: 6;
136
+ stroke-linecap: round;
137
+ opacity: 0.8;
138
+ transform-origin: -10px 8px;
139
+ transform: rotate(-90deg);
140
+ animation: rankAnimation 1s forwards ease-in-out;
141
+ }
142
+ ${getProgressAnimation({ progress })}
143
+ `;
144
+ };
145
+ /**
146
+ * Return the label for commits according to the selected options
147
+ *
148
+ * @param include_all_commits Option to include all years
149
+ * @param commits_year Option to include only selected year
150
+ * @param i18n The I18n instance.
151
+ * @returns The label corresponding to the options.
152
+ */
153
+ const getTotalCommitsYearLabel = (include_all_commits, commits_year, i18n) => include_all_commits
154
+ ? ''
155
+ : commits_year
156
+ ? ` (${commits_year})`
157
+ : ` (${i18n.t('wakatimecard.lastyear')})`;
158
+ /**
159
+ * Renders the stats card.
160
+ *
161
+ * @param stats The stats data.
162
+ * @param options The card options.
163
+ * @param username GitHub username, used to build stat search links.
164
+ * @param repo Repositories to scope the search links to.
165
+ * @param owner Owners to scope the search links to.
166
+ * @returns The stats card SVG object.
167
+ */
168
+ const renderStatsCard = (stats, options = {}, username, repo = [], owner = []) => {
169
+ const { name, totalStars, totalCommits, totalIssues, totalPRs, totalPRsMerged, mergedPRsPercentage, totalReviews, totalDiscussionsStarted, totalDiscussionsAnswered, contributedTo, allTimeContributedTo, totalPRsAuthored, totalPRsCommented, totalPRsReviewed, totalIssuesAuthored, totalIssuesCommented, totalContributions, rank, } = stats;
170
+ const { hide = [], show_icons = false, hide_title = false, hide_border = false, card_width, hide_rank = false, include_all_commits = false, commits_year, line_height = 25, text_bold = true, custom_title, border_radius, number_format = 'short', number_precision, locale, disable_animations = false, rank_icon = 'default', show = [], } = options;
171
+ const lheight = parseInt(String(line_height), 10);
172
+ const { lightColors, darkColors } = getLightDarkColors(options);
173
+ const apostrophe = /s$/i.test(name.trim()) ? '' : 's';
174
+ const i18n = new I18n({
175
+ locale,
176
+ translations: {
177
+ ...statCardLocales({ name, apostrophe }),
178
+ ...wakatimeCardLocales,
179
+ },
180
+ });
181
+ // Meta data for creating text nodes with createTextNode function
182
+ const STATS = {};
183
+ STATS['stars'] = {
184
+ icon: icons.star,
185
+ label: i18n.t('statcard.totalstars'),
186
+ value: totalStars,
187
+ id: 'stars',
188
+ };
189
+ if (show.includes('contributions')) {
190
+ STATS['contributions'] = {
191
+ icon: icons.contributions,
192
+ label: i18n.t('statcard.contributions'),
193
+ value: totalContributions,
194
+ id: 'contributions',
195
+ };
196
+ }
197
+ STATS['commits'] = {
198
+ icon: icons.commits,
199
+ label: `${i18n.t('statcard.commits')}${getTotalCommitsYearLabel(include_all_commits, commits_year, i18n)}`,
200
+ value: totalCommits,
201
+ id: 'commits',
202
+ };
203
+ STATS['prs'] = {
204
+ icon: icons.prs,
205
+ label: i18n.t('statcard.prs'),
206
+ value: totalPRs,
207
+ id: 'prs',
208
+ };
209
+ if (show.includes('prs_merged')) {
210
+ STATS['prs_merged'] = {
211
+ icon: icons.prs_merged,
212
+ label: i18n.t('statcard.prs-merged'),
213
+ value: totalPRsMerged,
214
+ id: 'prs_merged',
215
+ };
216
+ }
217
+ if (show.includes('prs_merged_percentage')) {
218
+ STATS['prs_merged_percentage'] = {
219
+ icon: icons.prs_merged_percentage,
220
+ label: i18n.t('statcard.prs-merged-percentage'),
221
+ value: mergedPRsPercentage.toFixed(number_precision !== undefined && Number.isFinite(number_precision)
222
+ ? clampValue(number_precision, 0, 2)
223
+ : 2),
224
+ id: 'prs_merged_percentage',
225
+ unitSymbol: '%',
226
+ };
227
+ }
228
+ if (show.includes('reviews')) {
229
+ STATS['reviews'] = {
230
+ icon: icons.reviews,
231
+ label: i18n.t('statcard.reviews'),
232
+ value: totalReviews,
233
+ id: 'reviews',
234
+ };
235
+ }
236
+ STATS['issues'] = {
237
+ icon: icons.issues,
238
+ label: i18n.t('statcard.issues'),
239
+ value: totalIssues,
240
+ id: 'issues',
241
+ };
242
+ if (show.includes('discussions_started')) {
243
+ STATS['discussions_started'] = {
244
+ icon: icons.discussions_started,
245
+ label: i18n.t('statcard.discussions-started'),
246
+ value: totalDiscussionsStarted,
247
+ id: 'discussions_started',
248
+ };
249
+ }
250
+ if (show.includes('discussions_answered')) {
251
+ STATS['discussions_answered'] = {
252
+ icon: icons.discussions_answered,
253
+ label: i18n.t('statcard.discussions-answered'),
254
+ value: totalDiscussionsAnswered,
255
+ id: 'discussions_answered',
256
+ };
257
+ }
258
+ const repoFilter = encodeURIComponent(buildSearchFilter(repo, owner));
259
+ const encodedUsername = encodeURIComponent(username ?? '');
260
+ if (show.includes('prs_authored')) {
261
+ STATS['prs_authored'] = {
262
+ icon: icons.prs,
263
+ label: i18n.t('statcard.prs-authored'),
264
+ value: totalPRsAuthored,
265
+ id: 'prs_authored',
266
+ link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&amp;type=pullrequests`,
267
+ };
268
+ }
269
+ if (show.includes('prs_commented')) {
270
+ STATS['prs_commented'] = {
271
+ icon: icons.comments,
272
+ label: i18n.t('statcard.prs-commented'),
273
+ value: totalPRsCommented,
274
+ id: 'prs_commented',
275
+ link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=pullrequests`,
276
+ };
277
+ }
278
+ if (show.includes('prs_reviewed')) {
279
+ STATS['prs_reviewed'] = {
280
+ icon: icons.reviews,
281
+ label: i18n.t('statcard.prs-reviewed'),
282
+ value: totalPRsReviewed,
283
+ id: 'prs_reviewed',
284
+ link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=pullrequests`,
285
+ };
286
+ }
287
+ if (show.includes('issues_authored')) {
288
+ STATS['issues_authored'] = {
289
+ icon: icons.issues,
290
+ label: i18n.t('statcard.issues-authored'),
291
+ value: totalIssuesAuthored,
292
+ id: 'issues_authored',
293
+ link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&amp;type=issues`,
294
+ };
295
+ }
296
+ if (show.includes('issues_commented')) {
297
+ STATS['issues_commented'] = {
298
+ icon: icons.discussions_started,
299
+ label: i18n.t('statcard.issues-commented'),
300
+ value: totalIssuesCommented,
301
+ id: 'issues_commented',
302
+ link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&amp;type=issues`,
303
+ };
304
+ }
305
+ STATS['contribs'] = {
306
+ icon: icons.contribs,
307
+ label: i18n.t('statcard.contribs'),
308
+ value: contributedTo,
309
+ id: 'contribs',
310
+ };
311
+ if (show.includes('all_time_contribs')) {
312
+ STATS['all_time_contribs'] = {
313
+ icon: icons.contribs,
314
+ label: i18n.t('statcard.all-time-contribs'),
315
+ value: allTimeContributedTo,
316
+ id: 'all_time_contribs',
317
+ };
318
+ }
319
+ const isLongLocale = locale ? LONG_LOCALES.includes(locale) : false;
320
+ // check if all used labels are short
321
+ const longLabels = Object.entries(STATS)
322
+ .filter(([key]) => !hide.includes(key))
323
+ .some(([, stat]) => stat.label.length > 18);
324
+ // filter out hidden stats defined by user & create the text nodes
325
+ const statItems = Object.entries(STATS)
326
+ .filter(([key]) => !hide.includes(key))
327
+ // pass index so that we can calculate the line spacing
328
+ .map(([, stat], index) => createTextNode({
329
+ icon: stat.icon,
330
+ label: stat.label,
331
+ value: stat.value,
332
+ id: stat.id,
333
+ unitSymbol: stat.unitSymbol,
334
+ index,
335
+ showIcons: show_icons,
336
+ shiftValuePos: 29.01 + (longLabels ? 50 : 0) + (isLongLocale ? 50 : 0),
337
+ bold: text_bold,
338
+ numberFormat: number_format,
339
+ numberPrecision: number_precision,
340
+ link: stat.link,
341
+ }));
342
+ if (statItems.length === 0 && hide_rank) {
343
+ throw new CardError('Could not render stats card.', {
344
+ code: 'invalid_param',
345
+ secondaryMessage: 'Either stats or rank are required.',
346
+ });
347
+ }
348
+ // Calculate the card height depending on how many items there are
349
+ // but if rank circle is visible clamp the minimum height to `150`
350
+ const height = Math.max(45 + (statItems.length + 1) * lheight, hide_rank ? 0 : statItems.length ? 150 : 180);
351
+ // the lower the user's percentile the better
352
+ const progress = 100 - rank.percentile;
353
+ const calculateTextWidth = () => {
354
+ return measureText(custom_title
355
+ ? custom_title
356
+ : statItems.length
357
+ ? i18n.t('statcard.title')
358
+ : i18n.t('statcard.ranktitle'));
359
+ };
360
+ /*
361
+ When hide_rank=true, the minimum card width is 270 px + the title length and padding.
362
+ When hide_rank=false, the minimum card_width is 340 px + the icon width (if show_icons=true).
363
+ Numbers are picked by looking at existing dimensions on production.
364
+ */
365
+ const iconWidth = show_icons && statItems.length ? 16 + /* padding */ 1 : 0;
366
+ const minCardWidth = (hide_rank
367
+ ? clampValue(50 /* padding */ + calculateTextWidth() * 2, CARD_MIN_WIDTH, Infinity)
368
+ : statItems.length
369
+ ? RANK_CARD_MIN_WIDTH
370
+ : RANK_ONLY_CARD_MIN_WIDTH) + iconWidth;
371
+ const defaultCardWidth = (hide_rank
372
+ ? CARD_DEFAULT_WIDTH
373
+ : statItems.length
374
+ ? RANK_CARD_DEFAULT_WIDTH
375
+ : RANK_ONLY_CARD_DEFAULT_WIDTH) + iconWidth;
376
+ const width = card_width
377
+ ? isNaN(card_width)
378
+ ? Math.max(defaultCardWidth, minCardWidth)
379
+ : card_width
380
+ : Math.max(defaultCardWidth, minCardWidth);
381
+ const card = new Card({
382
+ customTitle: custom_title,
383
+ defaultTitle: statItems.length ? i18n.t('statcard.title') : i18n.t('statcard.ranktitle'),
384
+ width,
385
+ height,
386
+ border_radius,
387
+ colors: { light: lightColors, dark: darkColors },
388
+ });
389
+ card.setHideBorder(hide_border);
390
+ card.setHideTitle(hide_title);
391
+ const cardStyles = ({ ringColor, textColor, iconColor }) => getStyles({ ringColor, textColor, iconColor, show_icons, progress });
392
+ card.setCSS({ light: cardStyles, dark: cardStyles });
393
+ if (disable_animations) {
394
+ card.disableAnimations();
395
+ }
396
+ /**
397
+ * Calculates the right rank circle translation values such that the rank circle
398
+ * keeps respecting the following padding:
399
+ *
400
+ * width > RANK_CARD_DEFAULT_WIDTH: The default right padding of 70 px will be used.
401
+ * width < RANK_CARD_DEFAULT_WIDTH: The left and right padding will be enlarged
402
+ * equally from a certain minimum at RANK_CARD_MIN_WIDTH.
403
+ *
404
+ * @returns Rank circle translation value.
405
+ */
406
+ const calculateRankXTranslation = () => {
407
+ if (statItems.length) {
408
+ const minXTranslation = RANK_CARD_MIN_WIDTH + iconWidth - 70;
409
+ if (width > RANK_CARD_DEFAULT_WIDTH) {
410
+ const xMaxExpansion = minXTranslation + (450 - minCardWidth) / 2;
411
+ return xMaxExpansion + width - RANK_CARD_DEFAULT_WIDTH;
412
+ }
413
+ else {
414
+ return minXTranslation + (width - minCardWidth) / 2;
415
+ }
416
+ }
417
+ else {
418
+ return width / 2 + 20 - 10;
419
+ }
420
+ };
421
+ // Conditionally rendered elements
422
+ const rankCircle = hide_rank
423
+ ? ''
424
+ : `<g data-testid="rank-circle"
425
+ transform="translate(${calculateRankXTranslation()}, ${height / 2 - 50})">
426
+ <circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
427
+ <circle class="rank-circle" cx="-10" cy="8" r="40" />
428
+ <g class="rank-text">
429
+ ${rankIcon(rank_icon, rank.level, rank.percentile)}
430
+ </g>
431
+ </g>`;
432
+ // Accessibility Labels
433
+ const labels = Object.entries(STATS)
434
+ .filter(([key]) => !hide.includes(key))
435
+ .map(([key, stat]) => {
436
+ if (key === 'commits') {
437
+ return `${i18n.t('statcard.commits')} ${getTotalCommitsYearLabel(include_all_commits, commits_year, i18n)} : ${stat.value}`;
438
+ }
439
+ return `${stat.label}: ${stat.value}`;
440
+ })
441
+ .join(', ');
442
+ card.setAccessibilityLabel({
443
+ title: `${card.title}, Rank: ${rank.level}`,
444
+ desc: labels,
445
+ });
446
+ return card.render(`
447
+ ${rankCircle}
448
+ <svg x="0" y="0">
449
+ ${flexLayout({
450
+ items: statItems,
451
+ gap: lheight,
452
+ direction: 'column',
453
+ }).join('')}
454
+ </svg>
455
+ `);
456
+ };
457
+ export { RANK_ICONS, renderStatsCard };
@@ -0,0 +1,153 @@
1
+ import type { Lang, TopLangData } from '../fetchers/types.js';
2
+ import type { CardOptions, CommonCardOptions } from './options.js';
3
+ declare const MIN_CARD_WIDTH = 280;
4
+ /** Layouts the card can draw; the api validates `layout` against this. */
5
+ declare const TOP_LANG_LAYOUTS: readonly ["compact", "normal", "donut", "donut-vertical", "pie"];
6
+ type TopLangLayout = (typeof TOP_LANG_LAYOUTS)[number];
7
+ /** How a language's value is shown; the api validates `stats_format` against this. */
8
+ declare const TOP_LANG_STATS_FORMATS: readonly ["percentages", "bytes"];
9
+ type TopLangStatsFormat = (typeof TOP_LANG_STATS_FORMATS)[number];
10
+ interface TopLangOptions extends CommonCardOptions {
11
+ locale: string;
12
+ hide_title: boolean;
13
+ card_width: number;
14
+ hide: Array<string>;
15
+ layout: TopLangLayout;
16
+ custom_title: string;
17
+ langs_count: number;
18
+ disable_animations: boolean;
19
+ hide_progress: boolean;
20
+ hide_values: boolean;
21
+ prog_bar_bg_color: string;
22
+ stats_format: TopLangStatsFormat;
23
+ }
24
+ /**
25
+ * Retrieves the programming language whose name is the longest.
26
+ *
27
+ * @param arr Array of programming languages.
28
+ * @returns Longest programming language object.
29
+ */
30
+ declare const getLongestLang: (arr: Array<Lang>) => Pick<Lang, "name" | "size" | "color">;
31
+ /**
32
+ * Convert degrees to radians.
33
+ *
34
+ * @param angleInDegrees Angle in degrees.
35
+ * @returns Angle in radians.
36
+ */
37
+ declare const degreesToRadians: (angleInDegrees: number) => number;
38
+ /**
39
+ * Convert radians to degrees.
40
+ *
41
+ * @param angleInRadians Angle in radians.
42
+ * @returns Angle in degrees.
43
+ */
44
+ declare const radiansToDegrees: (angleInRadians: number) => number;
45
+ /**
46
+ * Convert polar coordinates to cartesian coordinates.
47
+ *
48
+ * @param centerX Center x coordinate.
49
+ * @param centerY Center y coordinate.
50
+ * @param radius Radius of the circle.
51
+ * @param angleInDegrees Angle in degrees.
52
+ * @returns Cartesian coordinates.
53
+ */
54
+ declare const polarToCartesian: (centerX: number, centerY: number, radius: number, angleInDegrees: number) => {
55
+ x: number;
56
+ y: number;
57
+ };
58
+ /**
59
+ * Convert cartesian coordinates to polar coordinates.
60
+ *
61
+ * @param centerX Center x coordinate.
62
+ * @param centerY Center y coordinate.
63
+ * @param x Point x coordinate.
64
+ * @param y Point y coordinate.
65
+ * @returns Polar coordinates.
66
+ */
67
+ declare const cartesianToPolar: (centerX: number, centerY: number, x: number, y: number) => {
68
+ radius: number;
69
+ angleInDegrees: number;
70
+ };
71
+ /**
72
+ * Calculates length of circle.
73
+ *
74
+ * @param radius Radius of the circle.
75
+ * @returns The length of the circle.
76
+ */
77
+ declare const getCircleLength: (radius: number) => number;
78
+ /**
79
+ * Calculates height for the compact layout.
80
+ *
81
+ * @param totalLangs Total number of languages.
82
+ * @returns Card height.
83
+ */
84
+ declare const calculateCompactLayoutHeight: (totalLangs: number) => number;
85
+ /**
86
+ * Calculates height for the normal layout.
87
+ *
88
+ * @param totalLangs Total number of languages.
89
+ * @returns Card height.
90
+ */
91
+ declare const calculateNormalLayoutHeight: (totalLangs: number) => number;
92
+ /**
93
+ * Calculates height for the donut layout.
94
+ *
95
+ * @param totalLangs Total number of languages.
96
+ * @returns Card height.
97
+ */
98
+ declare const calculateDonutLayoutHeight: (totalLangs: number) => number;
99
+ /**
100
+ * Calculates height for the donut vertical layout.
101
+ *
102
+ * @param totalLangs Total number of languages.
103
+ * @returns Card height.
104
+ */
105
+ declare const calculateDonutVerticalLayoutHeight: (totalLangs: number) => number;
106
+ /**
107
+ * Calculates height for the pie layout.
108
+ *
109
+ * @param totalLangs Total number of languages.
110
+ * @returns Card height.
111
+ */
112
+ declare const calculatePieLayoutHeight: (totalLangs: number) => number;
113
+ /**
114
+ * Calculates the center translation needed to keep the donut chart centred.
115
+ *
116
+ * @param totalLangs Total number of languages.
117
+ * @returns Donut center translation.
118
+ */
119
+ declare const donutCenterTranslation: (totalLangs: number) => number;
120
+ /**
121
+ * Trim top languages to lang_count while also hiding certain languages.
122
+ *
123
+ * @param topLangs Top languages.
124
+ * @param langs_count Number of languages to show.
125
+ * @param hide Languages to hide.
126
+ * @returns Trimmed top languages and total size.
127
+ */
128
+ declare const trimTopLanguages: (topLangs: TopLangData, langs_count: number, hide?: Array<string>) => {
129
+ langs: Array<Lang>;
130
+ totalLanguageSize: number;
131
+ };
132
+ /**
133
+ * Get default languages count for provided card layout.
134
+ *
135
+ * @param props Function properties.
136
+ * @param props.layout Input layout string.
137
+ * @param props.hide_progress Input hide_progress parameter value.
138
+ * @returns Default languages count for input layout.
139
+ */
140
+ declare const getDefaultLanguagesCountByLayout: ({ layout, hide_progress, }: {
141
+ layout?: TopLangLayout | undefined;
142
+ hide_progress?: boolean | undefined;
143
+ }) => number;
144
+ /**
145
+ * Renders card that display user's most frequently used programming languages.
146
+ *
147
+ * @param topLangs User's most frequently used programming languages.
148
+ * @param options Card options.
149
+ * @returns Language card SVG object.
150
+ */
151
+ declare const renderTopLanguages: (topLangs: TopLangData, options?: CardOptions<TopLangOptions>) => string;
152
+ export { getLongestLang, degreesToRadians, radiansToDegrees, polarToCartesian, cartesianToPolar, getCircleLength, calculateCompactLayoutHeight, calculateNormalLayoutHeight, calculateDonutLayoutHeight, calculateDonutVerticalLayoutHeight, calculatePieLayoutHeight, donutCenterTranslation, trimTopLanguages, renderTopLanguages, MIN_CARD_WIDTH, getDefaultLanguagesCountByLayout, TOP_LANG_LAYOUTS, TOP_LANG_STATS_FORMATS, };
153
+ //# sourceMappingURL=top-languages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"top-languages.d.ts","sourceRoot":"","sources":["../../src/cards/top-languages.ts"],"names":[],"mappings":"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"}