@stats-organization/github-readme-stats-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.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/build/api/gist.d.ts +19 -0
- package/build/api/gist.d.ts.map +1 -0
- package/build/api/gist.js +77 -0
- package/build/api/index.d.ts +37 -0
- package/build/api/index.d.ts.map +1 -0
- package/build/api/index.js +115 -0
- package/build/api/pin.d.ts +27 -0
- package/build/api/pin.d.ts.map +1 -0
- package/build/api/pin.js +104 -0
- package/build/api/top-langs.d.ts +31 -0
- package/build/api/top-langs.d.ts.map +1 -0
- package/build/api/top-langs.js +121 -0
- package/build/api/wakatime.d.ts +28 -0
- package/build/api/wakatime.d.ts.map +1 -0
- package/build/api/wakatime.js +85 -0
- package/build/calculateRank.d.ts +28 -0
- package/build/calculateRank.d.ts.map +1 -0
- package/build/calculateRank.js +63 -0
- package/build/cards/gist.d.ts +21 -0
- package/build/cards/gist.d.ts.map +1 -0
- package/build/cards/gist.js +124 -0
- package/build/cards/repo.d.ts +21 -0
- package/build/cards/repo.d.ts.map +1 -0
- package/build/cards/repo.js +264 -0
- package/build/cards/stats.d.ts +49 -0
- package/build/cards/stats.d.ts.map +1 -0
- package/build/cards/stats.js +527 -0
- package/build/cards/top-languages.d.ts +143 -0
- package/build/cards/top-languages.d.ts.map +1 -0
- package/build/cards/top-languages.js +795 -0
- package/build/cards/wakatime.d.ts +16 -0
- package/build/cards/wakatime.d.ts.map +1 -0
- package/build/cards/wakatime.js +387 -0
- package/build/common/Card.d.ts +109 -0
- package/build/common/Card.d.ts.map +1 -0
- package/build/common/Card.js +241 -0
- package/build/common/I18n.d.ts +26 -0
- package/build/common/I18n.d.ts.map +1 -0
- package/build/common/I18n.js +34 -0
- package/build/common/color.d.ts +53 -0
- package/build/common/color.d.ts.map +1 -0
- package/build/common/color.js +92 -0
- package/build/common/config.d.ts +3 -0
- package/build/common/config.d.ts.map +1 -0
- package/build/common/config.js +69 -0
- package/build/common/constants.d.ts +6 -0
- package/build/common/constants.d.ts.map +1 -0
- package/build/common/constants.js +7 -0
- package/build/common/error.d.ts +53 -0
- package/build/common/error.d.ts.map +1 -0
- package/build/common/error.js +72 -0
- package/build/common/fmt.d.ts +27 -0
- package/build/common/fmt.d.ts.map +1 -0
- package/build/common/fmt.js +66 -0
- package/build/common/html.d.ts +10 -0
- package/build/common/html.d.ts.map +1 -0
- package/build/common/html.js +18 -0
- package/build/common/http.d.ts +9 -0
- package/build/common/http.d.ts.map +1 -0
- package/build/common/http.js +18 -0
- package/build/common/icons.d.ts +26 -0
- package/build/common/icons.d.ts.map +1 -0
- package/build/common/icons.js +77 -0
- package/build/common/languageColors.json +667 -0
- package/build/common/log.d.ts +9 -0
- package/build/common/log.d.ts.map +1 -0
- package/build/common/log.js +8 -0
- package/build/common/ops.d.ts +65 -0
- package/build/common/ops.d.ts.map +1 -0
- package/build/common/ops.js +137 -0
- package/build/common/render.d.ts +155 -0
- package/build/common/render.d.ts.map +1 -0
- package/build/common/render.js +361 -0
- package/build/common/retryer.d.ts +22 -0
- package/build/common/retryer.d.ts.map +1 -0
- package/build/common/retryer.js +86 -0
- package/build/fetchers/gist.d.ts +26 -0
- package/build/fetchers/gist.d.ts.map +1 -0
- package/build/fetchers/gist.js +99 -0
- package/build/fetchers/repo.d.ts +16 -0
- package/build/fetchers/repo.d.ts.map +1 -0
- package/build/fetchers/repo.js +116 -0
- package/build/fetchers/stats.d.ts +22 -0
- package/build/fetchers/stats.d.ts.map +1 -0
- package/build/fetchers/stats.js +339 -0
- package/build/fetchers/top-languages.d.ts +20 -0
- package/build/fetchers/top-languages.d.ts.map +1 -0
- package/build/fetchers/top-languages.js +139 -0
- package/build/fetchers/wakatime.d.ts +11 -0
- package/build/fetchers/wakatime.d.ts.map +1 -0
- package/build/fetchers/wakatime.js +25 -0
- package/build/index.d.ts +20 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +19 -0
- package/build/themes/index.d.ts +469 -0
- package/build/themes/index.d.ts.map +1 -0
- package/build/themes/index.js +468 -0
- package/build/translations.d.ts +533 -0
- package/build/translations.d.ts.map +1 -0
- package/build/translations.js +1140 -0
- package/package.json +94 -0
- package/src/api/gist.js +99 -0
- package/src/api/index.js +185 -0
- package/src/api/pin.js +146 -0
- package/src/api/top-langs.js +168 -0
- package/src/api/wakatime.js +113 -0
- package/src/calculateRank.js +86 -0
- package/src/cards/gist.js +187 -0
- package/src/cards/repo.js +365 -0
- package/src/cards/stats.js +673 -0
- package/src/cards/top-languages.js +1023 -0
- package/src/cards/types.d.ts +78 -0
- package/src/cards/wakatime.js +471 -0
- package/src/common/Card.js +275 -0
- package/src/common/I18n.js +42 -0
- package/src/common/color.js +145 -0
- package/src/common/config.js +78 -0
- package/src/common/constants.js +9 -0
- package/src/common/error.js +90 -0
- package/src/common/fmt.js +80 -0
- package/src/common/html.js +22 -0
- package/src/common/http.js +21 -0
- package/src/common/icons.js +81 -0
- package/src/common/languageColors.json +667 -0
- package/src/common/log.ts +12 -0
- package/src/common/ops.js +172 -0
- package/src/common/render.js +442 -0
- package/src/common/retryer.js +104 -0
- package/src/fetchers/gist.js +114 -0
- package/src/fetchers/repo.js +165 -0
- package/src/fetchers/stats.js +478 -0
- package/src/fetchers/top-languages.js +177 -0
- package/src/fetchers/types.d.ts +128 -0
- package/src/fetchers/wakatime.js +37 -0
- package/src/index.ts +25 -0
- package/src/themes/README.md +229 -0
- package/src/themes/index.ts +476 -0
- package/src/translations.js +1156 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { Card } from "../common/Card.js";
|
|
3
|
+
import { I18n } from "../common/I18n.js";
|
|
4
|
+
import { getCardColors } from "../common/color.js";
|
|
5
|
+
import { CustomError } from "../common/error.js";
|
|
6
|
+
import { kFormatter } from "../common/fmt.js";
|
|
7
|
+
import { icons, rankIcon } from "../common/icons.js";
|
|
8
|
+
import { buildSearchFilter, clampValue } from "../common/ops.js";
|
|
9
|
+
import { flexLayout, measureText } from "../common/render.js";
|
|
10
|
+
import { statCardLocales, wakatimeCardLocales } from "../translations.js";
|
|
11
|
+
const CARD_MIN_WIDTH = 287;
|
|
12
|
+
const CARD_DEFAULT_WIDTH = 287;
|
|
13
|
+
const RANK_CARD_MIN_WIDTH = 420;
|
|
14
|
+
const RANK_CARD_DEFAULT_WIDTH = 450;
|
|
15
|
+
const RANK_ONLY_CARD_MIN_WIDTH = 290;
|
|
16
|
+
const RANK_ONLY_CARD_DEFAULT_WIDTH = 290;
|
|
17
|
+
/**
|
|
18
|
+
* Long locales that need more space for text. Keep sorted alphabetically.
|
|
19
|
+
*
|
|
20
|
+
* @type {(keyof typeof wakatimeCardLocales["wakatimecard.title"])[]}
|
|
21
|
+
*/
|
|
22
|
+
const LONG_LOCALES = [
|
|
23
|
+
"az",
|
|
24
|
+
"bg",
|
|
25
|
+
"cs",
|
|
26
|
+
"de",
|
|
27
|
+
"el",
|
|
28
|
+
"es",
|
|
29
|
+
"fil",
|
|
30
|
+
"fi",
|
|
31
|
+
"fr",
|
|
32
|
+
"hu",
|
|
33
|
+
"id",
|
|
34
|
+
"ja",
|
|
35
|
+
"ml",
|
|
36
|
+
"my",
|
|
37
|
+
"nl",
|
|
38
|
+
"pl",
|
|
39
|
+
"pt-br",
|
|
40
|
+
"pt-pt",
|
|
41
|
+
"ru",
|
|
42
|
+
"sr",
|
|
43
|
+
"sr-latn",
|
|
44
|
+
"sw",
|
|
45
|
+
"ta",
|
|
46
|
+
"uk-ua",
|
|
47
|
+
"uz",
|
|
48
|
+
"zh-tw",
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Create a stats card text item.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} params Object that contains the createTextNode parameters.
|
|
54
|
+
* @param {string} params.icon The icon to display.
|
|
55
|
+
* @param {string} params.label The label to display.
|
|
56
|
+
* @param {number} params.value The value to display.
|
|
57
|
+
* @param {string} params.id The id of the stat.
|
|
58
|
+
* @param {string=} params.unitSymbol The unit symbol of the stat.
|
|
59
|
+
* @param {number} params.index The index of the stat.
|
|
60
|
+
* @param {boolean} params.showIcons Whether to show icons.
|
|
61
|
+
* @param {number} params.shiftValuePos Number of pixels the value has to be shifted to the right.
|
|
62
|
+
* @param {boolean} params.bold Whether to bold the label.
|
|
63
|
+
* @param {string} params.numberFormat The format of numbers on card.
|
|
64
|
+
* @param {number=} params.numberPrecision The precision of numbers on card.
|
|
65
|
+
* @param {string} params.link Url to link to.
|
|
66
|
+
* @param {number} params.labelXOffset horizontal offset for label.
|
|
67
|
+
* @returns {string} The stats card text item SVG object.
|
|
68
|
+
*/
|
|
69
|
+
const createTextNode = ({ icon, label, value, id, unitSymbol, index, showIcons, shiftValuePos, bold, numberFormat, numberPrecision, link, labelXOffset = 25, }) => {
|
|
70
|
+
const precision = typeof numberPrecision === "number" && !isNaN(numberPrecision)
|
|
71
|
+
? clampValue(numberPrecision, 0, 2)
|
|
72
|
+
: undefined;
|
|
73
|
+
const kValue = numberFormat.toLowerCase() === "long" || id === "prs_merged_percentage"
|
|
74
|
+
? value
|
|
75
|
+
: kFormatter(value, precision);
|
|
76
|
+
const staggerDelay = (index + 3) * 150;
|
|
77
|
+
const labelOffset = showIcons ? `x="${labelXOffset}"` : "";
|
|
78
|
+
const iconSvg = showIcons
|
|
79
|
+
? `
|
|
80
|
+
<svg data-testid="icon" class="icon" viewBox="0 0 16 16" version="1.1" width="16" height="16">
|
|
81
|
+
${icon}
|
|
82
|
+
</svg>
|
|
83
|
+
`
|
|
84
|
+
: "";
|
|
85
|
+
return (`
|
|
86
|
+
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">` +
|
|
87
|
+
(link ? `<a href="${link}">` : "") +
|
|
88
|
+
`
|
|
89
|
+
${iconSvg}
|
|
90
|
+
<text class="stat ${bold ? " bold" : "not_bold"}" ${labelOffset} y="12.5">${label}:</text>
|
|
91
|
+
<text
|
|
92
|
+
class="stat ${bold ? " bold" : "not_bold"}"
|
|
93
|
+
x="${(showIcons ? 140 : 120) + (bold ? 5 : 0) + shiftValuePos}"
|
|
94
|
+
y="12.5"
|
|
95
|
+
data-testid="${id}"
|
|
96
|
+
>${kValue}${unitSymbol ? ` ${unitSymbol}` : ""}</text>` +
|
|
97
|
+
(link ? "</a>" : "") +
|
|
98
|
+
`
|
|
99
|
+
</g>
|
|
100
|
+
`);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Calculates progress along the boundary of the circle, i.e. its circumference.
|
|
104
|
+
*
|
|
105
|
+
* @param {number} value The rank value to calculate progress for.
|
|
106
|
+
* @returns {number} Progress value.
|
|
107
|
+
*/
|
|
108
|
+
const calculateCircleProgress = (value) => {
|
|
109
|
+
const radius = 40;
|
|
110
|
+
const c = Math.PI * (radius * 2);
|
|
111
|
+
if (value < 0) {
|
|
112
|
+
value = 0;
|
|
113
|
+
}
|
|
114
|
+
if (value > 100) {
|
|
115
|
+
value = 100;
|
|
116
|
+
}
|
|
117
|
+
return ((100 - value) / 100) * c;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Retrieves the animation to display progress along the circumference of circle
|
|
121
|
+
* from the beginning to the given value in a clockwise direction.
|
|
122
|
+
*
|
|
123
|
+
* @param {{progress: number}} progress The progress value to animate to.
|
|
124
|
+
* @returns {string} Progress animation css.
|
|
125
|
+
*/
|
|
126
|
+
const getProgressAnimation = ({ progress }) => {
|
|
127
|
+
return `
|
|
128
|
+
@keyframes rankAnimation {
|
|
129
|
+
from {
|
|
130
|
+
stroke-dashoffset: ${calculateCircleProgress(0)};
|
|
131
|
+
}
|
|
132
|
+
to {
|
|
133
|
+
stroke-dashoffset: ${calculateCircleProgress(progress)};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Retrieves CSS styles for a card.
|
|
140
|
+
*
|
|
141
|
+
* @param {Object} colors The colors to use for the card.
|
|
142
|
+
* @param {string} colors.titleColor The title color.
|
|
143
|
+
* @param {string} colors.textColor The text color.
|
|
144
|
+
* @param {string} colors.iconColor The icon color.
|
|
145
|
+
* @param {string} colors.ringColor The ring color.
|
|
146
|
+
* @param {boolean} colors.show_icons Whether to show icons.
|
|
147
|
+
* @param {number} colors.progress The progress value to animate to.
|
|
148
|
+
* @returns {string} Card CSS styles.
|
|
149
|
+
*/
|
|
150
|
+
const getStyles = ({
|
|
151
|
+
// eslint-disable-next-line no-unused-vars
|
|
152
|
+
titleColor, textColor, iconColor, ringColor, show_icons, progress, }) => {
|
|
153
|
+
return `
|
|
154
|
+
.stat {
|
|
155
|
+
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
|
|
156
|
+
}
|
|
157
|
+
@supports(-moz-appearance: auto) {
|
|
158
|
+
/* Selector detects Firefox */
|
|
159
|
+
.stat { font-size:12px; }
|
|
160
|
+
}
|
|
161
|
+
.stagger {
|
|
162
|
+
opacity: 0;
|
|
163
|
+
animation: fadeInAnimation 0.3s ease-in-out forwards;
|
|
164
|
+
}
|
|
165
|
+
.rank-text {
|
|
166
|
+
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
|
|
167
|
+
animation: scaleInAnimation 0.3s ease-in-out forwards;
|
|
168
|
+
}
|
|
169
|
+
.rank-percentile-header {
|
|
170
|
+
font-size: 14px;
|
|
171
|
+
}
|
|
172
|
+
.rank-percentile-text {
|
|
173
|
+
font-size: 16px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.not_bold { font-weight: 400 }
|
|
177
|
+
.bold { font-weight: 700 }
|
|
178
|
+
.icon {
|
|
179
|
+
fill: ${iconColor};
|
|
180
|
+
display: ${show_icons ? "block" : "none"};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.rank-circle-rim {
|
|
184
|
+
stroke: ${ringColor};
|
|
185
|
+
fill: none;
|
|
186
|
+
stroke-width: 6;
|
|
187
|
+
opacity: 0.2;
|
|
188
|
+
}
|
|
189
|
+
.rank-circle {
|
|
190
|
+
stroke: ${ringColor};
|
|
191
|
+
stroke-dasharray: 250;
|
|
192
|
+
fill: none;
|
|
193
|
+
stroke-width: 6;
|
|
194
|
+
stroke-linecap: round;
|
|
195
|
+
opacity: 0.8;
|
|
196
|
+
transform-origin: -10px 8px;
|
|
197
|
+
transform: rotate(-90deg);
|
|
198
|
+
animation: rankAnimation 1s forwards ease-in-out;
|
|
199
|
+
}
|
|
200
|
+
${getProgressAnimation({ progress })}
|
|
201
|
+
`;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Return the label for commits according to the selected options
|
|
205
|
+
*
|
|
206
|
+
* @param {boolean} include_all_commits Option to include all years
|
|
207
|
+
* @param {number|undefined} commits_year Option to include only selected year
|
|
208
|
+
* @param {I18n} i18n The I18n instance.
|
|
209
|
+
* @returns {string} The label corresponding to the options.
|
|
210
|
+
*/
|
|
211
|
+
const getTotalCommitsYearLabel = (include_all_commits, commits_year, i18n) => include_all_commits
|
|
212
|
+
? ""
|
|
213
|
+
: commits_year
|
|
214
|
+
? ` (${commits_year})`
|
|
215
|
+
: ` (${i18n.t("wakatimecard.lastyear")})`;
|
|
216
|
+
/**
|
|
217
|
+
* @typedef {import('../fetchers/types').StatsData} StatsData
|
|
218
|
+
* @typedef {import('./types').StatCardOptions} StatCardOptions
|
|
219
|
+
*/
|
|
220
|
+
/**
|
|
221
|
+
* Renders the stats card.
|
|
222
|
+
*
|
|
223
|
+
* @param {StatsData} stats The stats data.
|
|
224
|
+
* @param {Partial<StatCardOptions>} options The card options.
|
|
225
|
+
* @returns {string} The stats card SVG object.
|
|
226
|
+
*/
|
|
227
|
+
const renderStatsCard = (stats, options = {}, username, repo = [], owner = []) => {
|
|
228
|
+
const { name, totalStars, totalCommits, totalIssues, totalPRs, totalPRsMerged, mergedPRsPercentage, totalReviews, totalDiscussionsStarted, totalDiscussionsAnswered, contributedTo, totalPRsAuthored, totalPRsCommented, totalPRsReviewed, totalIssuesAuthored, totalIssuesCommented, rank, } = stats;
|
|
229
|
+
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, title_color, ring_color, icon_color, text_color, text_bold = true, bg_color, theme = "default", custom_title, border_radius, border_color, number_format = "short", number_precision, locale, disable_animations = false, rank_icon = "default", show = [], } = options;
|
|
230
|
+
const lheight = parseInt(String(line_height), 10);
|
|
231
|
+
// returns theme based colors with proper overrides and defaults
|
|
232
|
+
const { titleColor, iconColor, textColor, bgColor, borderColor, ringColor } = getCardColors({
|
|
233
|
+
title_color,
|
|
234
|
+
text_color,
|
|
235
|
+
icon_color,
|
|
236
|
+
bg_color,
|
|
237
|
+
border_color,
|
|
238
|
+
ring_color,
|
|
239
|
+
theme,
|
|
240
|
+
});
|
|
241
|
+
const apostrophe = /s$/i.test(name.trim()) ? "" : "s";
|
|
242
|
+
const i18n = new I18n({
|
|
243
|
+
locale,
|
|
244
|
+
translations: {
|
|
245
|
+
...statCardLocales({ name, apostrophe }),
|
|
246
|
+
...wakatimeCardLocales,
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
// Meta data for creating text nodes with createTextNode function
|
|
250
|
+
const STATS = {};
|
|
251
|
+
STATS.stars = {
|
|
252
|
+
icon: icons.star,
|
|
253
|
+
label: i18n.t("statcard.totalstars"),
|
|
254
|
+
value: totalStars,
|
|
255
|
+
id: "stars",
|
|
256
|
+
};
|
|
257
|
+
STATS.commits = {
|
|
258
|
+
icon: icons.commits,
|
|
259
|
+
label: `${i18n.t("statcard.commits")}${getTotalCommitsYearLabel(include_all_commits, commits_year, i18n)}`,
|
|
260
|
+
value: totalCommits,
|
|
261
|
+
id: "commits",
|
|
262
|
+
};
|
|
263
|
+
STATS.prs = {
|
|
264
|
+
icon: icons.prs,
|
|
265
|
+
label: i18n.t("statcard.prs"),
|
|
266
|
+
value: totalPRs,
|
|
267
|
+
id: "prs",
|
|
268
|
+
};
|
|
269
|
+
if (show.includes("prs_merged")) {
|
|
270
|
+
STATS.prs_merged = {
|
|
271
|
+
icon: icons.prs_merged,
|
|
272
|
+
label: i18n.t("statcard.prs-merged"),
|
|
273
|
+
value: totalPRsMerged,
|
|
274
|
+
id: "prs_merged",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
if (show.includes("prs_merged_percentage")) {
|
|
278
|
+
STATS.prs_merged_percentage = {
|
|
279
|
+
icon: icons.prs_merged_percentage,
|
|
280
|
+
label: i18n.t("statcard.prs-merged-percentage"),
|
|
281
|
+
value: mergedPRsPercentage.toFixed(typeof number_precision === "number" && !isNaN(number_precision)
|
|
282
|
+
? clampValue(number_precision, 0, 2)
|
|
283
|
+
: 2),
|
|
284
|
+
id: "prs_merged_percentage",
|
|
285
|
+
unitSymbol: "%",
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (show.includes("reviews")) {
|
|
289
|
+
STATS.reviews = {
|
|
290
|
+
icon: icons.reviews,
|
|
291
|
+
label: i18n.t("statcard.reviews"),
|
|
292
|
+
value: totalReviews,
|
|
293
|
+
id: "reviews",
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
STATS.issues = {
|
|
297
|
+
icon: icons.issues,
|
|
298
|
+
label: i18n.t("statcard.issues"),
|
|
299
|
+
value: totalIssues,
|
|
300
|
+
id: "issues",
|
|
301
|
+
};
|
|
302
|
+
if (show.includes("discussions_started")) {
|
|
303
|
+
STATS.discussions_started = {
|
|
304
|
+
icon: icons.discussions_started,
|
|
305
|
+
label: i18n.t("statcard.discussions-started"),
|
|
306
|
+
value: totalDiscussionsStarted,
|
|
307
|
+
id: "discussions_started",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (show.includes("discussions_answered")) {
|
|
311
|
+
STATS.discussions_answered = {
|
|
312
|
+
icon: icons.discussions_answered,
|
|
313
|
+
label: i18n.t("statcard.discussions-answered"),
|
|
314
|
+
value: totalDiscussionsAnswered,
|
|
315
|
+
id: "discussions_answered",
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
let repoFilter = encodeURIComponent(buildSearchFilter(repo, owner));
|
|
319
|
+
if (show.includes("prs_authored")) {
|
|
320
|
+
STATS.prs_authored = {
|
|
321
|
+
icon: icons.prs,
|
|
322
|
+
label: i18n.t("statcard.prs-authored"),
|
|
323
|
+
value: totalPRsAuthored,
|
|
324
|
+
id: "prs_authored",
|
|
325
|
+
link: `https://github.com/search?q=${repoFilter}author%3A${username}&type=pullrequests`,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
if (show.includes("prs_commented")) {
|
|
329
|
+
STATS.prs_commented = {
|
|
330
|
+
icon: icons.comments,
|
|
331
|
+
label: i18n.t("statcard.prs-commented"),
|
|
332
|
+
value: totalPRsCommented,
|
|
333
|
+
id: "prs_commented",
|
|
334
|
+
link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&type=pullrequests`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (show.includes("prs_reviewed")) {
|
|
338
|
+
STATS.prs_reviewed = {
|
|
339
|
+
icon: icons.reviews,
|
|
340
|
+
label: i18n.t("statcard.prs-reviewed"),
|
|
341
|
+
value: totalPRsReviewed,
|
|
342
|
+
id: "prs_reviewed",
|
|
343
|
+
link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${username}+-author%3A${username}&type=pullrequests`,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (show.includes("issues_authored")) {
|
|
347
|
+
STATS.issues_authored = {
|
|
348
|
+
icon: icons.issues,
|
|
349
|
+
label: i18n.t("statcard.issues-authored"),
|
|
350
|
+
value: totalIssuesAuthored,
|
|
351
|
+
id: "issues_authored",
|
|
352
|
+
link: `https://github.com/search?q=${repoFilter}author%3A${username}&type=issues`,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (show.includes("issues_commented")) {
|
|
356
|
+
STATS.issues_commented = {
|
|
357
|
+
icon: icons.discussions_started,
|
|
358
|
+
label: i18n.t("statcard.issues-commented"),
|
|
359
|
+
value: totalIssuesCommented,
|
|
360
|
+
id: "issues_commented",
|
|
361
|
+
link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&type=issues`,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
STATS.contribs = {
|
|
365
|
+
icon: icons.contribs,
|
|
366
|
+
label: i18n.t("statcard.contribs"),
|
|
367
|
+
value: contributedTo,
|
|
368
|
+
id: "contribs",
|
|
369
|
+
};
|
|
370
|
+
// @ts-ignore
|
|
371
|
+
const isLongLocale = locale ? LONG_LOCALES.includes(locale) : false;
|
|
372
|
+
// check if all used labels are short
|
|
373
|
+
const longLabels = Object.keys(STATS)
|
|
374
|
+
.filter((key) => !hide.includes(key))
|
|
375
|
+
.filter((key) => STATS[key].label.length > 18).length > 0;
|
|
376
|
+
// filter out hidden stats defined by user & create the text nodes
|
|
377
|
+
const statItems = Object.keys(STATS)
|
|
378
|
+
.filter((key) => !hide.includes(key))
|
|
379
|
+
.map((key, index) => {
|
|
380
|
+
// @ts-ignore
|
|
381
|
+
const stats = STATS[key];
|
|
382
|
+
// create the text nodes, and pass index so that we can calculate the line spacing
|
|
383
|
+
return createTextNode({
|
|
384
|
+
icon: stats.icon,
|
|
385
|
+
label: stats.label,
|
|
386
|
+
value: stats.value,
|
|
387
|
+
id: stats.id,
|
|
388
|
+
unitSymbol: stats.unitSymbol,
|
|
389
|
+
index,
|
|
390
|
+
showIcons: show_icons,
|
|
391
|
+
shiftValuePos: 29.01 + (longLabels ? 50 : 0) + (isLongLocale ? 50 : 0),
|
|
392
|
+
bold: text_bold,
|
|
393
|
+
numberFormat: number_format,
|
|
394
|
+
numberPrecision: number_precision,
|
|
395
|
+
link: STATS[key].link,
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
if (statItems.length === 0 && hide_rank) {
|
|
399
|
+
throw new CustomError("Could not render stats card.", "Either stats or rank are required.");
|
|
400
|
+
}
|
|
401
|
+
// Calculate the card height depending on how many items there are
|
|
402
|
+
// but if rank circle is visible clamp the minimum height to `150`
|
|
403
|
+
let height = Math.max(45 + (statItems.length + 1) * lheight, hide_rank ? 0 : statItems.length ? 150 : 180);
|
|
404
|
+
// the lower the user's percentile the better
|
|
405
|
+
const progress = 100 - rank.percentile;
|
|
406
|
+
const cssStyles = getStyles({
|
|
407
|
+
titleColor,
|
|
408
|
+
ringColor,
|
|
409
|
+
textColor,
|
|
410
|
+
iconColor,
|
|
411
|
+
show_icons,
|
|
412
|
+
progress,
|
|
413
|
+
});
|
|
414
|
+
const calculateTextWidth = () => {
|
|
415
|
+
return measureText(custom_title
|
|
416
|
+
? custom_title
|
|
417
|
+
: statItems.length
|
|
418
|
+
? i18n.t("statcard.title")
|
|
419
|
+
: i18n.t("statcard.ranktitle"));
|
|
420
|
+
};
|
|
421
|
+
/*
|
|
422
|
+
When hide_rank=true, the minimum card width is 270 px + the title length and padding.
|
|
423
|
+
When hide_rank=false, the minimum card_width is 340 px + the icon width (if show_icons=true).
|
|
424
|
+
Numbers are picked by looking at existing dimensions on production.
|
|
425
|
+
*/
|
|
426
|
+
const iconWidth = show_icons && statItems.length ? 16 + /* padding */ 1 : 0;
|
|
427
|
+
const minCardWidth = (hide_rank
|
|
428
|
+
? clampValue(50 /* padding */ + calculateTextWidth() * 2, CARD_MIN_WIDTH, Infinity)
|
|
429
|
+
: statItems.length
|
|
430
|
+
? RANK_CARD_MIN_WIDTH
|
|
431
|
+
: RANK_ONLY_CARD_MIN_WIDTH) + iconWidth;
|
|
432
|
+
const defaultCardWidth = (hide_rank
|
|
433
|
+
? CARD_DEFAULT_WIDTH
|
|
434
|
+
: statItems.length
|
|
435
|
+
? RANK_CARD_DEFAULT_WIDTH
|
|
436
|
+
: RANK_ONLY_CARD_DEFAULT_WIDTH) + iconWidth;
|
|
437
|
+
let width = card_width
|
|
438
|
+
? isNaN(card_width)
|
|
439
|
+
? Math.max(defaultCardWidth, minCardWidth)
|
|
440
|
+
: card_width
|
|
441
|
+
: Math.max(defaultCardWidth, minCardWidth);
|
|
442
|
+
const card = new Card({
|
|
443
|
+
customTitle: custom_title,
|
|
444
|
+
defaultTitle: statItems.length
|
|
445
|
+
? i18n.t("statcard.title")
|
|
446
|
+
: i18n.t("statcard.ranktitle"),
|
|
447
|
+
width,
|
|
448
|
+
height,
|
|
449
|
+
border_radius,
|
|
450
|
+
colors: {
|
|
451
|
+
titleColor,
|
|
452
|
+
textColor,
|
|
453
|
+
iconColor,
|
|
454
|
+
bgColor,
|
|
455
|
+
borderColor,
|
|
456
|
+
},
|
|
457
|
+
});
|
|
458
|
+
card.setHideBorder(hide_border);
|
|
459
|
+
card.setHideTitle(hide_title);
|
|
460
|
+
card.setCSS(cssStyles);
|
|
461
|
+
if (disable_animations) {
|
|
462
|
+
card.disableAnimations();
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Calculates the right rank circle translation values such that the rank circle
|
|
466
|
+
* keeps respecting the following padding:
|
|
467
|
+
*
|
|
468
|
+
* width > RANK_CARD_DEFAULT_WIDTH: The default right padding of 70 px will be used.
|
|
469
|
+
* width < RANK_CARD_DEFAULT_WIDTH: The left and right padding will be enlarged
|
|
470
|
+
* equally from a certain minimum at RANK_CARD_MIN_WIDTH.
|
|
471
|
+
*
|
|
472
|
+
* @returns {number} - Rank circle translation value.
|
|
473
|
+
*/
|
|
474
|
+
const calculateRankXTranslation = () => {
|
|
475
|
+
if (statItems.length) {
|
|
476
|
+
const minXTranslation = RANK_CARD_MIN_WIDTH + iconWidth - 70;
|
|
477
|
+
if (width > RANK_CARD_DEFAULT_WIDTH) {
|
|
478
|
+
const xMaxExpansion = minXTranslation + (450 - minCardWidth) / 2;
|
|
479
|
+
return xMaxExpansion + width - RANK_CARD_DEFAULT_WIDTH;
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
return minXTranslation + (width - minCardWidth) / 2;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
return width / 2 + 20 - 10;
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
// Conditionally rendered elements
|
|
490
|
+
const rankCircle = hide_rank
|
|
491
|
+
? ""
|
|
492
|
+
: `<g data-testid="rank-circle"
|
|
493
|
+
transform="translate(${calculateRankXTranslation()}, ${height / 2 - 50})">
|
|
494
|
+
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
|
|
495
|
+
<circle class="rank-circle" cx="-10" cy="8" r="40" />
|
|
496
|
+
<g class="rank-text">
|
|
497
|
+
${rankIcon(rank_icon, rank?.level, rank?.percentile)}
|
|
498
|
+
</g>
|
|
499
|
+
</g>`;
|
|
500
|
+
// Accessibility Labels
|
|
501
|
+
const labels = Object.keys(STATS)
|
|
502
|
+
.filter((key) => !hide.includes(key))
|
|
503
|
+
.map((key) => {
|
|
504
|
+
// @ts-ignore
|
|
505
|
+
const stats = STATS[key];
|
|
506
|
+
if (key === "commits") {
|
|
507
|
+
return `${i18n.t("statcard.commits")} ${getTotalCommitsYearLabel(include_all_commits, commits_year, i18n)} : ${stats.value}`;
|
|
508
|
+
}
|
|
509
|
+
return `${stats.label}: ${stats.value}`;
|
|
510
|
+
})
|
|
511
|
+
.join(", ");
|
|
512
|
+
card.setAccessibilityLabel({
|
|
513
|
+
title: `${card.title}, Rank: ${rank.level}`,
|
|
514
|
+
desc: labels,
|
|
515
|
+
});
|
|
516
|
+
return card.render(`
|
|
517
|
+
${rankCircle}
|
|
518
|
+
<svg x="0" y="0">
|
|
519
|
+
${flexLayout({
|
|
520
|
+
items: statItems,
|
|
521
|
+
gap: lheight,
|
|
522
|
+
direction: "column",
|
|
523
|
+
}).join("")}
|
|
524
|
+
</svg>
|
|
525
|
+
`);
|
|
526
|
+
};
|
|
527
|
+
export { renderStatsCard, createTextNode };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export type Lang = any;
|
|
2
|
+
export type TopLangOptions = any;
|
|
3
|
+
export type Layout = TopLangOptions["layout"];
|
|
4
|
+
export type TopLangData = any;
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import("../fetchers/types").Lang} Lang
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves the programming language whose name is the longest.
|
|
10
|
+
*
|
|
11
|
+
* @param {Lang[]} arr Array of programming languages.
|
|
12
|
+
* @returns {{ name: string, size: number, color: string }} Longest programming language object.
|
|
13
|
+
*/
|
|
14
|
+
export function getLongestLang(arr: Lang[]): {
|
|
15
|
+
name: string;
|
|
16
|
+
size: number;
|
|
17
|
+
color: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Convert degrees to radians.
|
|
21
|
+
*
|
|
22
|
+
* @param {number} angleInDegrees Angle in degrees.
|
|
23
|
+
* @returns {number} Angle in radians.
|
|
24
|
+
*/
|
|
25
|
+
export function degreesToRadians(angleInDegrees: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Convert radians to degrees.
|
|
28
|
+
*
|
|
29
|
+
* @param {number} angleInRadians Angle in radians.
|
|
30
|
+
* @returns {number} Angle in degrees.
|
|
31
|
+
*/
|
|
32
|
+
export function radiansToDegrees(angleInRadians: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Convert polar coordinates to cartesian coordinates.
|
|
35
|
+
*
|
|
36
|
+
* @param {number} centerX Center x coordinate.
|
|
37
|
+
* @param {number} centerY Center y coordinate.
|
|
38
|
+
* @param {number} radius Radius of the circle.
|
|
39
|
+
* @param {number} angleInDegrees Angle in degrees.
|
|
40
|
+
* @returns {{x: number, y: number}} Cartesian coordinates.
|
|
41
|
+
*/
|
|
42
|
+
export function polarToCartesian(centerX: number, centerY: number, radius: number, angleInDegrees: number): {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Convert cartesian coordinates to polar coordinates.
|
|
48
|
+
*
|
|
49
|
+
* @param {number} centerX Center x coordinate.
|
|
50
|
+
* @param {number} centerY Center y coordinate.
|
|
51
|
+
* @param {number} x Point x coordinate.
|
|
52
|
+
* @param {number} y Point y coordinate.
|
|
53
|
+
* @returns {{radius: number, angleInDegrees: number}} Polar coordinates.
|
|
54
|
+
*/
|
|
55
|
+
export function cartesianToPolar(centerX: number, centerY: number, x: number, y: number): {
|
|
56
|
+
radius: number;
|
|
57
|
+
angleInDegrees: number;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Calculates length of circle.
|
|
61
|
+
*
|
|
62
|
+
* @param {number} radius Radius of the circle.
|
|
63
|
+
* @returns {number} The length of the circle.
|
|
64
|
+
*/
|
|
65
|
+
export function getCircleLength(radius: number): number;
|
|
66
|
+
/**
|
|
67
|
+
* Calculates height for the compact layout.
|
|
68
|
+
*
|
|
69
|
+
* @param {number} totalLangs Total number of languages.
|
|
70
|
+
* @returns {number} Card height.
|
|
71
|
+
*/
|
|
72
|
+
export function calculateCompactLayoutHeight(totalLangs: number): number;
|
|
73
|
+
/**
|
|
74
|
+
* Calculates height for the normal layout.
|
|
75
|
+
*
|
|
76
|
+
* @param {number} totalLangs Total number of languages.
|
|
77
|
+
* @returns {number} Card height.
|
|
78
|
+
*/
|
|
79
|
+
export function calculateNormalLayoutHeight(totalLangs: number): number;
|
|
80
|
+
/**
|
|
81
|
+
* Calculates height for the donut layout.
|
|
82
|
+
*
|
|
83
|
+
* @param {number} totalLangs Total number of languages.
|
|
84
|
+
* @returns {number} Card height.
|
|
85
|
+
*/
|
|
86
|
+
export function calculateDonutLayoutHeight(totalLangs: number): number;
|
|
87
|
+
/**
|
|
88
|
+
* Calculates height for the donut vertical layout.
|
|
89
|
+
*
|
|
90
|
+
* @param {number} totalLangs Total number of languages.
|
|
91
|
+
* @returns {number} Card height.
|
|
92
|
+
*/
|
|
93
|
+
export function calculateDonutVerticalLayoutHeight(totalLangs: number): number;
|
|
94
|
+
/**
|
|
95
|
+
* Calculates height for the pie layout.
|
|
96
|
+
*
|
|
97
|
+
* @param {number} totalLangs Total number of languages.
|
|
98
|
+
* @returns {number} Card height.
|
|
99
|
+
*/
|
|
100
|
+
export function calculatePieLayoutHeight(totalLangs: number): number;
|
|
101
|
+
/**
|
|
102
|
+
* Calculates the center translation needed to keep the donut chart centred.
|
|
103
|
+
* @param {number} totalLangs Total number of languages.
|
|
104
|
+
* @returns {number} Donut center translation.
|
|
105
|
+
*/
|
|
106
|
+
export function donutCenterTranslation(totalLangs: number): number;
|
|
107
|
+
/**
|
|
108
|
+
* Trim top languages to lang_count while also hiding certain languages.
|
|
109
|
+
*
|
|
110
|
+
* @param {Record<string, Lang>} topLangs Top languages.
|
|
111
|
+
* @param {number} langs_count Number of languages to show.
|
|
112
|
+
* @param {string[]=} hide Languages to hide.
|
|
113
|
+
* @returns {{ langs: Lang[], totalLanguageSize: number }} Trimmed top languages and total size.
|
|
114
|
+
*/
|
|
115
|
+
export function trimTopLanguages(topLangs: Record<string, Lang>, langs_count: number, hide?: string[] | undefined): {
|
|
116
|
+
langs: Lang[];
|
|
117
|
+
totalLanguageSize: number;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* @typedef {import('../fetchers/types').TopLangData} TopLangData
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* Renders card that display user's most frequently used programming languages.
|
|
124
|
+
*
|
|
125
|
+
* @param {TopLangData} topLangs User's most frequently used programming languages.
|
|
126
|
+
* @param {Partial<TopLangOptions>} options Card options.
|
|
127
|
+
* @returns {string} Language card SVG object.
|
|
128
|
+
*/
|
|
129
|
+
export function renderTopLanguages(topLangs: TopLangData, options?: Partial<TopLangOptions>): string;
|
|
130
|
+
export const MIN_CARD_WIDTH: 280;
|
|
131
|
+
/**
|
|
132
|
+
* Get default languages count for provided card layout.
|
|
133
|
+
*
|
|
134
|
+
* @param {object} props Function properties.
|
|
135
|
+
* @param {Layout=} props.layout Input layout string.
|
|
136
|
+
* @param {boolean=} props.hide_progress Input hide_progress parameter value.
|
|
137
|
+
* @returns {number} Default languages count for input layout.
|
|
138
|
+
*/
|
|
139
|
+
export function getDefaultLanguagesCountByLayout({ layout, hide_progress }: {
|
|
140
|
+
layout?: Layout | undefined;
|
|
141
|
+
hide_progress?: boolean | undefined;
|
|
142
|
+
}): number;
|
|
143
|
+
//# sourceMappingURL=top-languages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"top-languages.d.ts","sourceRoot":"","sources":["../../src/cards/top-languages.js"],"names":[],"mappings":";;qBAswBa,cAAc,CAAC,QAAQ,CAAC;;AA3uBrC;;GAEG;AAEH;;;;;GAKG;AACH,oCAHW,IAAI,EAAE,GACJ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAOvD;AAEH;;;;;GAKG;AACH,iDAHW,MAAM,GACJ,MAAM,CAE4D;AAE/E;;;;;GAKG;AACH,iDAHW,MAAM,GACJ,MAAM,CAE4D;AAE/E;;;;;;;;GAQG;AACH,0CANW,MAAM,WACN,MAAM,UACN,MAAM,kBACN,MAAM,GACJ;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAC,CAQlC;AAED;;;;;;;;GAQG;AACH,0CANW,MAAM,WACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAC,CASpD;AAED;;;;;GAKG;AACH,wCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,yDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,wDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,uDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,+DAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,qDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;GAOG;AACH,2CALW,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,eACpB,MAAM,SACN,MAAM,EAAE,YAAC,GACP;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CA4BxD;AA0mBD;;GAEG;AAEH;;;;;;GAMG;AACH,6CAJW,WAAW,YACX,OAAO,CAAC,cAAc,CAAC,GACrB,MAAM,CAkLlB;AA59BD,6BAAuB,GAAG,CAAC;AA2wB3B;;;;;;;GAOG;AACH,4EAJG;IAAuB,MAAM,GAArB,MAAM,YAAC;IACS,aAAa,GAA7B,OAAO,YAAC;CAChB,GAAU,MAAM,CAclB"}
|