@stats-forge/github-stats-forge-core 0.0.1 → 0.1.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.
- package/README.md +0 -10
- package/build/api/api-result.d.ts +6 -7
- package/build/api/api-result.d.ts.map +1 -1
- package/build/api/api-result.js +4 -5
- package/build/api/gist.d.ts +3 -10
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +4 -11
- package/build/api/index.d.ts +12 -12
- package/build/api/params.d.ts +11 -8
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +16 -14
- package/build/api/pin.d.ts +3 -19
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +6 -22
- package/build/api/stats.d.ts +10 -4
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +6 -32
- package/build/api/top-langs.d.ts +12 -6
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +6 -26
- package/build/api/wakatime.d.ts +13 -5
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +4 -21
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/gist.d.ts +2 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +27 -36
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +2 -4
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +61 -93
- package/build/cards/stats.d.ts +3 -8
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +119 -165
- package/build/cards/top-languages.d.ts +5 -31
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +176 -384
- package/build/cards/wakatime.d.ts +4 -6
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +118 -185
- package/build/common/Card.d.ts +14 -62
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +97 -199
- package/build/common/I18n.d.ts +0 -6
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +3 -6
- package/build/common/color.d.ts +4 -17
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +67 -49
- package/build/common/config.d.ts +4 -14
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +3 -16
- package/build/common/constants.d.ts +4 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +3 -1
- package/build/common/date.d.ts +0 -2
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +0 -2
- package/build/common/emojiMap.d.ts +8 -0
- package/build/common/emojiMap.d.ts.map +1 -0
- package/build/common/emojiMap.js +10 -0
- package/build/common/emojiMap.json +1915 -0
- package/build/common/error.d.ts +1 -10
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +1 -10
- package/build/common/fmt.d.ts +3 -15
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +7 -35
- package/build/common/http.d.ts +2 -7
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +8 -17
- package/build/common/icons.d.ts +18 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +103 -67
- package/build/common/languageColors.d.ts +0 -1
- package/build/common/languageColors.d.ts.map +1 -1
- package/build/common/languageColors.js +1 -4
- package/build/common/languageColors.json +18 -2
- package/build/common/ops.d.ts +3 -14
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +19 -30
- package/build/common/render.d.ts +28 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +175 -211
- package/build/common/retryer.d.ts +2 -7
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +4 -11
- package/build/fetchers/gist.d.ts +2 -5
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +1 -5
- package/build/fetchers/index.d.ts +12 -12
- package/build/fetchers/repo.d.ts +2 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +20 -33
- package/build/fetchers/stats.d.ts +2 -32
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +27 -86
- package/build/fetchers/top-languages.d.ts +2 -9
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +15 -31
- package/build/fetchers/types.d.ts +1 -1
- package/build/fetchers/wakatime.d.ts +2 -6
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +1 -5
- package/build/graphql/contributionsDocument.d.ts +3 -3
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +0 -1
- package/build/graphql/generated/gist.d.ts +1 -1
- package/build/graphql/generated/repo.d.ts +1 -1
- package/build/graphql/generated/stats.d.ts +3 -3
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +0 -1
- package/build/graphql/graphqlDocument.d.ts.map +1 -1
- package/build/graphql/graphqlDocument.js +0 -1
- package/build/graphql/reposContributedToDocument.d.ts +4 -5
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -1
- package/build/graphql/reposContributedToDocument.js +0 -2
- package/build/markup/css.d.ts +35 -0
- package/build/markup/css.d.ts.map +1 -0
- package/build/markup/css.js +64 -0
- package/build/markup/element.d.ts +41 -0
- package/build/markup/element.d.ts.map +1 -0
- package/build/markup/element.js +127 -0
- package/build/markup/html.d.ts +13 -0
- package/build/markup/html.d.ts.map +1 -0
- package/build/markup/html.js +27 -0
- package/build/markup/index.d.ts +9 -0
- package/build/markup/index.d.ts.map +1 -0
- package/build/markup/index.js +6 -0
- package/build/markup/serialize.d.ts +16 -0
- package/build/markup/serialize.d.ts.map +1 -0
- package/build/markup/serialize.js +17 -0
- package/build/themes/index.d.ts +332 -333
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +1 -1
- package/build/translations.d.ts +2 -6
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +621 -628
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/gist.ts +11 -18
- package/src/api/index.ts +12 -12
- package/src/api/params.ts +27 -21
- package/src/api/pin.ts +13 -28
- package/src/api/stats.ts +13 -39
- package/src/api/top-langs.ts +13 -33
- package/src/api/wakatime.ts +11 -28
- package/src/calculateRank.ts +12 -23
- package/src/cards/gist.ts +40 -43
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +97 -107
- package/src/cards/stats.ts +165 -184
- package/src/cards/top-languages.ts +297 -413
- package/src/cards/wakatime.ts +193 -221
- package/src/common/Card.ts +165 -217
- package/src/common/I18n.ts +3 -6
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +5 -2
- package/src/common/date.ts +0 -2
- package/src/common/emojiMap.json +1915 -0
- package/src/common/emojiMap.ts +13 -0
- package/src/common/error.ts +2 -11
- package/src/common/fmt.ts +7 -44
- package/src/common/http.ts +9 -15
- package/src/common/icons.ts +117 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +26 -34
- package/src/common/render.ts +279 -232
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/index.ts +12 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +44 -102
- package/src/fetchers/top-languages.ts +26 -40
- package/src/fetchers/types.ts +1 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsDocument.ts +7 -5
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +2 -2
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +0 -1
- package/src/graphql/reposContributedToDocument.ts +6 -7
- package/src/markup/css.ts +118 -0
- package/src/markup/element.ts +246 -0
- package/src/markup/html.ts +34 -0
- package/src/markup/index.ts +9 -0
- package/src/markup/serialize.ts +27 -0
- package/src/themes/index.ts +1 -1
- package/src/translations.ts +622 -629
- package/build/cards/index.d.ts +0 -11
- package/build/cards/index.d.ts.map +0 -1
- package/build/cards/index.js +0 -7
- package/build/common/html.d.ts +0 -8
- package/build/common/html.d.ts.map +0 -1
- package/build/common/html.js +0 -14
- package/build/index.d.ts +0 -15
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -10
- package/src/_emoji-name-map.d.ts +0 -10
- package/src/_github-username-regex.d.ts +0 -4
- package/src/cards/index.ts +0 -21
- package/src/common/html.ts +0 -17
- package/src/index.ts +0 -18
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Card } from '../common/Card.js';
|
|
2
2
|
import { getLightDarkColors, isPrefixedHexColor } from '../common/color.js';
|
|
3
3
|
import { formatBytes } from '../common/fmt.js';
|
|
4
|
-
import { encodeHTML } from '../common/html.js';
|
|
5
4
|
import { I18n } from '../common/I18n.js';
|
|
6
5
|
import { DEFAULT_LANG_COLOR } from '../common/languageColors.js';
|
|
7
6
|
import { chunkArray, clampValue, lowercaseTrim } from '../common/ops.js';
|
|
8
7
|
import { createProgressNode, flexLayout, measureText } from '../common/render.js';
|
|
8
|
+
import { atRule, cssComment, el, rule } from '../markup/index.js';
|
|
9
9
|
import { langCardLocales } from '../translations.js';
|
|
10
10
|
const DEFAULT_CARD_WIDTH = 300;
|
|
11
11
|
const MIN_CARD_WIDTH = 280;
|
|
@@ -24,31 +24,32 @@ const TOP_LANG_STATS_FORMATS = ['percentages', 'bytes'];
|
|
|
24
24
|
/**
|
|
25
25
|
* Retrieves the programming language whose name is the longest.
|
|
26
26
|
*
|
|
27
|
-
* @param arr Array of programming languages.
|
|
28
27
|
* @returns Longest programming language object.
|
|
29
28
|
*/
|
|
30
|
-
const getLongestLang = (arr) =>
|
|
29
|
+
const getLongestLang = (arr) => {
|
|
30
|
+
let longest = { name: '', size: 0, color: '' };
|
|
31
|
+
for (const lang of arr) {
|
|
32
|
+
if (lang.name.length > longest.name.length) {
|
|
33
|
+
longest = lang;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return longest;
|
|
37
|
+
};
|
|
31
38
|
/**
|
|
32
39
|
* Convert degrees to radians.
|
|
33
40
|
*
|
|
34
|
-
* @param angleInDegrees Angle in degrees.
|
|
35
41
|
* @returns Angle in radians.
|
|
36
42
|
*/
|
|
37
|
-
const degreesToRadians = (angleInDegrees) => angleInDegrees * (Math.PI / 180
|
|
43
|
+
const degreesToRadians = (angleInDegrees) => angleInDegrees * (Math.PI / 180);
|
|
38
44
|
/**
|
|
39
45
|
* Convert radians to degrees.
|
|
40
46
|
*
|
|
41
|
-
* @param angleInRadians Angle in radians.
|
|
42
47
|
* @returns Angle in degrees.
|
|
43
48
|
*/
|
|
44
|
-
const radiansToDegrees = (angleInRadians) => angleInRadians / (Math.PI / 180
|
|
49
|
+
const radiansToDegrees = (angleInRadians) => angleInRadians / (Math.PI / 180);
|
|
45
50
|
/**
|
|
46
51
|
* Convert polar coordinates to cartesian coordinates.
|
|
47
52
|
*
|
|
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
53
|
* @returns Cartesian coordinates.
|
|
53
54
|
*/
|
|
54
55
|
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
|
|
@@ -61,14 +62,10 @@ const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
|
|
|
61
62
|
/**
|
|
62
63
|
* Convert cartesian coordinates to polar coordinates.
|
|
63
64
|
*
|
|
64
|
-
* @param centerX Center x coordinate.
|
|
65
|
-
* @param centerY Center y coordinate.
|
|
66
|
-
* @param x Point x coordinate.
|
|
67
|
-
* @param y Point y coordinate.
|
|
68
65
|
* @returns Polar coordinates.
|
|
69
66
|
*/
|
|
70
67
|
const cartesianToPolar = (centerX, centerY, x, y) => {
|
|
71
|
-
const radius = Math.
|
|
68
|
+
const radius = Math.hypot(x - centerX, y - centerY);
|
|
72
69
|
let angleInDegrees = radiansToDegrees(Math.atan2(y - centerY, x - centerX));
|
|
73
70
|
if (angleInDegrees < 0) {
|
|
74
71
|
angleInDegrees += 360;
|
|
@@ -78,72 +75,48 @@ const cartesianToPolar = (centerX, centerY, x, y) => {
|
|
|
78
75
|
/**
|
|
79
76
|
* Calculates length of circle.
|
|
80
77
|
*
|
|
81
|
-
* @param radius Radius of the circle.
|
|
82
78
|
* @returns The length of the circle.
|
|
83
79
|
*/
|
|
84
|
-
const getCircleLength = (radius) =>
|
|
85
|
-
return 2 * Math.PI * radius;
|
|
86
|
-
};
|
|
80
|
+
const getCircleLength = (radius) => 2 * Math.PI * radius;
|
|
87
81
|
/**
|
|
88
82
|
* Calculates height for the compact layout.
|
|
89
83
|
*
|
|
90
|
-
* @param totalLangs Total number of languages.
|
|
91
84
|
* @returns Card height.
|
|
92
85
|
*/
|
|
93
|
-
const calculateCompactLayoutHeight = (totalLangs) =>
|
|
94
|
-
return COMPACT_LAYOUT_BASE_HEIGHT + Math.round(totalLangs / 2) * 25;
|
|
95
|
-
};
|
|
86
|
+
const calculateCompactLayoutHeight = (totalLangs) => COMPACT_LAYOUT_BASE_HEIGHT + Math.round(totalLangs / 2) * 25;
|
|
96
87
|
/**
|
|
97
88
|
* Calculates height for the normal layout.
|
|
98
89
|
*
|
|
99
|
-
* @param totalLangs Total number of languages.
|
|
100
90
|
* @returns Card height.
|
|
101
91
|
*/
|
|
102
|
-
const calculateNormalLayoutHeight = (totalLangs) =>
|
|
103
|
-
return 45 + (totalLangs + 1) * 40;
|
|
104
|
-
};
|
|
92
|
+
const calculateNormalLayoutHeight = (totalLangs) => 45 + (totalLangs + 1) * 40;
|
|
105
93
|
/**
|
|
106
94
|
* Calculates height for the donut layout.
|
|
107
95
|
*
|
|
108
|
-
* @param totalLangs Total number of languages.
|
|
109
96
|
* @returns Card height.
|
|
110
97
|
*/
|
|
111
|
-
const calculateDonutLayoutHeight = (totalLangs) =>
|
|
112
|
-
return 215 + Math.max(totalLangs - 5, 0) * 32;
|
|
113
|
-
};
|
|
98
|
+
const calculateDonutLayoutHeight = (totalLangs) => 215 + Math.max(totalLangs - 5, 0) * 32;
|
|
114
99
|
/**
|
|
115
100
|
* Calculates height for the donut vertical layout.
|
|
116
101
|
*
|
|
117
|
-
* @param totalLangs Total number of languages.
|
|
118
102
|
* @returns Card height.
|
|
119
103
|
*/
|
|
120
|
-
const calculateDonutVerticalLayoutHeight = (totalLangs) =>
|
|
121
|
-
return 300 + Math.round(totalLangs / 2) * 25;
|
|
122
|
-
};
|
|
104
|
+
const calculateDonutVerticalLayoutHeight = (totalLangs) => 300 + Math.round(totalLangs / 2) * 25;
|
|
123
105
|
/**
|
|
124
106
|
* Calculates height for the pie layout.
|
|
125
107
|
*
|
|
126
|
-
* @param totalLangs Total number of languages.
|
|
127
108
|
* @returns Card height.
|
|
128
109
|
*/
|
|
129
|
-
const calculatePieLayoutHeight = (totalLangs) =>
|
|
130
|
-
return 300 + Math.round(totalLangs / 2) * 25;
|
|
131
|
-
};
|
|
110
|
+
const calculatePieLayoutHeight = (totalLangs) => 300 + Math.round(totalLangs / 2) * 25;
|
|
132
111
|
/**
|
|
133
112
|
* Calculates the center translation needed to keep the donut chart centred.
|
|
134
113
|
*
|
|
135
|
-
* @param totalLangs Total number of languages.
|
|
136
114
|
* @returns Donut center translation.
|
|
137
115
|
*/
|
|
138
|
-
const donutCenterTranslation = (totalLangs) =>
|
|
139
|
-
return -45 + Math.max(totalLangs - 5, 0) * 16;
|
|
140
|
-
};
|
|
116
|
+
const donutCenterTranslation = (totalLangs) => -45 + Math.max(totalLangs - 5, 0) * 16;
|
|
141
117
|
/**
|
|
142
118
|
* Trim top languages to lang_count while also hiding certain languages.
|
|
143
119
|
*
|
|
144
|
-
* @param topLangs Top languages.
|
|
145
|
-
* @param langs_count Number of languages to show.
|
|
146
|
-
* @param hide Languages to hide.
|
|
147
120
|
* @returns Trimmed top languages and total size.
|
|
148
121
|
*/
|
|
149
122
|
const trimTopLanguages = (topLangs, langs_count, hide) => {
|
|
@@ -152,13 +125,13 @@ const trimTopLanguages = (topLangs, langs_count, hide) => {
|
|
|
152
125
|
const langsCount = clampValue(langs_count, 1, MAXIMUM_LANGS_COUNT);
|
|
153
126
|
// populate langsToHide map for quick lookup while filtering out
|
|
154
127
|
if (hide) {
|
|
155
|
-
|
|
128
|
+
for (const langName of hide) {
|
|
156
129
|
langsToHide[lowercaseTrim(langName)] = true;
|
|
157
|
-
}
|
|
130
|
+
}
|
|
158
131
|
}
|
|
159
132
|
// filter out languages to be hidden
|
|
160
133
|
langs = langs
|
|
161
|
-
.
|
|
134
|
+
.toSorted((a, b) => b.size - a.size)
|
|
162
135
|
.filter((lang) => !langsToHide[lowercaseTrim(lang.name)])
|
|
163
136
|
.slice(0, langsCount);
|
|
164
137
|
const totalLanguageSize = langs.reduce((acc, curr) => acc + curr.size, 0);
|
|
@@ -167,19 +140,13 @@ const trimTopLanguages = (topLangs, langs_count, hide) => {
|
|
|
167
140
|
/**
|
|
168
141
|
* Get display value corresponding to the format.
|
|
169
142
|
*
|
|
170
|
-
* @param size Bytes size.
|
|
171
|
-
* @param percentages Percentage value.
|
|
172
|
-
* @param format Format of the stats.
|
|
173
143
|
* @returns Display value.
|
|
174
144
|
*/
|
|
175
|
-
const getDisplayValue = (size, percentages, format) => {
|
|
176
|
-
return format === 'bytes' ? formatBytes(size) : `${percentages.toFixed(2)}%`;
|
|
177
|
-
};
|
|
145
|
+
const getDisplayValue = (size, percentages, format) => format === 'bytes' ? formatBytes(size) : `${percentages.toFixed(2)}%`;
|
|
178
146
|
/**
|
|
179
147
|
* Resolves a language's display color, falling back to the default, and
|
|
180
148
|
* validates it is a prefixed hex color.
|
|
181
149
|
*
|
|
182
|
-
* @param lang Programming language object.
|
|
183
150
|
* @returns Validated language color.
|
|
184
151
|
*/
|
|
185
152
|
const resolveLangColor = (lang) => {
|
|
@@ -192,15 +159,6 @@ const resolveLangColor = (lang) => {
|
|
|
192
159
|
/**
|
|
193
160
|
* Create progress bar text item for a programming language.
|
|
194
161
|
*
|
|
195
|
-
* @param props Function properties.
|
|
196
|
-
* @param props.width The card width
|
|
197
|
-
* @param props.color Color of the programming language.
|
|
198
|
-
* @param props.name Name of the programming language.
|
|
199
|
-
* @param props.size Size of the programming language.
|
|
200
|
-
* @param props.totalSize Total size of all languages.
|
|
201
|
-
* @param props.statsFormat Stats format.
|
|
202
|
-
* @param props.hideValues Whether to hide stats values.
|
|
203
|
-
* @param props.index Index of the programming language.
|
|
204
162
|
* @returns Programming language SVG node.
|
|
205
163
|
*/
|
|
206
164
|
const createProgressTextNode = ({ width, color, name, size, totalSize, statsFormat, hideValues, index, }) => {
|
|
@@ -210,31 +168,18 @@ const createProgressTextNode = ({ width, color, name, size, totalSize, statsForm
|
|
|
210
168
|
const progressWidth = width - paddingRight;
|
|
211
169
|
const progress = (size / totalSize) * 100;
|
|
212
170
|
const displayValue = getDisplayValue(size, progress, statsFormat);
|
|
213
|
-
return `
|
|
214
|
-
<g class="stagger" style="animation-delay: ${staggerDelay}ms">
|
|
215
|
-
<text data-testid="lang-name" x="2" y="15" class="lang-name">${encodeHTML(name)}</text>
|
|
216
|
-
${hideValues ? '' : `<text x="${progressTextX}" y="34" class="lang-name">${encodeHTML(displayValue)}</text>`}
|
|
217
|
-
${createProgressNode({
|
|
171
|
+
return el('g', { class: 'stagger', style: `animation-delay: ${staggerDelay}ms` }, el('text', { 'data-testid': 'lang-name', x: 2, y: 15, class: 'lang-name' }, name), !hideValues && el('text', { x: progressTextX, y: 34, class: 'lang-name' }, displayValue), createProgressNode({
|
|
218
172
|
x: 0,
|
|
219
173
|
y: 25,
|
|
220
174
|
color,
|
|
221
175
|
width: progressWidth,
|
|
222
176
|
progress,
|
|
223
177
|
delay: staggerDelay + 300,
|
|
224
|
-
})
|
|
225
|
-
</g>
|
|
226
|
-
`;
|
|
178
|
+
}));
|
|
227
179
|
};
|
|
228
180
|
/**
|
|
229
181
|
* Creates compact text item for a programming language.
|
|
230
182
|
*
|
|
231
|
-
* @param props Function properties.
|
|
232
|
-
* @param props.lang Programming language object.
|
|
233
|
-
* @param props.totalSize Total size of all languages.
|
|
234
|
-
* @param props.hideProgress Whether to hide percentage.
|
|
235
|
-
* @param props.hideValues Whether to hide stats values (percentages/bytes).
|
|
236
|
-
* @param props.statsFormat Stats format
|
|
237
|
-
* @param props.index Index of the programming language.
|
|
238
183
|
* @returns Compact layout programming language SVG node.
|
|
239
184
|
*/
|
|
240
185
|
const createCompactLangNode = ({ lang, totalSize, hideProgress, hideValues, statsFormat = 'percentages', index, }) => {
|
|
@@ -242,24 +187,12 @@ const createCompactLangNode = ({ lang, totalSize, hideProgress, hideValues, stat
|
|
|
242
187
|
const displayValue = getDisplayValue(lang.size, percentages, statsFormat);
|
|
243
188
|
const staggerDelay = (index + 3) * 150;
|
|
244
189
|
const color = resolveLangColor(lang);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<circle cx="5" cy="6" r="5" fill="${color}" />
|
|
248
|
-
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
|
|
249
|
-
${encodeHTML(lang.name)} ${hideProgress || hideValues ? '' : encodeHTML(displayValue)}
|
|
250
|
-
</text>
|
|
251
|
-
</g>
|
|
252
|
-
`;
|
|
190
|
+
const label = hideProgress || hideValues ? lang.name : `${lang.name} ${displayValue}`;
|
|
191
|
+
return el('g', { class: 'stagger', style: `animation-delay: ${staggerDelay}ms` }, el('circle', { cx: 5, cy: 6, r: 5, fill: color }), el('text', { 'data-testid': 'lang-name', x: 15, y: 10, class: 'lang-name' }, label));
|
|
253
192
|
};
|
|
254
193
|
/**
|
|
255
194
|
* Create compact languages text items for all programming languages.
|
|
256
195
|
*
|
|
257
|
-
* @param props Function properties.
|
|
258
|
-
* @param props.langs Array of programming languages.
|
|
259
|
-
* @param props.totalSize Total size of all languages.
|
|
260
|
-
* @param props.hideProgress Whether to hide percentage.
|
|
261
|
-
* @param props.hideValues Whether to hide stats values.
|
|
262
|
-
* @param props.statsFormat Stats format
|
|
263
196
|
* @returns Programming languages SVG node.
|
|
264
197
|
*/
|
|
265
198
|
const createLanguageTextNode = ({ langs, totalSize, hideProgress, hideValues, statsFormat, }) => {
|
|
@@ -274,83 +207,52 @@ const createLanguageTextNode = ({ langs, totalSize, hideProgress, hideValues, st
|
|
|
274
207
|
statsFormat,
|
|
275
208
|
index,
|
|
276
209
|
}));
|
|
277
|
-
return flexLayout({
|
|
278
|
-
items,
|
|
279
|
-
gap: 25,
|
|
280
|
-
direction: 'column',
|
|
281
|
-
}).join('');
|
|
210
|
+
return flexLayout({ items, gap: 25, direction: 'column' });
|
|
282
211
|
});
|
|
283
212
|
const percent = ((longestLang.size / totalSize) * 100).toFixed(2);
|
|
284
213
|
const minGap = 150;
|
|
285
214
|
const maxGap = 20 + measureText(`${longestLang.name} ${percent}%`, 11);
|
|
286
|
-
return flexLayout({
|
|
287
|
-
items: layouts,
|
|
288
|
-
gap: maxGap < minGap ? minGap : maxGap,
|
|
289
|
-
}).join('');
|
|
215
|
+
return flexLayout({ items: layouts, gap: maxGap < minGap ? minGap : maxGap });
|
|
290
216
|
};
|
|
291
217
|
/**
|
|
292
218
|
* Create donut languages text items for all programming languages.
|
|
293
219
|
*
|
|
294
|
-
* @param props Function properties.
|
|
295
|
-
* @param props.langs Array of programming languages.
|
|
296
|
-
* @param props.totalSize Total size of all languages.
|
|
297
|
-
* @param props.hideValues Whether to hide stats values.
|
|
298
|
-
* @param props.statsFormat Stats format
|
|
299
220
|
* @returns Donut layout programming language SVG node.
|
|
300
221
|
*/
|
|
301
|
-
const createDonutLanguagesNode = ({ langs, totalSize, hideValues, statsFormat, }) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
gap: 32,
|
|
314
|
-
direction: 'column',
|
|
315
|
-
}).join('');
|
|
316
|
-
};
|
|
222
|
+
const createDonutLanguagesNode = ({ langs, totalSize, hideValues, statsFormat, }) => flexLayout({
|
|
223
|
+
items: langs.map((lang, index) => createCompactLangNode({
|
|
224
|
+
lang,
|
|
225
|
+
totalSize,
|
|
226
|
+
hideProgress: false,
|
|
227
|
+
hideValues,
|
|
228
|
+
statsFormat,
|
|
229
|
+
index,
|
|
230
|
+
})),
|
|
231
|
+
gap: 32,
|
|
232
|
+
direction: 'column',
|
|
233
|
+
});
|
|
317
234
|
/**
|
|
318
235
|
* Renders the default language card layout.
|
|
319
236
|
*
|
|
320
|
-
* @param langs Array of programming languages.
|
|
321
|
-
* @param width Card width.
|
|
322
|
-
* @param totalLanguageSize Total size of all languages.
|
|
323
|
-
* @param statsFormat Stats format.
|
|
324
|
-
* @param hideValues Whether to hide stats values.
|
|
325
237
|
* @returns Normal layout card SVG object.
|
|
326
238
|
*/
|
|
327
|
-
const renderNormalLayout = (langs, width, totalLanguageSize, statsFormat, hideValues) => {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
gap: 40,
|
|
342
|
-
direction: 'column',
|
|
343
|
-
}).join('');
|
|
344
|
-
};
|
|
239
|
+
const renderNormalLayout = (langs, width, totalLanguageSize, statsFormat, hideValues) => flexLayout({
|
|
240
|
+
items: langs.map((lang, index) => createProgressTextNode({
|
|
241
|
+
width,
|
|
242
|
+
name: lang.name,
|
|
243
|
+
color: lang.color || DEFAULT_LANG_COLOR,
|
|
244
|
+
size: lang.size,
|
|
245
|
+
totalSize: totalLanguageSize,
|
|
246
|
+
statsFormat,
|
|
247
|
+
hideValues,
|
|
248
|
+
index,
|
|
249
|
+
})),
|
|
250
|
+
gap: 40,
|
|
251
|
+
direction: 'column',
|
|
252
|
+
});
|
|
345
253
|
/**
|
|
346
254
|
* Renders the compact language card layout.
|
|
347
255
|
*
|
|
348
|
-
* @param langs Array of programming languages.
|
|
349
|
-
* @param width Card width.
|
|
350
|
-
* @param totalLanguageSize Total size of all languages.
|
|
351
|
-
* @param hideProgress Whether to hide progress bar.
|
|
352
|
-
* @param statsFormat Stats format.
|
|
353
|
-
* @param hideValues Whether to hide stats values.
|
|
354
256
|
* @returns Compact layout card SVG object.
|
|
355
257
|
*/
|
|
356
258
|
const renderCompactLayout = (langs, width, totalLanguageSize, hideProgress, statsFormat = 'percentages', hideValues) => {
|
|
@@ -359,53 +261,37 @@ const renderCompactLayout = (langs, width, totalLanguageSize, hideProgress, stat
|
|
|
359
261
|
// progressOffset holds the previous language's width and used to offset the next language
|
|
360
262
|
// so that we can stack them one after another, like this: [--][----][---]
|
|
361
263
|
let progressOffset = 0;
|
|
362
|
-
const compactProgressBar = langs
|
|
363
|
-
.
|
|
364
|
-
const
|
|
365
|
-
const percentage = parseFloat(((lang.size / totalLanguageSize) * offsetWidth).toFixed(2));
|
|
366
|
-
const progress = percentage < 10 ? percentage + 10 : percentage;
|
|
367
|
-
const output = `
|
|
368
|
-
<rect
|
|
369
|
-
mask="url(#rect-mask)"
|
|
370
|
-
data-testid="lang-progress"
|
|
371
|
-
x="${progressOffset}"
|
|
372
|
-
y="0"
|
|
373
|
-
width="${progress}"
|
|
374
|
-
height="8"
|
|
375
|
-
fill="${langColor}"
|
|
376
|
-
/>
|
|
377
|
-
`;
|
|
264
|
+
const compactProgressBar = langs.map((lang) => {
|
|
265
|
+
const percentage = Number.parseFloat(((lang.size / totalLanguageSize) * offsetWidth).toFixed(2));
|
|
266
|
+
const x = progressOffset;
|
|
378
267
|
progressOffset += percentage;
|
|
379
|
-
return
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
268
|
+
return el('rect', {
|
|
269
|
+
mask: 'url(#rect-mask)',
|
|
270
|
+
'data-testid': 'lang-progress',
|
|
271
|
+
x,
|
|
272
|
+
y: 0,
|
|
273
|
+
width: percentage < 10 ? percentage + 10 : percentage,
|
|
274
|
+
height: 8,
|
|
275
|
+
fill: resolveLangColor(lang),
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
return [
|
|
279
|
+
!hideProgress && [
|
|
280
|
+
el('mask', { id: 'rect-mask' }, el('rect', { x: 0, y: 0, width: offsetWidth, height: 8, fill: 'white', rx: 5 })),
|
|
281
|
+
compactProgressBar,
|
|
282
|
+
],
|
|
283
|
+
el('g', { transform: `translate(0, ${hideProgress ? 0 : 25})` }, createLanguageTextNode({
|
|
284
|
+
langs,
|
|
285
|
+
totalSize: totalLanguageSize,
|
|
286
|
+
hideProgress,
|
|
287
|
+
statsFormat,
|
|
288
|
+
hideValues,
|
|
289
|
+
})),
|
|
290
|
+
];
|
|
401
291
|
};
|
|
402
292
|
/**
|
|
403
293
|
* Renders donut vertical layout to display user's most frequently used programming languages.
|
|
404
294
|
*
|
|
405
|
-
* @param langs Array of programming languages.
|
|
406
|
-
* @param totalLanguageSize Total size of all languages.
|
|
407
|
-
* @param statsFormat Stats format.
|
|
408
|
-
* @param hideValues Whether to hide stats values.
|
|
409
295
|
* @returns Compact layout card SVG object.
|
|
410
296
|
*/
|
|
411
297
|
const renderDonutVerticalLayout = (langs, totalLanguageSize, statsFormat, hideValues) => {
|
|
@@ -424,55 +310,34 @@ const renderDonutVerticalLayout = (langs, totalLanguageSize, statsFormat, hideVa
|
|
|
424
310
|
const percentage = (lang.size / totalLanguageSize) * 100;
|
|
425
311
|
const circleLength = totalCircleLength * (percentage / 100);
|
|
426
312
|
const delay = startDelayCoefficient * 100;
|
|
427
|
-
circles.push(`
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
data-testid="lang-donut"
|
|
440
|
-
/>
|
|
441
|
-
</g>
|
|
442
|
-
`);
|
|
313
|
+
circles.push(el('g', { class: 'stagger', style: `animation-delay: ${delay}ms` }, el('circle', {
|
|
314
|
+
cx: 150,
|
|
315
|
+
cy: 100,
|
|
316
|
+
r: radius,
|
|
317
|
+
fill: 'transparent',
|
|
318
|
+
stroke: langColor,
|
|
319
|
+
'stroke-width': 25,
|
|
320
|
+
'stroke-dasharray': totalCircleLength,
|
|
321
|
+
'stroke-dashoffset': indent,
|
|
322
|
+
size: percentage,
|
|
323
|
+
'data-testid': 'lang-donut',
|
|
324
|
+
})));
|
|
443
325
|
// Update the indent for the next part
|
|
444
326
|
indent += circleLength;
|
|
445
327
|
// Update the start delay coefficient for the next part
|
|
446
328
|
startDelayCoefficient += 1;
|
|
447
329
|
}
|
|
448
|
-
return
|
|
449
|
-
<svg data-testid="lang-items">
|
|
450
|
-
<g transform="translate(0, 0)">
|
|
451
|
-
<svg data-testid="donut">
|
|
452
|
-
${circles.join('')}
|
|
453
|
-
</svg>
|
|
454
|
-
</g>
|
|
455
|
-
<g transform="translate(0, 220)">
|
|
456
|
-
<svg data-testid="lang-names" x="${CARD_PADDING}">
|
|
457
|
-
${createLanguageTextNode({
|
|
330
|
+
return el('svg', { 'data-testid': 'lang-items' }, el('svg', { 'data-testid': 'donut' }, circles), el('g', { transform: 'translate(0, 220)' }, el('svg', { 'data-testid': 'lang-names', x: CARD_PADDING }, createLanguageTextNode({
|
|
458
331
|
langs,
|
|
459
332
|
totalSize: totalLanguageSize,
|
|
460
333
|
hideProgress: false,
|
|
461
334
|
statsFormat,
|
|
462
335
|
hideValues,
|
|
463
|
-
})
|
|
464
|
-
</svg>
|
|
465
|
-
</g>
|
|
466
|
-
</svg>
|
|
467
|
-
`;
|
|
336
|
+
}))));
|
|
468
337
|
};
|
|
469
338
|
/**
|
|
470
339
|
* Renders pie layout to display user's most frequently used programming languages.
|
|
471
340
|
*
|
|
472
|
-
* @param langs Array of programming languages.
|
|
473
|
-
* @param totalLanguageSize Total size of all languages.
|
|
474
|
-
* @param statsFormat Stats format.
|
|
475
|
-
* @param hideValues Whether to hide stats values.
|
|
476
341
|
* @returns Compact layout card SVG object.
|
|
477
342
|
*/
|
|
478
343
|
const renderPieLayout = (langs, totalLanguageSize, statsFormat, hideValues) => {
|
|
@@ -490,17 +355,15 @@ const renderPieLayout = (langs, totalLanguageSize, statsFormat, hideValues) => {
|
|
|
490
355
|
for (const lang of langs) {
|
|
491
356
|
const langColor = resolveLangColor(lang);
|
|
492
357
|
if (langs.length === 1) {
|
|
493
|
-
paths.push(
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
/>
|
|
503
|
-
`);
|
|
358
|
+
paths.push(el('circle', {
|
|
359
|
+
cx: centerX,
|
|
360
|
+
cy: centerY,
|
|
361
|
+
r: radius,
|
|
362
|
+
stroke: 'none',
|
|
363
|
+
fill: langColor,
|
|
364
|
+
'data-testid': 'lang-pie',
|
|
365
|
+
size: 100,
|
|
366
|
+
}));
|
|
504
367
|
break;
|
|
505
368
|
}
|
|
506
369
|
const langSizePart = lang.size / totalLanguageSize;
|
|
@@ -517,49 +380,28 @@ const renderPieLayout = (langs, totalLanguageSize, statsFormat, hideValues) => {
|
|
|
517
380
|
// Calculate delay
|
|
518
381
|
const delay = startDelayCoefficient * 100;
|
|
519
382
|
// SVG arc markup
|
|
520
|
-
paths.push(`
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
fill="${langColor}"
|
|
527
|
-
/>
|
|
528
|
-
</g>
|
|
529
|
-
`);
|
|
383
|
+
paths.push(el('g', { class: 'stagger', style: `animation-delay: ${delay}ms` }, el('path', {
|
|
384
|
+
'data-testid': 'lang-pie',
|
|
385
|
+
size: percentage,
|
|
386
|
+
d: `M ${centerX} ${centerY} L ${startPoint.x} ${startPoint.y} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y} Z`,
|
|
387
|
+
fill: langColor,
|
|
388
|
+
})));
|
|
530
389
|
// Update the start angle for the next part
|
|
531
390
|
startAngle = endAngle;
|
|
532
391
|
// Update the start delay coefficient for the next part
|
|
533
392
|
startDelayCoefficient += 1;
|
|
534
393
|
}
|
|
535
|
-
return
|
|
536
|
-
<svg data-testid="lang-items">
|
|
537
|
-
<g transform="translate(0, 0)">
|
|
538
|
-
<svg data-testid="pie">
|
|
539
|
-
${paths.join('')}
|
|
540
|
-
</svg>
|
|
541
|
-
</g>
|
|
542
|
-
<g transform="translate(0, 220)">
|
|
543
|
-
<svg data-testid="lang-names" x="${CARD_PADDING}">
|
|
544
|
-
${createLanguageTextNode({
|
|
394
|
+
return el('svg', { 'data-testid': 'lang-items' }, el('svg', { 'data-testid': 'pie' }, paths), el('g', { transform: 'translate(0, 220)' }, el('svg', { 'data-testid': 'lang-names', x: CARD_PADDING }, createLanguageTextNode({
|
|
545
395
|
langs,
|
|
546
396
|
totalSize: totalLanguageSize,
|
|
547
397
|
hideProgress: false,
|
|
548
398
|
statsFormat,
|
|
549
399
|
hideValues,
|
|
550
|
-
})
|
|
551
|
-
</svg>
|
|
552
|
-
</g>
|
|
553
|
-
</svg>
|
|
554
|
-
`;
|
|
400
|
+
}))));
|
|
555
401
|
};
|
|
556
402
|
/**
|
|
557
403
|
* Creates the SVG paths for the language donut chart.
|
|
558
404
|
*
|
|
559
|
-
* @param cx Donut center x-position.
|
|
560
|
-
* @param cy Donut center y-position.
|
|
561
|
-
* @param radius Donut arc Radius.
|
|
562
|
-
* @param percentages Array with donut section percentages.
|
|
563
405
|
* @returns Array of svg path elements
|
|
564
406
|
*/
|
|
565
407
|
const createDonutPaths = (cx, cy, radius, percentages) => {
|
|
@@ -567,7 +409,7 @@ const createDonutPaths = (cx, cy, radius, percentages) => {
|
|
|
567
409
|
let startAngle = 0;
|
|
568
410
|
const totalPercent = percentages.reduce((acc, curr) => acc + curr, 0);
|
|
569
411
|
for (const rawPercent of percentages) {
|
|
570
|
-
const percent = parseFloat(((rawPercent / totalPercent) * 100).toFixed(2));
|
|
412
|
+
const percent = Number.parseFloat(((rawPercent / totalPercent) * 100).toFixed(2));
|
|
571
413
|
const endAngle = 3.6 * percent + startAngle;
|
|
572
414
|
const startPoint = polarToCartesian(cx, cy, radius, endAngle - 90); // rotate donut 90 degrees counter-clockwise.
|
|
573
415
|
const endPoint = polarToCartesian(cx, cy, radius, startAngle - 90); // rotate donut 90 degrees counter-clockwise.
|
|
@@ -583,101 +425,78 @@ const createDonutPaths = (cx, cy, radius, percentages) => {
|
|
|
583
425
|
/**
|
|
584
426
|
* Renders the donut language card layout.
|
|
585
427
|
*
|
|
586
|
-
* @param langs Array of programming languages.
|
|
587
|
-
* @param width Card width.
|
|
588
|
-
* @param totalLanguageSize Total size of all languages.
|
|
589
|
-
* @param statsFormat Stats format.
|
|
590
|
-
* @param hideValues Whether to hide stats values.
|
|
591
428
|
* @returns Donut layout card SVG object.
|
|
592
429
|
*/
|
|
593
430
|
const renderDonutLayout = (langs, width, totalLanguageSize, statsFormat, hideValues) => {
|
|
594
431
|
if (!Number.isFinite(width)) {
|
|
595
|
-
throw new
|
|
432
|
+
throw new TypeError(`Invalid width: "${width}"`);
|
|
596
433
|
}
|
|
597
434
|
const centerX = width / 3;
|
|
598
435
|
const centerY = width / 3;
|
|
599
436
|
const radius = centerX - 60;
|
|
600
437
|
const strokeWidth = 12;
|
|
601
|
-
const colors = langs.map(resolveLangColor);
|
|
602
|
-
const langsPercents = langs.map((lang) => parseFloat(((lang.size / totalLanguageSize) * 100).toFixed(2)));
|
|
438
|
+
const colors = langs.map((lang) => resolveLangColor(lang));
|
|
439
|
+
const langsPercents = langs.map((lang) => Number.parseFloat(((lang.size / totalLanguageSize) * 100).toFixed(2)));
|
|
603
440
|
const langPaths = createDonutPaths(centerX, centerY, radius, langsPercents);
|
|
604
441
|
const donutPaths = langs.length === 1
|
|
605
|
-
?
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
${createDonutLanguagesNode({ langs, totalSize: totalLanguageSize, hideValues, statsFormat })}
|
|
630
|
-
</g>
|
|
631
|
-
|
|
632
|
-
<g transform="translate(125, ${donutCenterTranslation(langs.length)})">
|
|
633
|
-
${donut}
|
|
634
|
-
</g>
|
|
635
|
-
</g>
|
|
636
|
-
`;
|
|
442
|
+
? [
|
|
443
|
+
el('circle', {
|
|
444
|
+
cx: centerX,
|
|
445
|
+
cy: centerY,
|
|
446
|
+
r: radius,
|
|
447
|
+
stroke: colors[0] ?? DEFAULT_LANG_COLOR,
|
|
448
|
+
fill: 'none',
|
|
449
|
+
'stroke-width': strokeWidth,
|
|
450
|
+
'data-testid': 'lang-donut',
|
|
451
|
+
size: 100,
|
|
452
|
+
}),
|
|
453
|
+
]
|
|
454
|
+
: langPaths.map((section, index) => el('g', { class: 'stagger', style: `animation-delay: ${(index + 3) * 100 + 300}ms` }, el('path', {
|
|
455
|
+
'data-testid': 'lang-donut',
|
|
456
|
+
size: section.percent,
|
|
457
|
+
d: section.d,
|
|
458
|
+
stroke: colors[index] ?? DEFAULT_LANG_COLOR,
|
|
459
|
+
fill: 'none',
|
|
460
|
+
'stroke-width': strokeWidth,
|
|
461
|
+
})));
|
|
462
|
+
return [
|
|
463
|
+
createDonutLanguagesNode({ langs, totalSize: totalLanguageSize, hideValues, statsFormat }),
|
|
464
|
+
el('g', { transform: `translate(125, ${donutCenterTranslation(langs.length)})` }, el('svg', { width, height: width }, donutPaths)),
|
|
465
|
+
];
|
|
637
466
|
};
|
|
638
467
|
/**
|
|
639
468
|
* Creates the no languages data SVG node.
|
|
640
469
|
*
|
|
641
|
-
* @param props Object with function properties.
|
|
642
|
-
* @param props.text No languages data translated text.
|
|
643
|
-
* @param props.layout Card layout.
|
|
644
470
|
* @returns No languages data SVG node string.
|
|
645
471
|
*/
|
|
646
|
-
const noLanguagesDataNode = ({ text, layout, }) => {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
};
|
|
472
|
+
const noLanguagesDataNode = ({ text, layout, }) => el('text', {
|
|
473
|
+
x: layout === 'pie' || layout === 'donut-vertical' ? CARD_PADDING : 0,
|
|
474
|
+
y: 11,
|
|
475
|
+
class: 'stat bold',
|
|
476
|
+
}, text);
|
|
651
477
|
/**
|
|
652
478
|
* Get default languages count for provided card layout.
|
|
653
479
|
*
|
|
654
|
-
* @param props Function properties.
|
|
655
|
-
* @param props.layout Input layout string.
|
|
656
|
-
* @param props.hide_progress Input hide_progress parameter value.
|
|
657
480
|
* @returns Default languages count for input layout.
|
|
658
481
|
*/
|
|
659
482
|
const getDefaultLanguagesCountByLayout = ({ layout, hide_progress, }) => {
|
|
660
483
|
if (layout === 'compact' || hide_progress === true) {
|
|
661
484
|
return COMPACT_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
662
485
|
}
|
|
663
|
-
|
|
486
|
+
if (layout === 'donut') {
|
|
664
487
|
return DONUT_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
665
488
|
}
|
|
666
|
-
|
|
489
|
+
if (layout === 'donut-vertical') {
|
|
667
490
|
return DONUT_VERTICAL_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
668
491
|
}
|
|
669
|
-
|
|
492
|
+
if (layout === 'pie') {
|
|
670
493
|
return PIE_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
671
494
|
}
|
|
672
|
-
|
|
673
|
-
return NORMAL_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
674
|
-
}
|
|
495
|
+
return NORMAL_LAYOUT_DEFAULT_LANGS_COUNT;
|
|
675
496
|
};
|
|
676
497
|
/**
|
|
677
498
|
* Renders card that display user's most frequently used programming languages.
|
|
678
499
|
*
|
|
679
|
-
* @param topLangs User's most frequently used programming languages.
|
|
680
|
-
* @param options Card options.
|
|
681
500
|
* @returns Language card SVG object.
|
|
682
501
|
*/
|
|
683
502
|
const renderTopLanguages = (topLangs, options = {}) => {
|
|
@@ -688,7 +507,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
|
|
688
507
|
});
|
|
689
508
|
const { langs, totalLanguageSize } = trimTopLanguages(topLangs, langs_count, hide);
|
|
690
509
|
let width = card_width
|
|
691
|
-
? isNaN(card_width)
|
|
510
|
+
? Number.isNaN(card_width)
|
|
692
511
|
? DEFAULT_CARD_WIDTH
|
|
693
512
|
: card_width < MIN_CARD_WIDTH
|
|
694
513
|
? MIN_CARD_WIDTH
|
|
@@ -718,7 +537,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
|
|
718
537
|
}
|
|
719
538
|
else if (layout === 'donut') {
|
|
720
539
|
height = calculateDonutLayoutHeight(langs.length);
|
|
721
|
-
width
|
|
540
|
+
width += 50; // padding
|
|
722
541
|
finalLayout = renderDonutLayout(langs, width, totalLanguageSize, stats_format, hide_values);
|
|
723
542
|
}
|
|
724
543
|
else {
|
|
@@ -738,52 +557,29 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
|
|
738
557
|
card.setHideBorder(hide_border);
|
|
739
558
|
card.setHideTitle(hide_title);
|
|
740
559
|
card.setCSS({
|
|
741
|
-
light: ({ textColor, progBarBgColor }) =>
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
.bold { font-weight: 700 }
|
|
766
|
-
.lang-name {
|
|
767
|
-
font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
|
|
768
|
-
fill: ${textColor};
|
|
769
|
-
}
|
|
770
|
-
.stagger {
|
|
771
|
-
opacity: 0;
|
|
772
|
-
animation: fadeInAnimation 0.3s ease-in-out forwards;
|
|
773
|
-
}
|
|
774
|
-
#rect-mask rect{
|
|
775
|
-
animation: slideInAnimation 1s ease-in-out forwards;
|
|
776
|
-
}
|
|
777
|
-
.lang-progress{
|
|
778
|
-
animation: growWidthAnimation 0.6s ease-in-out forwards;
|
|
779
|
-
}
|
|
780
|
-
.progress-background { fill: ${progBarBgColor}; }
|
|
781
|
-
`,
|
|
782
|
-
dark: ({ textColor, progBarBgColor }) => `
|
|
783
|
-
.stat { fill: ${textColor}; }
|
|
784
|
-
.lang-name { fill: ${textColor}; }
|
|
785
|
-
.progress-background { fill: ${progBarBgColor}; }
|
|
786
|
-
`,
|
|
560
|
+
light: ({ textColor, progBarBgColor }) => [
|
|
561
|
+
atRule('@keyframes slideInAnimation', rule('from', { width: 0 }),
|
|
562
|
+
// Invalid on purpose — `calc` needs spaces around its `-`. Browsers drop the
|
|
563
|
+
// declaration and animate to the rect's own width, which is the reveal the mask wants.
|
|
564
|
+
rule('to', { width: 'calc(100%-100px)' })),
|
|
565
|
+
atRule('@keyframes growWidthAnimation', rule('from', { width: 0 }), rule('to', { width: '100%' })),
|
|
566
|
+
rule('.stat', {
|
|
567
|
+
font: `600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif`,
|
|
568
|
+
fill: textColor,
|
|
569
|
+
}),
|
|
570
|
+
atRule('@supports(-moz-appearance: auto)', cssComment('Selector detects Firefox'), rule('.stat', { 'font-size': '12px' })),
|
|
571
|
+
rule('.bold', { 'font-weight': 700 }),
|
|
572
|
+
rule('.lang-name', { font: '400 11px "Segoe UI", Ubuntu, Sans-Serif', fill: textColor }),
|
|
573
|
+
rule('.stagger', { opacity: 0, animation: 'fadeInAnimation 0.3s ease-in-out forwards' }),
|
|
574
|
+
rule('#rect-mask rect', { animation: 'slideInAnimation 1s ease-in-out forwards' }),
|
|
575
|
+
rule('.lang-progress', { animation: 'growWidthAnimation 0.6s ease-in-out forwards' }),
|
|
576
|
+
rule('.progress-background', { fill: progBarBgColor }),
|
|
577
|
+
],
|
|
578
|
+
dark: ({ textColor, progBarBgColor }) => [
|
|
579
|
+
rule('.stat', { fill: textColor }),
|
|
580
|
+
rule('.lang-name', { fill: textColor }),
|
|
581
|
+
rule('.progress-background', { fill: progBarBgColor }),
|
|
582
|
+
],
|
|
787
583
|
});
|
|
788
584
|
// `role="img"` hides the inner text from assistive tech, so everything the card
|
|
789
585
|
// shows has to be repeated here.
|
|
@@ -796,10 +592,6 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
|
|
796
592
|
if (layout === 'pie' || layout === 'donut-vertical') {
|
|
797
593
|
return card.render(finalLayout);
|
|
798
594
|
}
|
|
799
|
-
return card.render(
|
|
800
|
-
<svg data-testid="lang-items" x="${CARD_PADDING}">
|
|
801
|
-
${finalLayout}
|
|
802
|
-
</svg>
|
|
803
|
-
`);
|
|
595
|
+
return card.render(el('svg', { 'data-testid': 'lang-items', x: CARD_PADDING }, finalLayout));
|
|
804
596
|
};
|
|
805
597
|
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, };
|